策划|徐莹

作者|王强

近年来,随着大数据分析技术的普及和物联网产业的兴起,越来越多的企业开始关注海量数据的采集、分析和处理,希望从中挖掘出高价值信息以及来自海量数据的洞察力。 在数据规模迅速扩大的同时,企业也对数据处理平台的软硬件基础设施提出了更高的要求,催生了该领域诸多高水平的前沿技术变革。

在这样的趋势下,由俄罗斯Yandex公司开发的名为Clickhouse的数据库产品在众多竞争者中脱颖而出,赢得了全球众多大厂的青睐。 Clickhouse有什么样的独门绝技,如何做到如此强大的性能,在实践中又是如何在主流云平台上进行部署和优化的? 9月22日,京东智联云产品研发部架构师王翔飞做客InfoQ,介绍了Clickhouse数据库在京东智联云的应用和优化经验。 干货满满的技术分享课程。

本文总结了王翔飞老师的在线公开课:《Clickhouse在京东智联云的大规模应用与架构改进》。

1 什么是Clickhouse?

根据数据库处理业务数据量的大小和处理数据方式的不同,人们将数据库分为两种类型:OLTP和OLAP。 俄罗斯Yandex搜索引擎公司开发并开源的Clickhouse数据库,最初定位为Yandex内部的分析型数据库,符合OLAP数据库的实现特点。 Clickhouse的性能超越了很多流行的商业数据库,已经被CloudFlare、Spotify、阿里云、腾讯云、京东智联云、今日头条、携程等多家顶级公司采用。

OLTP 与 OLAP

常见的Oracle、MySQL等数据库都是OLTP类型,即On-Line Transaction Processing,联机事务处理。 OLTP数据库在处理请求和数据时对时延要求很高,必须保证数据的完整性和一致性。 此类数据库面向最终客户,需要 7×24 不间断服务能力。

OLAP的意思是联机分析数据处理。 这种数据库需要存储大量很少更新和修改的数据。 主要用于多维度的历史数据分析统计。 由于这个要求,OLAP数据库需要保证足够高的查询效率,至少90%的请求必须在很短的时间内返回。

另一方面,OLAP数据库不直接面向终端客户,而是更注重数据吞吐量,要求海量数据尽快持久化,为业务决策、战略定位等任务提供分析统计能力和分析,以及个性化的建议。 数据库中的查询通常相对不频繁。

Clickhouse 的主要特点:列式存储

Clickhouse基于OLAP数据库的特点,采用了基于列的数据存储引擎。 传统的基于行的数据库在存储信息时,是在数据库中按顺序一条一条记录的。 以用户注册信息为例,行数据库会依次记录每个用户的姓名、职业、年龄等数据。 当业务需要查找注册用户的职业或年龄分布时,数据库需要打开所有存储用户注册信息的文件,遍历所有数据行,依次选择所有职业和年龄信息进行汇总。 使用这种方式,查询遍历的数据往往远大于需要的数据大小,会造成IO能力的严重浪费。

相比之下,列式存储将数据划分为多个属性列。 例如,将用户注册信息分为职业、年龄等多个属性,并根据这些属性列分为多个文件,分别存储。 这样当查询需要获取某些属性的数据时,只需要找到对应的文件即可完成,大大节省了IO需求。

以一张包含1亿条记录的测试表为例,一个简单的计数查询在MySQL上需要两分多钟,而在列存Clickhouse数据库上不到一秒就可以返回结果。 那么,Clickhouse具体使用了哪些技术来实现如此高的效率提升呢?

2亿级查询,毫秒级返回:Clickhouse背后的秘密

B+Tree 与 MergeTree

在深入研究 Clickhouse 之前,我们先将其与传统的 MySQL InnoDB 存储格式进行比较。

oracle查看数据库_oracle库触发器怎么写_oracle rac连库串的含义

从InnoDB的逻辑结构图中可以看出,InnoDB中的所有数据都会放在表空间中。 表空间可以看作是InnoDB的最高逻辑层,由多个段组成,这些段又分为数据段和索引段。 当数据产生时,数据段按顺序写入。 随着数据记录的增多,InnoDB会把一些主键值放到索引段中,以实现快速定位。

随着数据量的不断增加,数据库形成了一种树状结构,称为B+Tree。 这棵树具有层次结构,会水平生长,其查询的复杂度取决于树的高度。 B+Tree的数据节点一般存放的是主键值。 根据主键查找时,可以通过叶子节点粗略定位到数据页,然后直接读取数据页。

oracle rac连库串的含义_oracle查看数据库_oracle库触发器怎么写

Clickhouse的数据结构类似于关系型数据库,包括一个解析器,主要负责将SQL语句通过词法分析和句法分析,转化为计算机可读的抽象语法树。 此外,还有一个优化器。 逻辑优化负责优化抽象语法树的逻辑,比如简化一些冗长难懂的表达式,做一些语义上的优化。 物理优化负责生成可以直接执行的物理执行计划,指导数据库管理系统如何获取数据表,如何进行数据的join、排序等。

Clickhouse的物理执行计划可以认为是数据流图,是数据的有向无环图。 在此图中,数据从一个管道传递到另一个管道,即从一个运算符传递到另一个运算符。 查询执行器是用于执行计划的引擎。 它将从存储引擎中获取数据并将其返回给客户端。

oracle库触发器怎么写_oracle查看数据库_oracle rac连库串的含义

如上图,Clickhouse在启动时加载配置信息,然后根据不同的解析协议监听不同的服务端口。 客户端发出SQL请求后,首先对SQL进行解析,然后生成抽象语法树,并进行一系列的逻辑优化和物理优化,生成执行计划。 接下来,不同的执行器根据SQL请求将执行计划分发到本地或远程存储引擎,并从存储引擎中获取数据。 数据经过一系列的计算和处理后返回给客户端,客户端可以输出缓冲区来读取查询结果。

MergeTree 存储过程

与InnoDB使用的B+Tree相比,Clickhouse使用MergeTree存储引擎来存储数据。 以下是 Clickhouse 表的示例:

oracle rac连库串的含义_oracle库触发器怎么写_oracle查看数据库

本例中,我们按照出生日期做数据分区,以用户名为主键,设置SETTINGS index_granularity=3。 建表后插入10条记录,分为2001年3月和2001年2月两个数据区间,建表写入数据后,Clickhouse会默认在数据文件存放路径下创建对应的表名:

oracle rac连库串的含义_oracle库触发器怎么写_oracle查看数据库

在这里可以看到,10条数据分别存放在两个文件夹中。 文件夹命名时,第一部分是分区键,即出生日期; 1_1(2_2)表示每个数据分区中最小和最大数据块的编号。 最后一个数字 0 代表合并级别。

oracle库触发器怎么写_oracle rac连库串的含义_oracle查看数据库

上图是MergeTree中Data部分元数据管理的结构。 其中,partition id表示数据所在的分区id; min block和max block表示数据写入的版本信息——用户写入的每一批数据都会生成一个Data部分,同一批次写入的数据会被标记为唯一的块号。 MergeTree存储引擎后台会通过异步任务周期性的合并数据,并且只合并同一个数据分区的数据。 它还要求最小块和最大块数据间隔必须连续且不重叠。

第四级字段对于新插入的数据默认为0,之后随着合并次数的增加,会在原来的基础上增加。 更正数据时使用下面的突变字段。 如果需要数据修正,Clickhouse会默认标记并更新变异字段。

oracle rac连库串的含义_oracle查看数据库_oracle库触发器怎么写

测试数据虽然只有一张表10条,但是会在磁盘目录下生成大量的文件。 具体来说,Clickhouse默认会为每一列生成一个文件,默认的数据文件放在bin文件中。 每个数据分析目录下都会生成一个count文件,记录该分区有多少行数据。

oracle查看数据库_oracle库触发器怎么写_oracle rac连库串的含义

本例中建表时设置的SETTINGS index_granularity设置为3,插入数据后观察主键索引,可以发现primary.idx中会存储主键信息,每3条记录作为一个间隔。

结合前面的例子来看数据全景图。 假设下面绿色的是一批要写入的数据,存储的是用户名; 假设每个名字占4个字节,可以看到绿色上面有一个granule,就是8192,指定granule为8192后,写的时候会把数据放到一个有buffer的OutPort流中,按照一粒一粒; 写入第一个granule后,当发现buffer中的数据大小超过64KB时,这时数据就会被压缩掉到磁盘中,放在下面粉色的文件块中。 当drop一个数据块时,首先会写入一个文件头,文件头由三部分组成,如上图所示。

对于8192数据的第二段,压缩后数据块可能会更长; 可以发现每次写入数据都会生成两个文件。 一种是bin文件,也就是压缩后的数据文件。 另一个文件是主键索引文件。 但是这样在查询数据的时候,不知道数据文件里面是哪条数据,也不知道如何拆分bin文件。 如果将整个bin文件加载到内存中扫描,效率会很差。 为了解决这个尴尬的问题,Clickhouse引入了mrk文件。 在写入数据文件时,会将bin文件的头信息写入mrk文件中。 比如第一块数据写入后,起始位置,解压后位置,解压前位置都会作为一行记录放在mrk文件块中。 查询时直接根据主键索引记录的偏移量在对应的mrk记录中找到某条数据的起始位置,然后读取数据。

MergeTree还有一些异步任务处理,主要有三部分:第一,定时清理一些有问题,提交失败,写入失败的数据文件; 然后定期将一些比较琐碎的插入语句产生的小文件块合并到大文件块中; 偶尔会有修正,比如数据更新和删除产生的临时文件,MergeTree也会将相应的数据文件聚合成一个比较大的Part。

3 京东智联云如何基于K8s部署Clickhouse

智联云选择K8s部署的原因

京东智联云基于现有云平台部署ClickHouse时,是基于K8s团队提供的强大的运维调度平台。 选择基于K8s部署有几个原因:

Clickhouse之智联云部署流程

数据库系统是一个比较复杂的有状态业务系统。 分片和副本之间存在状态关系。 这个时候就需要维护Pod之间的关系。 K8s为此提供了算子函数。 京东智联云二次开发开源的Clickhouse算子,丰富算子的API功能,并为安全生产需要增加一些额外的标签,控制Pod调度的亲和性oracle查看数据库,防止主从复制从落入同一个身体在船上。

oracle库触发器怎么写_oracle查看数据库_oracle rac连库串的含义

这个operator开发部署完成并安装到K8s中后,K8s将具备管理和调度Clickhouse状态的能力。 对外,借助helm系统,将一些事先定义好的表单发送给K8s,K8s会根据表单中定义的参数创建需要的实例。

除了创建最基本的Clickhouse,如果需要复制关系引擎,还会创建Zookeeper; 同时,为了丰富监控能力oracle查看数据库,方便DBA监控服务器运维,还会打造Promethus和可视化Grafana。 这样就可以直接通过VPC中的Grafana监控数据库的运维状态。

这个服务还会创建一个域名绑定headless服务ip地址,用户可以通过这个数据库域名直接连接到这套Clickhouse系统。 从上图右边可以看出,这个Pod的底层存储使用的是京东的云硬盘,在构建Pod的时候会申请一个PVC controller,PVC controller会绑定京东的云硬盘。 这样就形成了计算和存储分离的架构,可以进一步提升计算能力。

京东智联云目前在高性能、高可用和可扩展性方面有自己的特点:

oracle库触发器怎么写_oracle查看数据库_oracle rac连库串的含义

京东智联云还提供了完善的监控系统,可以帮助DBA更好的观察数据库的运行状态。 该平台不仅提供服务级别的数据库监控,还向用户展示所有 Pod 使用的磁盘空间、CPU 和内存。 有了这些信息,用户可以更直观地观察到各个Pod的压力分布,进而方便灵活地调整数据压力,避免某个Pod出现数据瓶颈。

根据这些监控目标,用户可以灵活定义告警信息。 智联云支持多维度数据告警,可以通过邮件、短信、微信等形式进行告警。

4 总结

Clickhouse本身具有强大的数据处理能力,同时也很好的兼容SQL语句。 但在实际设计和使用过程中,不应将其视为传统关系型数据库的增强替代品,这可能会限制Clickhouse的潜力。 企业需要改进传统的数据仓库、设计理念和上下游数据传输方式,发挥想象力和创造力,更好地利用Clickhouse的列式存储、并行计算等数据能力,为数据业务创造更多的数据。 巨大的价值。

京东智联云Clickhouse目前正在进行产品内测,欢迎大家使用。