Ozone如何利用Multi-Raft优化写入吞吐量

发布日期:2021-01-07 10:23
Ozone利用开源项目Ratis实现的Raft机制管理数据和元数据的写入流程。数据写入DataNode上的磁盘前,Leader节点需要利用RaftLog的复制功能将数据同步到Follower节点上。由于Raft协议依赖RaftLog作为其WAL(写前日志),那么在数据节点上写入数据时也受到了RaftLog持久化时延的影响。

从2019年年底开始,腾讯大数据平台内部已经上线了Ozone生产集群承接一部分大数据服务的数据存储业务。随着数据服务体量和数据模型的增加,逐渐发现Ozone写入性能显现出了一定的波动和瓶颈。之后,腾讯的Ozone小组与社区合作设计并开发了Multi-Raft的功能演进优化了Ozone的写入吞吐量和性能。本文将深入介绍Ozone写入性能优化的技术分析和演进过程。

Ozone的数据写入模式

Ozone对于数据的管理主要由Pipeline和Container完成。Ozone的Storage Container Manager (SCM)负责创建数据Pipeline,并且分配Container到不同的Pipeline中,而每个Container负责在不同的数据节点DataNode上分配Block用来存储数据。用户通过客户端写入Ozone,会通过Ozone Manager创建Key,并从SCM拿到数据可以写入的空间,这个空间会由Pipeline和Container分配得来。



Pipeline和Container分配写入数据跟数据的副本数有关,Ozone现在主要支持三副本的方式,数据Pipeline创建时会关联三个数据节点,然后相关的Container会在这三个数据节点上分配Block来完成写入空间分配,三个数据节点会分别记住Pipeline和Container信息,异步发送Report到SCM上报Pipeline和Container的状态。三副本的数据Pipeline是通过Raft协议保证多副本一致性,在Ozone中也叫Ratis Pipeline,相关的三个数据节点会根据Raft协议组成一个Leader和2个Follower的组合,数据写入时会利用RaftLog把数据从leader发到Followers。所以Ozone的数据写入的性能依赖RaftLog的写入吞吐量和传输速度。

关于吞吐量的优化探索

ozone-0.4.0版本中,Pipeline控制数据写入是基于Single-Raft的实现,即每一个数据节点只能参与一个Pipeline。我们针对这个版本的Ozone进行了写入性能的观察和测试,组件了一个10节点的Ozone集群,每台Ozone数据节点都有12块HDD磁盘,网络选取了10 Gps带宽,作为大数据外部存储的集群配置。访问Ozone的方式我们选择了S3协议写入Ozone,对象大小比较离散,由内部sql query的结果组成,大部分是KB级的小对象,其中掺杂了GB级的大对象。

根据图中时延分布,我们可以看到有68%的写入可以在200毫秒内完成,但是依然有超过27%的文件集中于2-3秒内才能完成,同时观察发现时延与文件大小没有非常直接的联系。同时,我们也观察了某个数据节点的磁盘使用率。

在前台持续并发写入的过程中,在全部12块磁盘中,只有5块数据盘有负载,并且集中于其中的3块磁盘。通过日志挖掘和数据统计也观察到,有IO阻塞的现象,数据节点上RaftLog写入磁盘的时候很有可能有排队的现象。于是我们将思路放在了提高数据节点磁盘使用率和缓解Ratis持久化RaftLog排队现象上。

在社区版本的HDFS上也有DataNode IO吞吐量不高的现象,之前有一些落地的方案会改动Linux操作文件系统的方式,增加一些类似Cache的手段帮助增大DataNode通过操作系统写入磁盘的吞吐量。而Ozone这部分优化的思路放在了通过数据Pipeline的节点复用来加大每个节点上Pipeline的使用量,从而通过增加使用者的方式变相增大磁盘使用率。

Multi-Raft的设计思路

如果每一个DataNode,受到了Single-Raft的制约,只能参加一个数据Pipeline的写入,那么上面的磁盘使用率观察可以看到Ratis实现的RaftLog并不能将写入IO均匀的分配到每一个磁盘路径上。
在于Ratis社区讨论后,我们提出了了Multi-Raft的方案,即允许数据节点参与多个数据Pipeline的工作,同时,Multi-Raft也需要通过新的Pipeline分配算法保证数据隔离,考虑数据locality和节点的rack awareness。

在允许数据节点DataNode参加多个数据Pipeline之后,Pipeline的节点分配就出现了很大的变化:

  • SCM能在集群不变大的情况下分配出更多的数据Pipeline。假设配置每个节点最多可以承接M个数据Pipeline的写入,在有N个数据节点的情况下,Single-Raft下SCM最多可以分配N/3个Pipeline,而Multi-Raft下就可以配置M(M*N)/3个Pipeline。
  • 由于三副本备份的原因,数据Pipeline必须有刚好3个数据节点加入才能创建成功,Multi-Raft可以合理利用每一个数据节点的能力参与Pipeline。如图示,在有4个数据节点的时候,Single-Raft的集群只能创建出1个数据Pipeline,而剩下的1个数据节点(4-3*1)只能作为StandBy备用,在开启Multi-Raft功能后,4个节点都可以参加数据Pipeline的分配,大大提高了集群配置的灵活度。
  • 从Single-Raft的磁盘使用率能看到,一个数据Pipeline使用的RaftLog并不能充分将数据写入很好的load balance,在与Ratis社区协作之后,Multi-Raft的方案可以有效利用节点上服务多个数据Pipeline的磁盘,从原来的一个RaftLog使用12个磁盘,变为多个RaftLog使用12个磁盘。对于Ratis的Batch写入和排队机制来说,一次写入可能会Hold某个磁盘一段时间,于是后面排队的写入由于RaftLog个数的限制,会造成一定程度的排队,这也是我们在Single-Raft的集群看到有超过27%的写入需要花费2-3秒,多个RaftLog的存在会很好减少排队的拥挤程度,因为“队伍”变多了。
Multi-Raft 优化后的写性能表现

首先来看看同样的大数据数据集写入Multi-Raft集群和Single-Raft集群的时延分布对比:

对比Single-Raft的集群:

可以看到Multi-Raft优化后的集群,面对同样的数据集写入,接近98%的写入都在200ms内完成,IO排队导致的时延波动已经几乎看不到了。

然后再选取一个数据节点根据节点上Pipeline分配个数观察磁盘使用率:
单数据节点参与12条数据Pipeline时:


单数据节点参与15条数据Pipeline时:


可以很明显地看到当数据节点上的数据Pipeline增多的时候,越来越多的磁盘达到了繁忙的程度,不再出现忙碌和闲置不均匀的情况了。

总结

Ozone的数据节点写入磁盘的部分一定程度上延续了HDFS单节点写入的方式,同时也保留了一部分可待优化的部分。比起单纯在数据节点上做IO栈层面的优化,Multi-Raft的方案利用了数据Pipeline的节点复用和RaftLog的特点加大了数据节点对于并发写入数据的参与度。这样通过元数据和管理成本的修改增大写入带宽的方式对于开源社区是更好的选择,后续可以打开更多的优化点,当前的ozone-0.5.0版本在HDD集群上的写入性能比起0.4版本也有显著的提升。
分享到:
推荐精彩博文