Impala和ClickHouse解决的问题、使用场景本来就不太一样,前者是Sql On Hadoop的分布式查询引擎,而后者是列式的OLAP数据库。
从架构上看,每个Impala节点的imapad守护进程充当了多个角色:查询协调器(Query Coordinator)和执行引擎(Query Exec Engine),而且impala和DataNode部署在同一个服务器上,意味着数据查询是本地化的,这样避免了网络开销;ClickHouse作为一个列式DBMS,所以CK有完善的数据库和表的管理、数据存储和数据查询的功能,作为一个分布式的数据库,也支持数据分片、分布式查询,并可以通过设置副本提高容错。
但是把他们放在一起,最主要是想通过对比,做个深入了解。
Impala
Impala查询大致过程:
应用程序通过JDBC、ODBC接口将SQL查询发送到impala集群,应用程序可以连接到任何一个集群的impalad节点,这个impalad节点被当作该查询的协调器节点
impala解析并分析查询语句,以确定impalad集群中的实例需要执行哪些任务
执行任务的本地impalad节点访问HDFS、Hbase等服务来提供数据
每个impalad将查询后的数据返回给协调者,协调者再把最终汇总的结果返回给客户端
Impala多表查询策略:
Broadcast joins:默认连接方式,impala默认右表小于左表,右表的完整数据的copy会分发到所有查询节点上
partitioned join:适合大表之间的连接,每个表的一部分都会发送到合适的节点上,每个节点并行处理这些数据的子集
Impala根据每个表的大小、行数、每列不同值的数量等统计信息自动优化查询。我们可以通过执行COMPUTE STATS
获取准确的统计信息;但是如果统计信息误差很大,或者impala选择的表join顺序不是最高效的,可以用STRAIGHT_JOIN
关键字重写join顺序,这种情况下,Impala使用表在查询中出现的顺序来指引join执行。
ClickHouse
本文我们主要关注ClickHouse分布式查询过程,首先分布式表本身不存储数据,它只为集群里的多个节点的所有本地表提供一个视图,当从分布式表中进行 SELECT 时,它会重写该查询,根据负载均衡的配置选择远程节点,并将查询发送给它们,如果到了可以合并不同服务器中间结果的阶段,将接收不同服务器的中间结果然后进行merge,分布式表将尽可能的把任务分配给远程服务器,尽量不通会过网络发送太多中间数据,查询过程:
分布式表将查询发送到所有远程服务器,远程服务器在local_table表上执行查询
集群上的多个服务器并行执行查询,直到可以对查询的中间结果进行合并
服务器将中间结果返回给请求服务器(分布式表)并在其上进行合并
分布式表再把合并后的最终结果发送给客户端
如果join或in子查询里包含了分布式表,ClickHourse的查询过程就变得异常复杂,假设我们的ClickHouse集群里,每个节点上都有一个普通的local_table表,同时都有一个分布式的distributed_table表。比如我们跑了一个带有分布式表的子查询:
SELECT uniq(UserID)
FROM distributed_table
WHERE CounterID = 101500
AND UserID IN
(SELECT UserID
FROM distributed_table
WHERE CounterID = 34)
复制
ClickHouse有两种分布式查询方法:
normal JOIN
,查询发送到远程服务上后,每个节点都会执行join语句的子查询,然后用这个表进行连接,而右表又是分布式表,就导致右表一共会被查询N的平分次(N是该分布式表的shard数量),出现了查询放大问题。ClickHouse默认用hash join算法,获取右表的数据并在内存中创建一个hase table,但是如果内存使用达到了一定阈值,clickhouse会退回到merge join算法,对数据进行排序并将结果转存到磁盘上。GLOBAL ... JOIN
, 请求服务器会先执行一个子查询,以生成右表,然后这个临时表(右表)就被发送到每一个远程服务上,每个远程节点上用这个临时表执行查询;也就是说右表只会在接收查询请求的那个节点查询一次,然后将查询后的右边分发到远程节点上