跳转到主要内容
Chinese, Simplified

Citus有多个不同的执行程序,每个执行程序的行为都不同,以支持各种用例。对于许多概念而言,分布式SQL似乎必须是一个复杂的概念,但是其原理并不是火箭科学。在这里,我们将看几个有关Citus如何采用标准SQL并将其转换为以分布式形式运行以便可以并行化的示例。结果是您可以看到单节点数据库的查询性能提高了100倍或更多。

我们如何知道某物是分布式的还是单片?


在了解实时执行器的工作方式之前,值得对Citus执行器进行全面的复习。

当Citus收到查询时,我们首先查看它是否具有where子句的分片键(也称为分发列)。如果您要分拆诸如CRM应用程序之类的多租户应用程序,则可能会有一个org_id,您总是会限制查询。在这种情况下,只要org_id是where子句的一部分,我们就知道它的目标是单个分片,因此可以使用路由器执行程序。如果未使用该查询,我们会将查询拆分并跨节点并行发送给所有分片。

作为快速更新,Citus中的一个表是另一个表。如果您有一个表事件并想要分发它,则可以创建32个分片,这意味着我们可以轻松扩展到32个节点。如果您从2个节点开始,则每个节点包含32个分片。这意味着每个节点将一次接收16个查询,并且如果它有16个可用的内核,那么所有工作将并行完成,从而导致2个节点x 16个内核,或者说,与在单个内核上执行相比,速度提高了32倍。

对于后面的示例,我们将仅创建4个分片以简化它们,但是随着添加的分片和对应的内核的增加,事情几乎线性地扩展。

用SQL编写,用MapReduce思考


Citus对实时分析的支持是自从我们早期以来,人们就一直使用Citus的工作负载,这要归功于我们先进的查询并行化。结果就是您能够用标准SQL表示事物,并让Citus的分布式查询计划器完成重写查询的艰苦工作,从而为您提供出色的性能,而无需创建复杂的工程胶带。

深入研究一些示例,从count(*)开始


我们可以开始处理的最简单的查询是count(*)。对于count(*),我们需要从每个分片中获取一个count(*)。首先,针对事件表运行一个解释计划,以了解其运作方式:

                                              QUERY PLAN
-------------------------------------------------------------------------------------------------------
 Aggregate  (cost=0.00..0.00 rows=0 width=0)
   ->  Custom Scan (Citus Real-Time)  (cost=0.00..0.00 rows=0 width=0)
         Task Count: 4
         Tasks Shown: One of 4
         ->  Task
               Node: host=ec2-18-233-232-9.compute-1.amazonaws.com port=5432 dbname=citus
               ->  Aggregate  (cost=11.62..11.63 rows=1 width=8)
                     ->  Seq Scan on events_102329 events  (cost=0.00..11.30 rows=130 width=0)
(8 rows)

Time: 160.596 ms

查询中有一些注意事项。 首先是它使用的是Citus Real-Time执行程序,这意味着查询正在击中所有碎片。 第二个是任务是4个之一。该任务在所有节点上通常是相同的,但是由于它是纯粹的Postgres计划,可以根据数据分布和估算值进行更改。 如果要查看所有查询计划,则可以扩展输出以获取所有4个分片的任务。 最后,您具有针对该特定分片的查询计划本身。

让我们以集群示例为例:

Citus four shard cluster

如果我们要对该集群执行count(*),Citus将重新编写查询并将四个count(*)查询发送到每个分片。 然后将所得的计数返回给协调器以执行最终聚合:

Citus four shard cluster performing count

性能远远超过count(*)


虽然count(*)很容易看出它是如何工作的,但是您可以执行更多操作。 如果要获得四个平均值并将它们平均在一起,则实际上并不会获得结果平均值。 相反,对于普通的Citus将执行sum(foo)和count(foo),然后在协调器上将sum(foo)/ count(foo)相除,以得出正确的结果。 最好的部分仍然可以编写AVG,Citus负责底层的复杂性。

除了汇总之外,Citus还可以告诉您何时加入并在本地执行这些加入。 让我们向事件表中添加另一个表:会话。 现在,对于每个事件,我们都将会话ID记录为其中的一部分,以便我们加入。 有了这两个表,我们现在想要一个查询,该查询将告诉我们会话的平均事件数,以及上周创建的会话:

SELECT count(events.*), 
       count(distinct session_id)
FROM events,
     sessions
WHERE sessions.created_at >= now() - '1 week'::interval
  AND sessions.id = events.session_id

在这两个表上都分配有会话ID的情况下,Citus会知道这些表在同一位置。 使用共置的表,Citus将重新编写查询以将连接向下推送到本地,从而不会通过网络发送太多数据。 结果是,我们将从每个分片(而不是所有原始数据)中将2条记录发送回协调器,从而大大缩短了分析查询时间。 内部重写的内容可能类似于:

SELECT count(events_01.*), 
       count(distinct session_id)
FROM events_01,
     sessions_01
WHERE sessions_01.created_at >= now() - '1 week'::interval
  AND sessions_01.id = events_01.session_id

SELECT count(events_02.*), 
       count(distinct session_id)
FROM events_02,
     sessions_02
WHERE sessions_02.created_at >= now() - '1 week'::interval
  AND sessions_02.id = events_02.session_id

...

分布式SQL不一定很困难,但是可以肯定很快


下推连接和并行化的好处是:

  • 您不必通过网络发送太多数据,这比在内存中扫描要慢
  • 您可以一次利用系统中的所有内核,而不是在单个内核上运行查询
  • 您可以超出可以在一台计算机中装载多少内存/内核的限制

希望这次对Citus实时执行器的浏览简化了幕后工作的方式。 如果您想更深入地学习,请阅读我们的文档。

 

原文:https://www.citusdata.com/blog/2018/08/17/breaking-down-citus-real-time-executor/

本文:http://jiagoushi.pro/node/927

讨论:请加入知识星球或者微信圈子【首席架构师圈】

 

Article
知识星球
 
微信公众号
 
视频号