实现一个时序数据库的集群方案是一项非常复杂的工作。通常需要实现三个目标:(1)水平扩展能力,当数据量增加时,可以增加节点来满足。(2) 高可用,保证系统7x24不间断运行,并且当网络或节点恢复时,系统具备自愈能力(3)负载均衡,多个副本同时提供服务,解决读数据的热点问题。实现上述目标,不仅前期的开发非常复杂,测试工作更是耗时耗力,通常需要根据大量用户在实际使用中的反馈,覆盖到各种corner cases,让系统逐步变得健壮。没有3~5年很难推出一个相对稳定的时序数据库集群方案。
相比于分布式关系数据库如TiDB和OceanBase,时序数据库集群的实现在数据量和负载均衡上更有挑战性,在事务和一致性方面要求较低,实现相对容易。时序数据库要支持海量的历史数据,数据规模通常是关系数据库的100倍以上,region(或称为chunk,shard)的个数远远高于关系数据库。关系数据库中的多副本(譬如采用raft协议),通常读取时只有一个主副本可用,这对存储海量数据的时序数据库来说,可能是一个浪费。时序数据库通常需要需要多个副本同时提供读服务,也即负载均衡。100倍以上的分区数量以及对多副本负载均衡的要求,增加了时序数据库集群方案的难度。
分布式关系数据库对事务和数据的一致性有很高的要求,在一致性上,通常采用强一致性,代价便是增加了系统的复杂性,牺牲了性能。大部分时序数据库的集群方案选择了简单和性能,牺牲事务和强一致性。但不一致性,增加了实现系统自愈的难度,有时候不得不运维介入,才能手工恢复系统。缺乏事务和一致性,也可能导致一小部分业务的实现变得困难。举几个例子。国内的股票市场行情数据,每3秒发布一个快照,3000个股票的快照写入时可能会落在不同的分区上,一些应用程序在读取最新的数据时,会出现一部分股票是最新数据,另一部分股票是3秒钟前的数据。基于这样的数据做出的决策,可能会有问题。又譬如在工业控制领域,要根据多个传感器的数据做出响应,并反控设备。这些传感器数据的不同步,会造成跟上一个例子中股票投资决策同样的问题。如果时序数据库的集群要实现跟关系数据库类似的基本事务支持,譬如写入数据的原子性(多行的原子性,多个分区的原子性以及多个副本的原子性)以及读数据的隔离性(譬如不能读到一个写入批次的部分数据),复杂性会增加。
国内的一些大厂内部实现了influxdb的集群方案。但这些方案,通常是为某些特定的应用场景设计的,设计上做了很多简化。代价除了场景的限制,往往对运维和运行环境提出了更高的要求。这也可能是这些第三方集群方案没有对外开放的原因之一。再回到influxdb闭源的集群方案。根据官方文档简答的描述(https://docs.influxdata.com/enterprise_influxdb/v1.8/concepts/clustering/),集群的元数据采用强一致性的raft协议,副本方案是基于异步复制。influxdb的集群方案不支持基本的事务。influxdb的多个副本可以同时对外提供读服务,但是没有一致性的保证,也就是说多个连接在同一时间读取同一份数据时,看到的数据可能不一样。异步复制会给数据的一致性带来很多问题,对运维提出了很高的要求。有时候数据不一致,无法自动恢复,可能需要运维的人工介入。
我司推出的分布式时序数据库产品DolphinDB在选择集群的设计方案时做了如下选择:(1)集群的控制节点(元数据解决方案)采用了强一致性的raft协议,节点个数必须是奇数个。(2)时序数据支持多副本,采用强一致性的二阶段提交协议,控制节点的元数据写入也纳入二阶段提交,不仅多个副本之间可以实现一致性,副本数据和元数据也可以实现一致性。(3)支持基本的事务ACID功能,二阶段提交协议实现写入的原子性(包括跨行、跨分区和跨节点)。全局的版本号实现快照级别的读隔离。(4)通过Write Ahead Log (WAL)和Cache Engine提升写入性能。
这个方案的的优点包括:(1)实现了元数据和副本数据的高可用和强一致性,多副本数据可以提供负载均衡,硬件资源的利用效率很高,系统有非常好的自愈能力,运维成本低。(2)以低成本的方式支持千万级分区(Chunk)的数据量。(3)系统有非常高的吞吐量。(4)支持基本的事务,可以满足较为复杂的业务场景需要。这个方案的主要缺点是写入的延迟较高。使用hdd盘保存元数据和WAL,写入延迟在100~200ms之间,使用消费级ssd保存元数据和WAL延迟在5~20ms之间,使用企业级ssd,延迟在1ms左右。因此要提升写入的吞吐量,可以做好三件事情:(1)加大每个批次写入的数据量,如果数据量很大,建议每个批次的写入数据在10万条左右,(2)不同Chunk的数据并行写入,(3)启用高性能的磁盘保存元数据和WAL。由于元数据很小,WAL只要保留较短的时间(30分钟以下),高性能磁盘的容量不需要很大,总体上还是很经济。
我们用4台中等性能的Dell服务器 (每个服务器配置24核48超线程,256G内存,8 X 10000RPM 1.8T HDD, 512G 消费级SSD, 万兆以太网)构建DolphinDB集群。其中3台服务器上各配置一个控制节点,构成3节点的raft组。每台服务器上各配置2个数据节点,每个数据节点配置16个逻辑CPU核和64G内存,共8个数据节点。数据副本个数为2,副本数据写入Cache Engine后再批量压缩写入HDD,元数据和WAL写入SSD。在这样的配置下,每秒钟的写入吞吐量约为1400万条记录/秒 (每条记录约为45个字节)。