SOFAJRaft 源码分析一(启动流程和节点变化)

1.概述

前段时间接触了raft协议,唯一的感受就是易于理解。对于raft,在分布式领域还是有一片天地的。当然,光看算法不去工程化就是耍流氓,所以我专门拉了一下sofa团队的jraft代码。然后对其实现进行分析,一方面是为了提高自己的编码功底,一方面也是更加深入的理解。今天我们就先看看其架构实现。然后会对其进行逐一拆分,深入底层代码。
sofastack是一个不错平台,大家也可以持续关注。

2.架构设计


纵观设计架构图,还是非常容易理解的。

整个系统围绕着Node进行。涵盖了日志管理、元数据存储、快照、状态机、日志复制等模块。Node和Node之间通过RPC进行通信。
系统日志模块和状态机的任务都是通过Disruptor异步去执行。

这里主要介绍一下几个类的功能。

  • FSMCaller主要就是将日志同步到状态机。

  • LogManager,顾名思义,就是管理日志。

  • MetaStorage用来存储节点的元数据信息。

  • SnapshotExecutor就是快照方面的实现。

具体实现细节还是要深入到源代码。
为了我们更方便的去分析代码。我们从对应简单的例子counter出发。

3.源码分析

CounterServer服务端启动流程
// 这里让 raft RPC 和业务 RPC 使用同一个 RPC server, 通常也可以分开
final RpcServer rpcServer = RaftRpcServerFactory.createRaftRpcServer(serverId.getEndpoint());
// 注册业务处理器
CounterService counterService = new CounterServiceImpl(this);
rpcServer.registerProcessor(new GetValueRequestProcessor(counterService));
rpcServer.registerProcessor(new IncrementAndGetRequestProcessor(counterService));
// 初始化状态机
this.fsm = new CounterStateMachine();
// 设置状态机到启动参数
nodeOptions.setFsm(this.fsm);
// 设置存储路径
// 日志, 必须
nodeOptions.setLogUri(dataPath + File.separator + "log");
// 元信息, 必须
nodeOptions.setRaftMetaUri(dataPath + File.separator + "raft\_meta");
// snapshot, 可选, 一般都推荐
nodeOptions.setSnapshotUri(dataPath + File.separator + "snapshot");
// 初始化 raft group 服务框架
this.raftGroupService = new RaftGroupService(groupId, serverId, nodeOptions, rpcServer);
// 启动
this.node = this.raftGroupService.start();

1.首先通过工厂模式创建一个RpcServer。RaftRpcServerFactory#addRaftRequestProcessors 主要就是注册一些时间处理器。根据不同的协议处理。这个序列化协议使用的google的protobuf。每当有不同的请求过来都会调用不同的处理器方法。

2.然后创建一个一个业务类。因为这个例子比较简单,其实就是维护一个分布式自增键。所以只有两个操作,一个就是增加value大小,一个是读取该值。对应的Processor也就是调用了CounterService的这两个操作。当然这不是我们关注的重点。

3.创建业务状态机。raft提供了一个StateMachine接口,奈何他的方法太多,业务方有时候没有必要去实现。所以他提供了一个适配器。这个也就是适配器模式。是可以去学习的。

StateMachine有很多方法。比如节点状态变化的回调。其中核心的还是onApply方法。参数是一个Iterator,可以看出是可以批量apply的。这个方法,业务方一般要去主动实现。


4.设置NodeOptions并初始化RaftGroupService  ,最后调用strat启动服务。

RaftGroupService#start方法

1.该节点的信息校验
2.将该几点添加到NodeManager 中。这是一个单例的实现。用于存储该进程RPC地址信息。和raft的group 信息。
3.通过工厂创建raft node并init。init rpc server。

NodeImpl#init方法

这个方法比较长,我们慢慢分析

1.获取JRaftServiceFactory,这个工厂主要用于创建各种存储实现类。这里通过SPI机制暴露给也业务方实现。当然raft有个默认的实现。DefaultJRaftServiceFactory

具体SPI实现后面会介绍一下。其实就是JRaftServiceLoader 实现。

2.初始化配置信息。校验,ip准确,并且一个ip:port只能创建初始化一次。初始化定时线程池。初始化各种计时器。

3.初始化配置管理器,主要就是集群配置

4.初始化请求的disruptor队列

th
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值