岱岳区建设信息网站,网站开发自学时间,中企动力济南分公司,移动互联网站开发工程师背景
阿里云InfluxDB是阿里云基于开源版InfluxDB打造的一款时序数据库产品#xff0c;提供更稳定的持续运行状态、更丰富强大的时序数据计算能力。在现有的单节点版本之外#xff0c;阿里云InfluxDB团队还将推出多节点的高可用版本。
我们知道现有的开源版InfluxDB只提供单…背景
阿里云InfluxDB®是阿里云基于开源版InfluxDB打造的一款时序数据库产品提供更稳定的持续运行状态、更丰富强大的时序数据计算能力。在现有的单节点版本之外阿里云InfluxDB®团队还将推出多节点的高可用版本。
我们知道现有的开源版InfluxDB只提供单节点的能力早期开源的集群版本功能不完善、且社区不再提供更新与支持。经过对官网商业版InfluxDB现有文档的研究我们猜测在商业版InfluxDB集群方案中meta信息集群是基于一致性协议Raft做同步的而数据是异步复制的。这种分离的方式虽然有优点但也引起了一系列的一致性问题在一些公开的文档中官方也承认这种数据复制方案并不令人满意。
因此团队在参考多项技术选型后决定采用最为广泛使用并有较长历史积累的ETCD/Raft作为核心组件实现阿里云InfluxDB®的Raft内核对用户所有的写入或一致性读请求直接进行Raft同步不做meta信息同步与数据写入在一致性过程中的拆分保证多节点高可用版本拥有满足强一致性要求的能力。
有幸笔者参与到多节点的高可用版本的开发中期间遇到非常多的挑战与困难。其中一项挑战是ETCD的Raft框架移植过程中在移除了ETCD自身较为复杂、对时序数据库没有太多作用的Raft日志模块后所带来的一系列问题。本文就业界Raft日志的几种不同实现方案做讨论并提出一种自研的Raft HybridStorage方案。
业内方案 ETCD
由于我们采用了ETCD/Raft的方案绕不开讨论一下ETCD本家的Raft日志实现方式。
官网对Raft的基本处理流程总结参考下图所示协议细节本文不做扩展 对于ETCD的Raft日志主要包含两个主要部分文件部分WAL、内存存储部分MemoryStorage。
文件部分WAL是ETCD Raft过程所用的日志文件。Raft过程中收到的日志条目都会记录在WAL日志文件中。该文件只会追加不会重写和覆盖。
内存存储部分MemoryStorage主要用于存储Raft过程用到的日志条目一段较新的日志可能包含一部分已共识的日志和一些尚未共识的日志条目。由于是内存维护可以灵活的重写替换。MemoryStorage有两种方式清理释放内存第一种是compact操作对appliedId之前的日志进行清理释放内存第二种是周期snapshot操作该操作会创建snapshot那一时刻的ETCD全局数据状态并持久化同时清理内存中的日志。
在最新的ETCD 3.3代码仓库中ETCD已经将Raft日志文件部分WAL和Raft日志内存存储部分MemoryStorage都抽象提升到了与Raft节点Node、Raft节点id以及Raft集群其他节点信息*membership.RaftCluster平级的Server层级这与老版本的ETCD代码架构有较大区别在老版本中Raft WAL与MemoryStorage都仅仅只是Raft节点Node的成员变量。 一般情况下一条Raft日志的文件部分与内存存储部分配合产生作用写入时先写进WAL保证持久化随之马上追加到MemoryStorage中保证热数据的高效读取。
无论是文件部分还是内存存储部分其存储的主要数据结构一致都是raftpb.Entry。一条log Entry主要包含以下几个信息
参数描述Termleader的任期号Index当前日志索引Type日志类型Data日志内容
此外ETCD Raft日志的文件部分WAL还会存储针对ETCD设计的一些额外信息比如日志类型、checksum等等。
CockroachDB
CockroachDB是一款开源的分布式数据库具有NoSQL对海量数据的存储管理能力又保持了传统数据库支持的ACID和SQL等还支持跨地域、去中 心、高并发、多副本强一致和高可用等特性。
CockroachDB的一致性机制也是基于Raft协议单个Range的多个副本通过Raft协议进行数据同步。Raft协议将所有的请求以Raft Log的形式串行化并由Leader同步给Follower当绝大多数副本写Raft Log成功后该Raft Log会标记为Committed状态并Apply到状态机。
我们来分析一下CockroachDB Raft机制的关键代码可以很明显的观察到也是从鼻祖ETCD的Raft框架移植而来。但是CockroachDB删除了ETCD Raft日志的文件存储部分将Raft日志全部写入RocksDB同时自研一套热数据缓存raftentry.Cache利用raftentry.Cache与RocksDB自身的读写能力包括RocksDB的读缓存来保证对日志的读写性能。 此外Raft流程中的创建snapshot操作也是直接保存到RocksDB。这样实现的原因个人推测是可能由于CockroachDB底层数据存储使用的就是RocksDB直接使用RocksDB的能力读写WAL或者存取snapshot相对简单不需要再额外开发适用于CockroachDB特性的Raft日志模块了。 自研HybridStorage 移除snapshot
在阿里云InfluxDB多节点高可用方案实现过程中我们采用了ETCD/Raft作为核心组件根据移植过程中的探索与InfluxDB实际需要移除了原生的snapshot过程。同时放弃原生的日志文件部分WAL而改用自研方案。
为什么移除snapshot呢原来在Raft的流程中为了防止Raft日志的无限增加会每隔一段时间做snapshot早于snapshot index的Raft日志请求将直接用snapshot回应。然而我们的单Raft环架构如果要做snapshot就是对整个InfluxDB做将非常消耗资源和影响性能而且过程中要锁死整个InfluxDB这都是不能让人接受的。所以我们暂时不启用snapshot功能而是存储固定数量的、较多的Raft日志文件备用。
自研的Raft日志文件模块会周期清理最早的日志防止磁盘开销过大当某个节点下线的时间并不过长时其他正常节点上存储的日志文件如果充足则足够满足它追取落后的数据。但如果真的发生单节点宕机太长正常节点的日志文件已出现被清理而不足故障节点追取数据时我们将利用InfluxDB的backup和restore工具将落后节点还原至被Raft日志涵盖的较新的状态然后再做追取。
在我们的场景下ETCD自身的WAL模块并不适用于InfluxDB。ETCD的WAL是纯追加模式的当故障恢复时正常节点要相应落后节点的日志请求时就有必要分析并提取出相同index且不同term中那条最新的日志同时InfluxDB的一条entry可能包含超过20M的时序数据这对于非kv模式的时序数据库而言是非常大的磁盘开销。
HybridStorage设计
我们自研的Raft日志模块命名为HybridStorage即意为内存与文件混合存取内存保留最新热数据文件保证全部日志落盘内存、文件追加操作高度一致。
HybridStorage的设计思路是这样的 1保留MemoryStorage为了保持热数据的读取效率内存中的MemoryStorage会保留作为热数据cache提升性能但是周期清理其中最早的数据防止内存消耗过大。 2重新设计WALWAL不再是像ETCD那样的纯追加模式、也不需要引入类似RocksDB这样重的读写引擎。新增的日志在MemoryStorage与WAL都会保存WAL文件中最新内容始终与MemoryStorage保持完全一致。
一般情况下HybridStorage新增不同index的日志条目时需要在写内存日志时同时操作文件执行类似的增减。正常写入流程如下图所示 当出现了同index不同term的日志条目的情况此时执行truncate操作截断对应文件位置之后一直到文件尾部的全部日志然后重新用append方式写入最新term编号的日志操作逻辑上十分清晰不存在Update文件中间的某个位置的操作。
例如在一组Raft日志执行append操作时出现了如下图所示的同index37、38、39不同term的日志条目的情况。在MemoryStorage的处理方式是找到对应index位置的内存位置内存位置37并抛弃从位置A以后的全部旧日志占用的内存数据因为在Raft机制中这种情况下内存位置37以后的那些旧日志都是无效的无需保留然后拼接上本次append操作的全部新日志。在自研WAL也需要执行类似的操作找到WAL文件中对应index的位置文件位置37删除从文件位置37之后的所有文件内容并写入最新的日志。如下图分析 方案对比
ETCD的方案Raft日志有2个部分文件与内存文件部分因为只有追加模式因此并不是每一条日志都是有效的当出现同index不同term的日志条目时只有最新的term之后的日志是生效的。配合snapshot机制非常适合ETCD这样的kv存储系统。但对于InfluxDB高可用版本而言snapshot将非常消耗资源和影响性能而且过程中要锁死整个InfluxDB。同时一次Raft流程的一条entry可能包含超过20M的时序数据。所以这种方案不适合。
CockroachDB的方案看似偷懒使用了RocksDB的能力但因其底层存储引擎也是RocksDB所以无何厚非。但对于我们这样需要Raft一致性协议的时序数据库而言引入RocksDB未免过重了。
自研的Raft HybridStorage是比较符合阿里云InfluxDB®的场景的本身模块设计轻便简介内存保留了热数据缓存文件使用接近ETCD append only的方式遇到同index不同term的日志条目时执行truncate操作删除冗余与无效数据降低了磁盘压力。
总结
本文对比了业内常见的两种Raft日志的实现方案也展示了阿里云InfluxDB®团队自研的HybridStorage方案。在后续开发过程中团队内还会对自研Raft HybridStorage进行多项优化例如异步写、日志文件索引、读取逻辑优化等等。也欢迎读者提出自己的解决方案。相信阿里云InfluxDB®团队在技术积累与沉淀方面会越做越好成为时序数据库技术领导者。
原文链接 本文为云栖社区原创内容未经允许不得转载。