查看原文
其他

Dledger 技术在消息领域的探索和应用

刘振东 阿里巴巴中间件 2021-08-09

Photo by Daniel Bowman on Unsplash


一直以来,在多地多中心的消息发送场景下,如何保障数据的完整性和一致性是一个技术难点。本文将和您一起探讨 Dledger 技术,并分享 RocketMQ 的实践。

 


多副本技术的演进



1.1 Master/Slave

多副本最早的是Master/Slave架构,即简单地用Slave去同步Master的数据,RocketMQ最早也是这种实现。分为同步模式(Sync Mode)和异步模式(Async Mode),区别就是Master是否等数据同步到Slave之后再返回Client。这两种方式目前在RocketMQ社区广泛使用的版本中都有支持,原理图如下图1所示。

             

             图1 Master-Slave

 

1.2 基于Zookeeper服务

随着 Google 三篇核心技术论文的发表(MapReduce、GFS和BigTable),分布式领域开启了快速发展。在 Hadoop 生态中,诞生了一个基于 Paxos 算法选举 Leader 的分布式协调服务 ZooKeeper。[z1] 由于 ZooKeeper 本身拥有高可用和高可靠的特性,随之诞生了很多基于 ZooKeepe r的高可用高可靠的系统。具体做法如下图2所示:


 图2 Based on Zookeeper/Etcd


如图所示,假如系统里有3个节点,通过ZooKeeper提供的一些接口,可以从3个节点中自动的选出一个Master来。选出一个Master后,另外两个没成功的就自然变成Slave。选完之后,后续过程与传统实现方式中的复制一样。故基于ZooKeeper的系统与基于Master/Slave系统最大的区别就是:选Master的过程由手动选举变成依赖一个第三方的服务(比如ZooKeeper或Etcd)的选举。


基于ZooKeeper的服务还存在一个变种,具体做法如下图3:

图3 Based on ZooKeeper/Etcd


在第一种方式中,发起者(Client)和接收者(Server)都是在同一个进程中的。而在这种方式中Client是脱离于Server之外的,通过Zookeeper,从这三个Client中选出一个Master来,选完Master后把请求同时发送到3个Server里,这样也可以达到多副本的效果。


但是基于ZooKeeper的服务也带来一个比较严重的问题:依赖加重。因为运维ZooKeeper是一件很复杂的事情。


1.3 基于 Raft 服务方式

因为 ZooKeeper 的复杂性,又有了以下 Raft 的方式。Raft 可以认为是 Paxos 的简化版。基于Raft 的方式如下图4所示,与上述两种方式最大的区别是:leader 的选举是由自己完成的。比如一个系统有3个节点,这3个节点的 leader 是利用Raft的算法通过协调选举自己去完成的,选举完成之后,Master 到 Slave 同步的过程仍然与传统方式类似。最大的好处就是去除了依赖,即本身变得很简单,可以自己完成自己的协调。


图4 Raft

 

  • Raft Leader Election 机制

Raft 最大的好处就是可以实现自身 leader 选举。如果一个分布系统要自我协调,通常是采用“投票”的方式,在“投票”的时候,为了解决冲突问题,就采用了两个机制:Term和Quorum。


  • Term,即给每一次投票编号,以1、2、3这样的数字命名。

  • Quorum,即少数服从多数原则,每一次投票必须要得到多数派(N/2 + 1)的同意才认为是成功。


根据这两个机制,在一个 Term 中,一个节点只能投出一票,保证在一个 Term 中只有一个节点能选举成功。如果在一个 Term 中,没有节点获得大多数节点(N/2+1)的选票,选举失败,会重新发起选举。选举失败后,给每个节点设置合适的随机等待时间,会容易更快选举完成。选举成功之后就是跟之前比较相似的复制过程。


  • 三种实现高可靠和高可用的方法优劣对比

Master/Slave,Based on ZooKeeper/Etcd 和 Raft,这三种是目前分布式系统中,做到高可靠和高可用的基本的实现方法,各有优劣。


  • Master/Slave

优点:实现简单

缺点:不能自动控制节点切换,一旦出了问题,需要人为介入。

  • Based on Zookeeper/Etcd

优点:可以自动切换节点

缺点:运维成本很高,因为 ZooKeeper 本身就很难运维。

  • Raft

优点:可以自己协调,并且去除依赖。

缺点:实现 Raft,在编码上比较困难。



什么是 DLedger



2.1 Dledger 的定位

前文介绍了目前分布式系统中,做到高可靠和高可用的三种基本的实现方法。Raft 算法现在解析的比较多,也比较成熟,代码实现难度也有所降低。Dledger 作为一个轻量级的 Java Library,它的作用就是将 Raft 有关于算法方面的内容全部抽象掉,开发人员只需要关心业务即可。


图5 Dledger  Proposition


如上图所示,Dledger 只做一件事情,就是 CommitLog。Etcd 虽然也实现了Raft协议,但它是自己封装的一个服务,对外提供的接口全是跟它自己的业务相关的。在这种对Raft的抽象中,可以简单理解为有一个 StateMachine 和 CommitLog。CommitLog 是具体的写入日志、操作记录,StateMachine 是根据这些操作记录构建出来的系统的状态。在这样抽象之后,Etcd 对外提供的是自己的 StateMachine 的一些服务。Dledger 的定位就是把上一层的 StateMachine 给去除,只留下 CommitLog。这样的话,系统就只需要实现一件事:就是把操作日志变得高可用和高可靠。


这样做对消息系统还有非常特别的含义。消息系统里面如果还采用 StateMachine + CommitLog的方式,会出现 double IO 的问题,因为消息本省可以理解为是一个操作记录。所以Dledger 会提供一些对原生 CommitLog 访问的API。通过这些 API 可以直接去访问 CommitLog。这样的话,只需要写入一次就可以拿到写入的内容。Dledger 对外提供的是简单的API,如下图6所示。可以把它理解为一个可以无限写入操作记录的文件,可以不停 append,每一个append 的记录会加上一个编号。所以直接去访问Dledger 的话就是两个 API:一个是 append,另一个是 get,即根据编号拿到相应的 entry(一条记录)。


 图6  Dledger  API

 

2.2 Dledger的架构

Dledger 的架构如下图7所示:

图7 Dledger  Architecture


从前面介绍的多副本技术的历史可以知道,我们要做的主要有两件事:选举和复制,对应到上面的架构图中,也就是两个核心类:DLedgerLeaderElector 和 DLedgerStore,选举和文件存储。选出 leader 后,再由 leader 去接收数据的写入,同时同步到其他的 follower,这样就完成了整个 Raft 的写入过程。

 

2.3  Dledger 的代码

因为Dledger 只有CommitLog,没有StateMachine,所以代码很精简,只有4000多行,总体代码测试覆盖率大概是70%。通过如下几行命令便可以快速地体验:


 图8 Dledge Quick Start


Dledger 源代码地址:

https://github.com/openmessaging/openmessaging-storage-dledger



RocketMQ on DLedger



3.1 Dledger 在 RocketMQ 上的应用


图9 RocketMQ on Dledger Architecture


Dledger 虽然只需要写 CommitLog,但是基于 CommitLog 是可以做很多事情的。RocketMQ原来的架构里是有 CommitLog 的,现在用 Dledger 去替代原来的 CommitLog。由于Dledger 提供了一些可以直接读取 CommitLog 的API,于是就可以很方便地根据 CommitLog 去构建ConsumerQueue 或者其他的模块。这就是 Dledger 在 RocketMQ 上最直接的应用。

 

3.2 Dledger 与 RocketMQ 对接时格式上的区别:

加了 Dledger 之后,其实就是在原来的消息上面加了一个头。这个头就是 Dledger 的头,本质上是一些简单的属性,例如size等。如下图10所示。


图10 RocketMQ on Dledger  Format


在使用的时候会有格式上的差异,所以社区在升级的时候做了一个平滑升级的考虑,如图11所示。要解决的问题是:如何将原来已有的 CommitLog 和现在基于 Dledger 的 CommitLog混合?现在已经支持自动混合,但是唯一的一个要求是旧版的 CommitLog 需要自己去保持它的一致性。因为 Dledger 的复制是从新写入的记录开始。假设旧的 CommitLog 已经是一致的情况下,然后直接启动 Dledger ,是可以在旧的 CommitLog基础上继续append,同时保证新写消息的一致性,高可靠和高可用。这是 Dledger 直接应用到 RocketMQ 上的时候一个格式上的区别。


图11 RocketMQ on Dledger  Smooth Upgrade


对于用户来说,这样做最直接的好处是:若使用 Master/Slave 架构模式,一旦一个broker挂了,则需要手动控制。但是使用 Dledger 之后不需要这么做。因为 Dledger 可以通过自己选举,然后把选举结果直接传给 RocketMQ 的 broker,这样通过 nameserver 拿到路由的时候就可以自动找到 leader 节点去访问消息,达到自动切换的目的。如下图12所示。


图12 RocketMQ on Dledger  Failover

 

3.3 Dledger 在多中心场景下的使用

上面只是最基本的应用,更直接的应用如图13所示:(容灾切换)


图13 RocketMQ on Dledger  Multi Center


这里举一个真实的金融应用场景:杭州、深圳和上海分别代表系统中三个节点,进行消息传输。要求:数据一条都不能丢,满足实时高可用并且考虑城市之间的容灾。


Raft 的论文中没有提及如何优先选择某个节点作为 leader,但是我们实现的时候可以自己优化。假设杭州节点服务更好,我们可以指定优先选择杭州节点为 leader。如果杭州节点宕机,可以再把 leader 节点切换到上海,如果上海节点也挂掉,虽然集群不可用了,但是大部分数据还在深圳节点有灾备。深圳主要起复制和灾备的作用,一般情况下不会被选为 leader。


3.4 Dledger 的使用方式

社区4.4.0刚刚发表,RocketMQ on DLedger 计划在4.5.0发布,目前可以在分支上获取代码:https://github.com/apache/rocketmq/blob/store_with_dledger/docs/cn/dledger/


下载代码之后,可以通过运行社区提供的简单脚本fast-try.sh来体验一下。


 图14  RocketMQon Dledger Quick Start

 


RocketMQ 社区发展



4.1 功能点展望

前面主要讲了两个东西:RocketMQ 和 DLedger。DLedger 主要是作为 OpenMessaging 的一个社区在孵化,OpenMessaging 针对消息的存储也抽象出了一套API,DLedger 是其一个标准的实现。


目前,Github 上的 DLedger 只是实现了 Raft 一些基础功能。后续有很多可以扩展的功能点,比如:

  • Leader节点优先选择

  • 手动配置leader

  • 自动降级到master/slave架构

 

4.2 openmessaging-hakv

再看一下跟 DLedger 定位相似的 Java Library:openmessaging-hakv。openmessaging-hakv结构图如图15所示。

图15 openmessaging-hakv


代码详见:

https://github.com/openmessaging/openmessaging-hakv


目前来看,我们没有一个嵌入式且高可用的解决方案。RocksDB 可以直接用,但是它本身不支持高可用。有了 DLedger 之后,我们可以把操作的记录直接写入 DLedger,但是基于这些记录恢复过程我们可以自己选择。假如数据量少,对高可用要求高,比如元数据,我们可以直接存在内存的 hashmap 中,根据 DLedger 的写入记录来构建自己的 hashmap,从而达到数据的一致性和容灾功能。


本文作者:刘振东,GitHub ID dongeforever,阿里巴巴技术专家,2016年中间件性能挑战赛亚军,具有丰富的分布式系统设计经验,目前负责 RocketMQ 新航道的探索和创新。



/ 推荐另一篇值得细品的「深度文章」 /



/ 推荐一个值得参与的「开发者活动」 /




©每周一推

第一时间获得下期分享


☟☟☟


Tips:

# 点下“好看”❤️

# 然后,公众号对话框内发送“雨伞”,试试手气?😆

# 本期奖品由采购不设限的「淘宝企业服务」赞助 🌂

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存