我有一个分布式/联合数据库,其结构如下:
- 数据库分布在三个地理位置(“节点”)
- 多个数据库集群在每个节点上
- 关系数据库是 PostgreSQL、MySQL、Oracle 和 MS SQL Server 的混合;非关系数据库是 MongoDB 或 Cassandra
- 每个节点内和跨节点联合的松散耦合是通过 RabbitMQ 实现的,每个节点运行一个 RabbitMQ 代理
我正在为跨节点联合的作业(即非节点本地的作业)实现一个只读的节点间聚合作业系统。这些作业只执行“获取”查询——它们不修改数据库。(如果作业的结果打算进入一个或多个数据库,那么这是由一个单独的作业完成的,该作业不是我试图优化的节点间作业系统的一部分。)我的目标是最小化这些作业所需的网络带宽(首先最小化节点间/WAN 带宽,然后最小化节点内/LAN 带宽);我假设每个 WAN 链接的成本是统一的,每个 LAN 链接的成本是统一的。这些工作对时间不是特别敏感。我在一个节点内而不是在节点之间执行一些 CPU 负载平衡。
相对于集群或特定数据库本地的数据库写入量,聚合作业通过 WAN/LAN 传输的数据量很小,因此跨联合完全分布数据库是不切实际的。
我用于最小化网络带宽的基本算法是:
- 给定一个作业,该作业运行在整个联邦中的一组数据上,管理器节点向每个其他节点发送一条消息,其中包含相关的数据库查询。
- 每个节点运行它的一组查询,用 gzip 压缩它们,缓存它们,并将它们的压缩大小发送到管理器节点。
- 管理器移动到包含多个数据的节点(具体来说,移动到集群内具有最多数据并且具有空闲核心的机器);它从其他两个节点和集群中的其他机器请求其余数据,然后运行该作业。
在可能的情况下,作业使用分而治之的方法来最大限度地减少所需的数据共置量。例如,如果作业需要计算联盟中所有销售数据的总和,则每个节点在本地计算其销售总和,然后在管理节点聚合(而不是将所有未处理的销售数据复制到管理节点) . 但是,有时(例如在位于不同节点的两个表之间执行连接时)需要数据共置。
我做优化的第一件事是聚合作业,并在十分钟的时期运行聚合作业(机器都在运行 NTP,所以我可以合理地确定“每十分钟”在每个节点上意味着相同的事情)。目标是让两个作业能够共享相同的数据,从而降低传输数据的总体成本。
- 给定两个查询同一个表的作业,我生成每个作业的结果集,然后取两个结果集的交集。
- 如果两个作业都安排在同一个节点上运行,则网络传输成本计算为两个结果集的总和减去两个结果集的交集。
- 这两个结果集存储到 PostgreSQL 临时表(在关系数据的情况下)或临时 Cassandra columnfamilies / MongoDB 集合(在 nosql 数据的情况下)在选择运行作业的节点上;然后针对组合的结果集执行原始查询,并将数据传递给各个作业。(此步骤仅在组合结果集上执行;单个结果集数据只是简单地交付到其工作中,而无需首先存储在临时表/列族/集合中。)
这会改善网络带宽,但我想知道是否有框架/库/算法可以改善这一点。我考虑的一个选项是在节点缓存结果集,并在确定网络带宽时考虑这些缓存的结果集(即,除了当前的预调度协同定位作业集之外,尝试跨作业重用结果集,例如在一个 10 分钟的时期运行的作业可以使用前 10 分钟结果集中的缓存结果集),但除非作业使用完全相同的结果集(即,除非它们使用相同的 where 子句),否则我不知道一般情况 -将填补结果集中空白的目的算法(例如,如果结果集使用子句“where N > 3”并且不同的作业需要带有子句“where N > 0”的结果集 那么我可以使用什么算法来确定我需要将原始结果集与带有子句“其中 N > 0 AND N <= 3”的结果集结合起来 - 我可以尝试编写自己的算法来执行此操作,但结果将是一个错误无用的混乱。我还需要确定缓存数据何时过时 - 最简单的方法是将缓存数据的时间戳与源表上的最后修改时间戳进行比较,如果时间戳已更改,则替换所有数据,但理想情况下我希望能够仅更新已随每行或每块时间戳更改的值。) - 我可以尝试编写自己的算法来做到这一点,但结果将是一个错误的无用混乱。我还需要确定缓存数据何时过时 - 最简单的方法是将缓存数据的时间戳与源表上的最后修改时间戳进行比较,如果时间戳已更改,则替换所有数据,但理想情况下我希望能够仅更新已随每行或每块时间戳更改的值。) - 我可以尝试编写自己的算法来做到这一点,但结果将是一个错误的无用混乱。我还需要确定缓存数据何时过时 - 最简单的方法是将缓存数据的时间戳与源表上的最后修改时间戳进行比较,如果时间戳已更改,则替换所有数据,但理想情况下我希望能够仅更新已随每行或每块时间戳更改的值。