17

Ozone原理|Ratis代码解析之一-gRPC

 5 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzU5OTQ1MDEzMA%3D%3D&%3Bmid=2247487527&%3Bidx=2&%3Bsn=b31f878e519a85f20d3115d7ba0cea74
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Ozone采用Ratis保证数据一致性,Ratis采用Raft协议实现,代码可见Github。本文首先介绍Ratis的gRPC模块代码,后续会陆续介绍其他模块。

1. Ratis简介

目前主要有两种分布式协议Paxos、Raft。Raft在保证一致性效果上等价于Paxos,和Paxos同等高效。而 Raft的优势是易理解,易实现。

Ratis采用Raft实现,为了保证Ozone数据一致性,Ozone的每个读写请求,都采用三备份,需要写入一个Leader和两个Follower。一个Leader和两个Follower为一个group,各为一个Ratis Server,只是角色不同,一组Ratis Server分布在三个Datanode里,作为Datanode的子线程。一个leader和两个follower各将一份请求写到log里,请求被一个group的大多数Ratis Server写入log后,即回复给client。

以写数据请求为例,该请求发到Leader后,Leader不仅需要将写数据请求写入log,而且需将被写的数据写入Leader的本地存储。Ratis负责请求写入log,然后Ratis回调Ozone的writeStateMachineData将数据写入Leader本地存储。请求写入Leader的log后,Leader将写请求以及数据发给Follower,数据需要从Leader本地存储读,数据不从请求里获取的原因是需要保证Leader写入了数据。然后Follower开始写log以及数据。可以看出,Leader将数据写入本地存储后,才将请求发给Follower,因为本地存储是磁盘,会造成Leader和Follower串行将数据写入磁盘,速度较慢。优化的方法是,Leader先将数据写入内存Cache,再将数据写入本地存储磁盘。而Leader在将数据写入内存Cache后,就可以将数据读出,并发给Follower,这样Leader和Follower可以并行将数据写入磁盘。

2. Ratis模块简介

Ratis主要模块分为三部分:ratis-client、ratis-grpc、ratis-server。

ratis-client封装给上层使用,提供操作group的接口:groupAdd、groupRemove、getGroupList等,以及发送请求的接口sendRequest等。Ozone使用ratis时,需要首先用groupAdd创建一个Leader和两个Follower的group,然后将请求包装成Ratis的请求RaftClientRequest,通过sendRequest发给Leader。

ratis-server负责数据同步主要逻辑:选举、快照、日志同步等功能,每个leader和follower都是一个RaftServerImpl实例。

ratis-grpc负责ratis-client和ratis-server,以及ratis-server和ratis-server之间的通信。

3. Ratis gRPC简介

Ratis采用gRPC作为网络框架,gRPC相关封装代码在ratis-grpc包下。一个完整的请求分为client和leader、leader和两个follower之间通信。例如Ozone需要ratis将请求写三份时,会用ratis client向ratis leader发送该请求,而ratis leader又会向两个ratis follower发送该请求,当ratis leader和两个ratis follower的大多数写完该请求时,ratis leader会向ratis client回复写成功。client、leader、follower通信时序图如下,后文会做详细介绍。

YjUziey.png!web

4. Client和Leader通信

该部分相关代码在ratis-grpc/src/main/java/org/apache/ratis/grpc/client,该目录下有三个文件负责通信:GrpcClientProtocolClient、GrpcClientProtocolService、GrpcClientRpc。

ratis client相关代码在ratis-client目录下,本文不涉及该部分。client调用GrpcClientRpc::sendRequestAsync向leader发送请求。leader会在GrpcClientProtocolService的RequestStreamObserver::onNext里处理该请求。leader处理请求时,不仅会自己将请求写入log,还会通知两个follower写入log,可见下文。leader处理完后会向client回复,client在GrpcClientProtocolClient的AsyncStreamObservers::onNext里判断写请求三备份是否成功。

5. Leader和Follower通信

该部分相关代码在ratis-grpc/src/main/java/org/apache/ratis/grpc/server,该目录下有三个文件负责通信:GrpcClientProtocolService、GrpcLogAppender、GrpcServerProtocolClient。

leader在GrpcClientProtocolService的RequestStreamObserver::onNext里收到请求后,会交给RaftServerImpl::submitClientRequestAsync处理,该函数首先校验当前server是否是leader等,然后leader将请求放入待写队列,并通知leader向follower发请求的线程GrpcLogAppender。GrpcLogAppender负责将请求从leader发送到follower,leader为每个follower维护一个GrpcLogAppender线程。

GrpcLogAppender调用GrpcServerProtocolClient:: appendEntries将Leader已经写成功的请求发给follower,follower在GrpcServerProtocolService的ServerRequestStreamObserver::onNext里接收请求,并交给RaftServerImpl:: appendEntriesAsync处理,appendEntriesAsync需要首先校验Leader的请求,包括该请求的源Server是否是Leader,以及该请求是否已经在Follower写入等,然后将请求写入日志,处理完后回复给leader,leader在GrpcLogAppender的AppendLogResponseHandler::onNext检查follower是否写成功。如果leader和两个follower大多数写成功,leader向client回复成功,client在上文提到的GrpcClientProtocolClient的AsyncStreamObservers::onNext处理回复。

欢迎阅读其他Ozone系列文章

浅谈配置化的Ozone网络拓扑结构

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

如何用hadoop的用法来玩转ozone

浅谈Ozone的HA能力

Ozone on K8S

聊一聊Ozone如何高效利用Raft机制

Hadoop原生对象存储Ozone

欢迎关注我们公众号

VbaYVzn.jpg!web

j e r r y s h a o @ t e n c e n t . c o m


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK