一、概述
中移某业务拨测系统基于业务数据拨测指标及日志的分析需要,随着Clickhouse在OLAP领域的快速崛起,以及一些特性考虑,比如:
数据量会很大,最好需要分布式;
支持实时写入,支持快速计算,在较短时间内能完成计算;
强大的sql能力,实时指标sql化;
人力有限,运维需要简单;
高效的压缩比存储,服务器有限,可以用更少的服务器存储更多的数据;
我们也考虑在环境中引入ClickHouse组件,替代ES协助flink加强日志数据分析,本业务场景里主要用于存储拨测详单数据,预估1天1000w条数据,存储前已累计3-4亿条数据;尤其CK单表的处理优势,有利于项目中大表的分析,特别适合大数据量的即时查询,从而充当秒级别的实时OLAP查询引擎的角色,且Clickhouse社区活跃度高、版本迭代非常快,有更好的生态趋势,ClickHouse已成为目前流程的一款OLAP引擎,它不能也不会用于任何 OLTP 事务性操作的场景;
ClickHouse是由俄罗斯IT公司Yandex为Yandex.Metrica开发的一个列式数据库管理系统,全称是 Click Stream、Data WareHouse,简称 ClickHouse,它使用 C++ 语言编写,专门用于 OLAP(联机分析处理,又称为多维分析处理),它遵循 Apache License 2.0 协议,所以可以被免费使用。ClickHouse允许使用实时更新的SQL查询生成数据分析报告。该系统以高性能著称。官方称,ClickHouse的性能超过了同类其他列式数据库,单主机每秒可理数十亿行和几十千兆字节的数据。ClickHouse是CPU的,因为它的矢量化查询执行涉及相关的处理器指令和运行时代码生成。它充分利用所有可用的硬件,以最快的速度处理每个查询。单个查询的峰值处理性能超过每秒2 TB。该项目于2016年6月在Apache2许可下作为开源软件发布。它可作为开源SQL数据仓库。除了 Yandex 自己以外,ClickHouse 还被众多商业公司或研究组织应用到了其生产环境。欧洲核子研究中心(CERN,想起了石头门)将它用于保存强对撞机试验后所记录的数十亿事件的测量数据,并成功将先前的数据查询时间从几个小时缩短到几秒;著名的 CDN 服务厂商 CloudFlare 将 ClickHouse 用于 HTTP 的流量分析;国内的头条、阿里巴巴、腾讯和新浪等一众互联网公司都在应用 ClickHouse,ClickHouse 已作为微信 OLAP 的主要核心引擎。ClickHouse 非常适用于商业智能领域,也就是我们所说的 BI 领域,但有些场景更需要针对性对内核优化。它包括以下功能:
处理具有数万亿行和数千列的表的列存储。
基于shard+replica实现的线性扩展和高可靠,由于内置了复制功能,因此具有容错能力和读取扩展能力。可在数百个节点集群上运行,很容易地安装在单个服务器或虚拟机上。
采用列式存储,数据类型一致,压缩性能更高,通过物化视图进行出色的聚合。
解决实际问题的功能,如漏斗分析和最后一点查询。
硬件利用率高,连续IO,提高了磁盘驱动器的效率;
向量化引擎与SIMD提高了CPU利用率,多核多节点并行化大查询;
官方网站:https://clickhouse.com/
GitHub:https://github.com/ClickHouse/ClickHouse,版本说明;
安装文档:https://clickhouse.com/docs/en/development/architecture
文档参考:https://clickhouse.com/blog
二、架构说明
我们依据数据的流向将Clickhouse的应用架构划分为4个层级。ClickHouse 是一个真正的列式数据库管理系统(DBMS),列式存储(Columnar or column-based)是相对于传统关系型数据库的行式存储(Row-basedstorage)来说的。在 ClickHouse 中,数据始终是按列存储的,包括矢量(向量或列块)执行的过程。只要有可能,操作都是基于矢量进行分派的,而不是单个的值,这被称为矢量化查询执行,它有利于降低实际的数据处理开销。
上图中数据存储层,采用双副本机制来保证数据的高可靠,同时用nginx代理clickhouse集群,通过域名的方式进行读写操作,实现了数据均衡及高可靠写入,且对于域名的响应时间及流量还可进行对应的实时监控,一旦响应速度出现波动或异常我们能在第一时间收到报警通知。
nginx_one_replication:代理集群一半节点即一个完整副本,常用于写操作,在每次提交数据时由nginx均衡路由到对应的shard表,当某一个节点出现异常导致写入失败时,nginx会暂时剔除异常节点并报警,然后另选一台节点重新写入。
nginx_two_replication:代理集群所有节点,一般用作查询和无副本表数据写入,同时也会有对于异常节点的剔除和报警机制。
对比HDFS、Spark、HBase 和 Elasticsearch 这类分布式系统,都采用了 master-slave 主从架构,由一个管控节点作为 Leader 统筹全局,而 ClickHouse 则采用 multi-master 多主架构,集群中的每个节点角色对等,客户端访问任意一个节点都能得到相同的效果。这种多主架构有很多优势,例如对等的角色使系统架构变得更加简单,不用再区分主控节点、数据节点和计算节点,集群中的所有节点功能相同。所以它天然规避了单点故障的问题,非常适合用于多数据中心、异地多活的场景。
2)优势
- 查询速度快,可高效的使用CPU,利用多核并行处理单个查询数据,不仅仅按列存储,同时还按向量进行处理;
- 数据压缩空间大,减少IO,也就减少数据扫描范围和数据传输时的大小;处理单查询高吞吐量每台服务器每秒最多数十亿行;
- 索引非B树结构,不需要满足最左原则;只要过滤条件在索引列中包含即可;即使在使用的数据不在索引中,由于各种并行处理机制ClickHouse全表扫描的速度也很快;
- 写入速度非常快,50-200M/s,对于大量的数据更新非常适用。
- 内置数较多(例如IP转化,URL分析等,预估计算/HyperLoglog等);
- 作为一个 DBMS,它具备如下功能:
DDL(数据定义语言):可以动态地创建、修改或者删除数据库、表和视图,而无需重启服务
DML(数据操作语言):可以动态地查询、插入、修改或删除数据
权限控制:可以按照用户粒度设置数据库或者表的操作权限,保障数据的安全性
数据备份与恢复:提供了数据备份导出与导入恢复机制,满足生产环境的要求
分布式管理:提供集群模式,能够自动管理多个数据库节点
3)劣势
- 不支持事务,不支持真正的删除/更新,不支持UPDATE/DELETE操作,不擅长按行删除数据(虽然支持),不擅长根据主键按行粒度进行查询(虽然支持)
- 不支持高并发,官方建议qps为100,可以通过修改配置文件增加连接数,但是在服务器足够好的情况下;
- SQL满足日常使用80%以上的语法,join写法比较特殊;最新版已支持类似SQL的join,但性能不好;
- 尽量做1000条以上批量的写入,避免逐行insert或小批量的insert,update,delete操作,因为ClickHouse底层会不断的做异步的数据合并,会影响查询性能,这个在做实时数据写入的时候要尽量避开;
- Clickhouse快是因为采用了并行处理机制,即使一个查询,也会用服务器一半的CPU去执行,所以ClickHouse不能支持高并发的使用场景,默认单查询使用CPU核数为服务器核数的一半,安装时会自动识别服务器核数,可以通过配置文件修改该参数。
- 聚合结果必须小于一台机器的内存大小,否则失败
4)性能数据参考
- 单个查询吞吐量:如果数据被放置在page cache中,则一个不太复杂的查询在单个服务器上大约能够以2-10GB/s(未压缩)的速度进行处理(对于简单的查询,速度可以达到30GB/s)。如果数据没有在page cache中的话,那么速度将取决于你的磁盘系统和数据的压缩率。例如,如果一个磁盘允许以400MB/s的速度读取数据,并且数据压缩率是3,则数据的处理速度为1.2GB/s。这意味着,如果你是在提取一个10字节的列,那么它的处理速度大约是1-2亿行每秒。对于分布式处理,处理速度几乎是线性扩展的,但这受限于聚合或排序的结果不是那么大的情况下。
- 处理短查询的延时时间:数据被page cache缓存的情况下,它的延迟应该小于50毫秒(最佳情况下应该小于10毫秒)。 否则,延迟取决于数据的查找次数。延迟可以通过以下公式计算得知: 查找时间(10 ms) * 查询的列的数量 * 查询的数据块的数量。
- 处理大量短查询:ClickHouse可以在单个服务器上每秒处理数百个查询(在最佳的情况下最多可以处理数千个)。但是由于这不适用于分析型场景。建议每秒最多查询100次。
- 数据写入性能:建议每次写入不少于1000行的批量写入,或每秒不超过一个写入请求。当使用tab-separated格式将一份数据写入到MergeTree表中时,写入速度大约为50到200MB/s。如果您写入的数据每行为1Kb,那么写入的速度为50,000到200,000行每秒。如果您的行更小,那么写入速度将更高。为了提高写入性能,您可以使用多个INSERT进行并行写入,这将带来线性的性能提升。
- 其他参考:
count: 千万级别,500毫秒,1亿 800毫秒 2亿 900毫秒 3亿 1.1秒
group: 百万级别 200毫米,千万 1秒,1亿 10秒,2亿 20秒,3亿 30秒
join:千万-10万 600 毫秒, 千万 -百万:10秒,千万-千万 150秒
5)配置文件结构
clickhouse大部分参数都是支持热修改的,它的配置文件结构如下:
- users.xml默认的users.xml可分为三个部分:用户设置users:主要配置用户信息如账号、密码、访问ip等及对应的权限映射;配额设置quotas:用于追踪和限制用户一段时间内的资源使用;参数权限profiles:读写权限、内存、线程等大多数参数配置;为了统一管理权限我们在users.xml预定义了对应权限及资源的quotas及profiles,例如default_profile、readwrite_profile、readonly_profile等,新增用户无需单独配置quotas及profiles,直接关联预定义好的配置即可
\- users.d/xxx.xml按不同的用户属性设置user配置,每一个xml对应**一组用户,**每个用户关联users.xml中的不同权限quotas及profiles
\- users_copy/xxx.xml每次有变更用户操作时备份指定属性的xml,方便回滚
\- metrika.xml默认情况下包含集群的配置、zookeeper的配置、macros的配置,当有集群节点变动时通常需要将修改后的配置文件同步整个集群,而macros是每个服务器独有的配置,如果不拆解很容易造成配置覆盖,引起macros混乱丢失数据,所以我们在metrika.xml中只保留每台服务器通用的配置信息,而将独立的配置拆解出去
\- conf.d/xxx.xml保存每台服务器独立的配置,如macros.xml
config_copy/xxx.xml存放每次修改主配置时的备份文件,方便回滚
- ck-man工具
ckman(ClickHouse Manager)是由擎创科技自主研发的一款管理ClickHouse的工具,前端用Vue框架,后端使用Go语言编写。它主要用来管理ClickHouse集群、节点以及数据监控等,致力于服务ClickHouse分布式的操作以及管理。同时提供简单的数据查询窗口。
通过网页端的可视化界面,ckman可以非常便捷的完成集群的导入、部署、节点的增删以及性能指标的监控等功能,可以大大简化集群部署的操作流程,从而起到事半功倍的效果。
2.2、其他应用参考
1)快手应用实践案例
上图中:通过一个路由进行分流到CH多集群处理,Ps还做一些类似“切面”“网关”做的工作。数据则是通过 mapreduce(无论是 hive、sparksql 还是其他) 和 flink 进入clickhouse。Clickhouse在单表的情况下性能比多表join好很多,快手给出一些实践经验,更多参见:文章1;另外,如果是普通企业,上图结构就满足了,但快手由于业务量大,提出了Clickhouse on Hdfs 的方案,即存储和计算分离,存储使用hadoop hdfs。自己基于接口重写了 HdfsMergeTree实现。
2)案例2:
3)案例3:
4)案例4:
5)案例5:
6)案例6:微信ClickHouse OLAP 的生态
目前,微信当前规模千台,数据量 PB 级,每天的查询量上百万,单集群 TPS 达到了亿级,而查询耗时均值仅需秒级返回。主要生态组件:
1.QueryServer:数据网关,负责智能缓存,大查询拦截,限流;
2.Sinker:离线/在线高性能接入层,负责削峰、hash 路由,流量优先级,写入控频;
3.OP-Manager:负责集群管理、数据均衡,容灾切换、数据迁移;
4.Monitor:负责监控报警,亚健康检测,查询健康度分析,可与 Manager 联动;
三、部署配置
四、使用
五、FAQ
六、附录:
6.1、优化参考
- 关闭虚拟内存,物理内存和虚拟内存的数据交换,会导致查询变慢。
- 为每一个账户添加join_use_nulls配置,左表中的一条记录在右表中不存在,右表的相应字段会返回该字段相应数据类型的默认值,而不是标准SQL中的Null值。
- JOIN操作时一定要把数据量小的表放在右边,ClickHouse中无论是Left Join 、Right Join还是Inner Join永远都是拿着右表中的每一条记录到左表中查找该记录是否存在,所以右表必须是小表。
- 批量写入数据时,必须控制每个批次的数据中涉及到的分区的数量,在写入之前最好对需要导入的数据进行排序。无序的数据或者涉及的分区太多,会导致ClickHouse无法及时对新导入的数据进行合并,从而影响查询性能。
- 尽量减少JOIN时的左右表的数据量,必要时可以提前对某张表进行聚合操作,减少数据条数。有些时候,先GROUP BY再JOIN比先JOIN再GROUP BY查询时间更短。
ClickHouse的分布式表性能性价比不如物理表高,建表分区字段值不宜过多,防止数据导入过程磁盘可能会被打满。- CPU一般在50%左右会出现查询波动,达到70%会出现大范围的查询超时,CPU是最关键的指标,要非常关注。
6.2、MySQL VS ClickHouse
MySQL单条SQL是单线程的,只能跑满一个core,ClickHouse相反,有多少CPU,吃多少资源,所以飞快;
ClickHouse不支持事务,不存在隔离级别。ClickHouse的定位是分析性数据库,而不是严格的关系型数据库。
IO方面,MySQL是行存储,ClickHouse是列存储,后者在count()这类操作天然有优势,同时,在IO方面,MySQL需要大量随机IO,ClickHouse基本是顺序IO。
6.3、Doris VS ClickHouse
Doris支持Array,ch支持Array/嵌套类型/枚举类型等。
Doris支持事务和幂等性导入数据,ch不支持。
Doris的join性能比较好,ch的单表查询性能好。
Doris更优的方面1. 使用更简单,如建表更简单,SQL标准支持更好, Join性能更好,导数功能更强大2. 运维更简单,如灵活的扩缩容能力,故障节点自动恢复,社区提供的支持更好3. 分布式更强,支持事务和幂等性导入数据,物化视图自动聚合,查询自动路由,全面元数据管理
ClickHouse更优的方面1. 性能更佳,导入性能和单表查询性能更好,同时可靠性更好2. 功能丰富,非常多的表引擎,更多类型和函数支持,更好的聚合函数以及庞大的优化参数选项3. 集群管理工具更多,更好多租户和配额管理,灵活的集群管理,方便的集群间迁移工具;
那么两者之间如何选择呢?1. 业务场景复杂数据规模巨大,希望投入研发力量做定制开发,选ClickHouse2. 希望一站式的分析解决方案,少量投入研发资源,选择Doris;
更多参看:https://zhuanlan.zhihu.com/p/421469439
6.4、列式存储VS行式存储
行存储是将整行放入连续的物理位置,就像传统的记录存储或文件存储方式,列存储是按列将连续的某几列数据放入连续的物理存储单元中;列式存储是指一列中的数据在存储介质中是连续存储的;行式存储是指一行中的数据在存储介质中是连续存储的。简单理解,列式数据库认为是每一列都是一个表,这个表只有一列,如果只在该列进行条件查询,速度就很快。新兴的 Hbase、HP Vertica、EMC Greenplum 、Hbase,Hive,Clickhouse,Sybase 等分布式数据库均采用列式存储。在基于列式存储的数据库中, 数据是按照列为基础的逻辑存储单元进行存储的,一列中的数据在存储介质中以连续存储形式存在。
传统的行式数据库将一个个完整的数据行存储在数据页中。这种方式在大数据量查询的时候会出现以下问题:
1、在没有索引的情况下,会把一行行全部查出来,会使用大量IO
2、虽然建立索引和物化视图可以可以快速定位列,但是也需要花费大量时间
列式数据模型可以看作是一个每行列数可变的数据表,如下:
在行式数据库中查询时,无论需要哪一列都需要将每一行扫描完。如果给某些特定列建索引,虽然可以显著提高查找速度,但是索引会带来新的开销,而且数据库仍在扫描所有列。而列式数据库可以分别存储每个列,从而在列数较少的情况下更快速地进行扫描。比如:
上图的布局看起来和行式数据库很相似,每一列都有一个索引,索引将行号映射到数据,列式数据库将数据映射到行号,采用这种方式计数变得更快,很容易就可以查询到某个项目的爱好人数, 并且每个表都只有一种数据类型,所以单独存储列也利于优化压缩。列式数据库能够在其他列不受影响的情况下,轻松添加一列,但是如果要添加一条记录时就需要访问所有表,所以行式数据库要比列式数据库更适合联机事务处理过程(OLTP:Online Transaction Processing),因为 OLTP 要频繁地进行记录的添加或修改。列式数据库是将同一个数据列的各个值存放在一起。插入某个数据行时,该行的各个数据列的值也会存放到不同的地方。每次读取某个数据行时,需要分别从不同的地方读取各个数据列的值,然后合并在一起形成数据行。因此,如果每次查询涉及的数据量较小或者大部分查询都需要整行的数据,列式数据库并不适用。列式数据库还支持列组(column group,Bigtable系统中称为locality group),即将多个经常一起访问的数据列的各个值存放在一起。如果读取的数据列属于相同的列组,列式数据库可以从相同的地方一次性读取多个数据列的值,避免了多个数据列的合并。列组是一种行列混合存储模式,这种模式能够同时满足OLTP和OLAP的查询需求。
示例2:
假设一张数据表 A,里面有 50 个字段 A1 ~ A50,如果我们需要查询前 5 个字段的数据的话,那么可以使用如下 SQL 实现:SELECT A1, A2, A3, A4, A5 from A;
但是这样问题来了,数据库每次都会逐行扫描、并获取每行数据的全部字段,这里就是 50 个,然后再从中返回前 5 个字段。因此不难发现,尽管只需要前 5 个字段,但由于数据是按行进行组织的,实际上还是扫描了所有的字段。但如果数据是按列进行存储,则不会出现这样的问题,由于数据按列进行组织,数据库可以直接选择 A1 ~ A5 这 5 列的数据并返回,从而避免多余的数据扫描。
示例3:
如上图所示,假设我们要计算 age 这一列的平均值,就需要一行一行扫描,所以最终会至少扫描 11 个值( 3 + 3 + 3 + 2 )才能找到 age 这一列所存储的 4 个值。这意味着我们要花费更多的时间等待 IO 完成,而且读完之后还要扔掉很多(因为我们只需要部分字段)。但如果是按列存储的话,我们只需要获取 age 这一列的连续快,即可得到我们想要的 4 个值,所以这种操作速度更快、效率更高。
基于列模式的存储,天然就会具备:自动索引、利于数据压缩;每一列本身就相当于索引。对应压缩,会发下大部分列数据基数其实是重复的,列数据类型一致,这样利于数据结构填充的优化和压缩;数据按列进行组织,属于同一列的数据会被保存在一起,并进行压缩,而列与列之间的数据也会由不同的文件分别保存。数据默认使用 LZ4 算法压缩,在 Yandex 公司的 Metrica 生产环境中,数据整体的压缩比可以达到 8 比 1(未压缩前 17 PB,压缩后 8 PB)。
列式存储: 每一列单独存放,数据即是索引。只访问涉及得列,如果我们想访问单独一列就会相当快。 一行数据包含一个列或者多个列,每个列用单独一个cell来存储数据。列式场景比较关注的都是某几列的内容,或者有频繁聚集需要的,通过聚集之后进行数据分析的表。如果大部分时间都是关注整张表的内容,而不是单独某几列,并且所关注的内容是不需要通过任何聚集运算的,那么推荐使用行式存储。
6.5、Infobright VSTiDB、Doris、Clickhouse、spark
相关经验表明,Clickhouse的查询性能略高于Doris,而TiDB在千万量级以上性能下降明显,而对于大数据量级下Clickhouse相比Infobright性能提升巨大,因此可选择Clikhouse作为BI的存储查询引,替代Infobright;在 10 亿条测试数据的体量下,Spark 被 ClickHouse 打的落花流水。ClickHouse 具有 ROLAP(关系型)、在线实时查询、完整的 DBMS、列式存储、不需要任何数据预处理、支持批量更新、拥有非常完善的 SQL 支持和函数、支持高可用、不依赖 Hadoop 复杂生态、开箱即用等许多特点。特别是它那夸张的查询性能;有组织做了测试,使用了相同配置的服务器,在单个节点的情况下,对一张拥有 133 个字段的数据表分别在 1000 万、1 亿和 10 亿三种数据体量下执行基准测试,基准测试的范围涵盖 43 项SQL查询。在 1 亿数据级体量的情况下,ClickHouse 的平均响应速度是 Vertica 的2.63倍、InfiniDB 的 17 倍、MonetDB 的 27 倍、Hive 的 126 倍、MySQL 的 429 倍以及 Greenplum 的 10 倍。
采用单分片多副本的方式来构建Clickhouse集群时,对于数据量可控的情况下,因clickhouse有着高效的数据压缩比,采用单节点看是否能存储当前某一层级的全量数据,且能满足未来几年的数据存储需求。Clickhouse默认并发数为100,采用单分片每个节点都拥有全量数据,当qps过高时可横向增加节点来增大并发数。clickhouse对Distributed 表的join支持较差,单分片不走网络,能提高join查询速度。单分片多副本架构参考:
下图为实时数仓_Clickhouse应用架构图:
数据输入层面将用户的行为数据实时关联维表写入kafka,然后由Flink + JDBC写入Clickhouse,为了保证实时查询的稳定性我们采用了双副本结构,用nginx代理其中一个完整的副本,直接对域名写入;同时在程序中增加失败重试机制,当有节点不可写入时,会尝试向其他分片写入,保证了每条数据都能被写入clickhouse。在数据的输出层面将同样由nginx代理整个集群,对接到客户端工具及与SCF服务,其中客户端工具对接到开发人员及分析师,scf对外提供查询服务。
相关经验:
数据写入:一个batch内不要写多个分区的数据;根据服务器配置适当增大background_pool_size,提高merge线程的数量 默认值16。对于system.merges、system.processes表做好监控,可随时感知写入压力情况作出预警,避免服务崩溃
索引不宜建立过多,对于大数据量高并发的写入可以考虑先做数据编排按建表索引排序再写入,减少merge压力
禁止对Distributed表写入,可通过代理方式如nginx或chproxy直接对local表写入,而且能基于配置实现均衡写入及动态上下线节点
JOIN操作:无论什么join小表必须放在右边,可以用left、right调整join方式;
开启enable_optimize_predicate_expression=1(部分版本默认关闭);大量降低数据量的操作如where、group by、distinct操作优先在join之前做(需根据降低比例评估)常用参数:
max_execution_time 单次查询的最大时间:600s
max_memory_usage 单服务器单次查询使用的最大内存,设置总体内存的50%
max_bytes_before_external_group_by 启动外部存储 max_memory_usage/2
max_memory_usage_for_all_queries 单服务器所有查询使用的最大内存,设置总体内存的80%-90%,防止因clickhouse服务占用过大资源导致服务器假死
6.6、相关概念
1)向量化执行:可以简单地看做成一种消除程序中的循环所做的优化,举个栗子。假设小明在卖果汁,而榨一杯果汁假设需要 2 分钟,有客户抱怨太慢了,那么为了增加速度要怎么办呢?显然多准备几台榨汁机就好了,因此非向量化执行的方式是利用 1 台榨汁机重复 n 次,而向量化执行的方式是利用 n 台榨汁机只执行 1 次。而为了实现向量化执行,需要利用 CPU 的 SIMD 指令。SIMD 的全称是:Single Instruction Multiple Data,即用单条指令操作多条数据。现代计算机系统概念中,它是通过数据并行以提高性能的一种实现方式(其它的还有指令级并行和线程级并行),它的原理是在 CPU 寄存器层面实现数据的并行计算。CPU 从寄存器中获取数据的速度是最快的,是内存的 300 倍,磁盘的 3000 万倍。利用 CPU 向量化执行的特性,对于程序的性能提升有着非凡的意义。ClickHouse 目前使用 SSE 4.2 指令集实现向量化执行。
相比 HBase 和 Redis 这类 NoSQL 数据库,ClickHouse 使用关系模型描述数据并提供了传统数据库的概念(数据库、表、视图和函数等)。ClickHouse 完全使用 SQL 作为查询语言(支持 GROUP BY、ORDER BY、JOIN、IN 等大多数标准 SQL),这使得它容易理解和学习。 ClickHouse 提供了标准协议的 SQL 查询接口,使得现有的第三方分析可视化系统可以轻松地与它集成对接。而在 SQL 解析方面,ClickHouse 是大小写敏感的,这点需要注意;
关系模型相比文档模型、键值对模型等等,拥有更好的描述能力,也能更加清楚地表示实体之间的关系。更重要的是,在 OLAP 领域,已有的大量数据建模工作都是基于关系模型展开的(星座模型、雪花模型和宽表模型)。ClickHouse 使用了关系模型,所以将构建在传统关系型数据库或者数仓之上的系统迁移到 ClickHouse 的成本会变得更低,可以直接沿用之前的经验成果。
向量化执行是通过数据级别的并行方式提升了性能,那么多线程处理就是通过线程级并行的方式实现了性能提升。相比基于底层硬件实现的向量化执行 SIMD,线程级并行通常由更高层次的软件层面控制。由于 SIMD 不适合用于带有较多分支判断的场景,ClickHouse 也大量使用了多线程技术以实现提速,以此和向量化执行形成互补。SIMD 被广泛地应用于文本转换、数据过滤、数据解压和 JSON 转换等场景。 ClickHouse 在数据存储方面,既支持分区(纵向扩展,利用多线程资源),也支持分片(横向扩展,利用分布式原理)。
Vertica、SparkSQL、Hive 和 Elasticsearch 等,都可以支撑海量数据的查询场景,都拥有分布式架构,都支持列存储、数据分片、计算下推等功能。但相关经验表明,Vertica 这类商用软件价格高昂;SparkSQL 与 Hive 这类系统无法保障 90% 的查询都能在 1 秒内返回,在大数据量下的复杂查询可能会需要分钟级的响应时间;而 Elasticsearch 这类搜索引擎在处理亿级数据聚合查询时则已经显得捉襟见肘。
数据分片是将数据进行横向切分,ClickHouse 支持分片,而分片则依赖集群,每个集群可以有一到多个分片,但是注意:一个服务节点只能有一个分片,所以分片的数量取决于节点数量。ClickHouse 提供了本地表(Local Table)和分布式表(Distributed Table)的概念。一张本地表等同于一份数据的分片,而分布式表本身不存储任何数据,它是本地表的访问代理,其作用类似分库中间件。借助分布式表,能够代理访问多个数据分片,从而实现分布式查询。在业务上线的初期,数据体量并不高,此时数据表并不需要多个分片。所以使用单个节点的本地表(单个数据分片)即可满足业务需求,待到业务增长、数据量增大的时候,再通过新增数据分片的方式分流数据,并通过分布式表实现分布式查询。 ClickHouse 的设计则采用了自底向上的方式,它的目的很单纯,就是希望能以最快的速度进行 GROUP BY 查询和过滤;ClickHouse 会在内存中进行 GROUP BY,并且使用 HashTable 装载数据。
6.7、Apache Doris VS ClickHouse
Apache Doris是由百度贡献的开源MPP分析型数据库产品,亚秒级查询响应时间,支持实时数据分析;分布式架构简洁,易于运维,可以支持10PB以上的超大数据集;可以满足多种数据分析需求,例如固定历史报表,实时数据分析,交互式数据分析和探索式数据分析等。而ClickHouse最大的特色是高性能的向量化执行引擎;京东当前都在大范围使用这两种分析引擎,京东相关经验:
Doris更优的方面:1. 使用更简单,如建表更简单,SQL标准支持更好, Join性能更好,导数功能更强大;2. 运维更简单,如灵活的扩缩容能力,故障节点自动恢复,社区提供的支持更好;3. 分布式更强,支持事务和幂等性导数,物化视图自动聚合,查询自动路由,全面元数据管理
ClickHouse更优的方面:1. 性能更佳,导入性能和单表查询性能更好,同时可靠性更好;2. 功能丰富,非常多的表引擎,更多类型和函数支持,更好的聚合函数以及庞大的优化参数选项;3. 集群管理工具更多,更好多租户和配额管理,灵活的集群管理,方便的集群间迁移工具
那么两者之间如何选择呢?1. 业务场景复杂数据规模巨大,希望投入研发力量做定制开发,选ClickHouse;2. 希望一站式的分析解决方案,少量投入研发资源,选择Doris,Doris的问题是性能差一些可靠性差一些。Doris源自在线广告系统,偏交易系统数据分析;ClickHouse起源于网站流量分析服务,偏互联网数据分析,但是这两类场景这两个引擎都可以覆盖。
1)架构方面:Doris一般只需要FE和BE两个组件。ClickHouse本身只有一个模块,就是ClickHouse Server,周边有两个模块,如ClickHouseProxy主要是转发请求、配额限制和容灾等,ZooKeeper这块负责分布式DDL和副本间数据同步,ClickHouseCopier负责集群和数据迁移,ClickHouse一般需要Server、ZooKeeper和CHProxy三个组件。Doris增加节点,只需Add Backend即可,ClickHouse中需要更改配置文件并下发到各个节点上。ClickHouse的权限和Quota的粒度更细,可以很方便的支持多租户使用共享集群。比如可以设置查询内存、查询线程数量、查询超时等,以便来限制查询的大小;同时结合查询并发和一定时间窗口内的查询数量,以便来控制查询数量。多租户的方案,对发展中的业务非常友好,因为使用共享集群资源,可以快速动态调整配额;ClickHouse的扩容缩容复杂且繁琐,目前做不到自动在线操作,需要自研工具支持。扩容时需要部署新的节点,添加新分片和副本到配置文件中,并在新节点上创建元数据,如果是扩副本数据会自动均衡,如果是扩分片,需要手工去做均衡,或自研相关工具,让均衡自动进行。
2)分布式及高可用:ClickHouse目前版本是基于ZooKeeper来存储元数据,包含分布式的DDL、表和数据Part信息,从元数据丰富程度来说稍弱,因为存储了大量细粒度的文件信息,导致ZooKeeper经常出现性能瓶颈,社区也有基于Raft协议的改进计划。ClickHouse依赖Zookeeper来实现数据的高可用,Zookeeper带来额外的运维复杂性的同时也有性能问题。ClickHouse没有集中的元数据管理,每个节点分别管理,高可用一般依赖业务方来实现。ClickHouse中某个副本节点宕机,对查询和分布式表的导入没有影响,本地表导入要在导数程序中做灾备方案比如选择健康的副本,对DDL操作是有影响的,需要及时处理。
3)事务支持:即ACID指事务的原子性、一致性、隔离性和持久化;Doris提供了导入的事务支持,可以保证导数的幂等性,比如数据导入的原子性,如果有其他错误会自动回滚,同时相同标签的数据不会重复导入。有事务支持的Doris比无事务支持的ClickHouse要节省很多开发成本,ClickHouse不支持事务,需要在外部去做各种校验和检查,在导数这块能保证100万以内的原子性,但是不保证一致性,比如要更新某些字段或者更新物化视图,这个操作是后台异步的,需要显示指定关键字FINAL来查询最终数据,而且其他操作没有事务支持。DDL操作两者都是异步的,但是Doris能保证各个节点元数据的一致性,但ClickHouse中保证不了,会出现局部节点元数据和其他节点不一致的情况。
4)存储结构:两者都是列存,列存的好处就是1. 分析场景中需要读大量行但是少数几个列,只需要读取参与计算的列即可,极大的减低了IO,加速了查询2. 同一列中的数据属于同一类型,压缩效果显著,节省存储空间,降低了存储成本3. 高压缩比,意味着同等大小的内存能够存放更多数据,系统Cache效果更好;Doris的数据划分方式是Table、Partition、Bucket/Tablet、Segment几个部分,其中Partition代表数据的纵向划分分区一般是日期列,Bucket/Tablet一般指数据的横向切割分桶规则一般为某主键, Segment是具体的存储文件。Segment中包含数据和索引,数据部分包含多个列的数据按列存放,有三种索引:物理索引、稀疏索引和ZoneMap索引。ClickHouse中分为DistributeTable、LocalTable、Partition、Shard、Part、Column几个部分,差不多能和Doris对应起来,区别就是CH中每个Column都对应一组数据文件和索引文件,好处就是命中系统Cache性能更高,不好的地方就是IO较高且文件数量较多,另外CH有Count索引,所以Count时命中索引会比较快。通过分区分桶的方式可以让用户自定义数据在集群中的数据分布方式,降低数据查询的扫描量,方便集群的管理。分区作为数据管理的手段, Doris支持按照range分区,ClickHouse可以表达式来自定义。Doris可以通过动态分区的配置来按照时间自动创建新的分区,也可以做冷热数据的分级存储。ClickHouse通过distrubute引擎来进行多节点的数据分布,但是因为缺少bucket这一层,会导致集群的迁移扩容比较麻烦, Doris通过分桶的配置可以进一步对数据划分,方便数据的均衡和迁移。更多参看Apache Doris和ClickHouse的深度分析;
6.8、CH vs Mysql
ClickHouse支持Mysql大多数语法,迁移成本低,目前有五种迁移方案:
create table engin mysql,映射方案数据还是在Mysql
insert into select from,先建表,在导入
create table as select from,建表同时导入
csv离线导入
streamsets
示例1:
CREATE TABLE [IF NOT EXISTS] [db.]table_name ENGINE = Mergetree AS SELECT * FROM mysql('host:port', 'db', 'database', 'user', 'password')