Ratis代理服务初始化及启动 - RaftServerProxy

一、proxy配置(ratis自带例子 - counter)

图1.1

ratis proxy利用构建者模式 - Builder构建proxy实例,如图65~ 68行,分别设置proxy服务的分组、配置信息、节点信息、状态机。

分组信息封装于:RaftGroup 对象中,包含对应的分组标识符 - RaftGroupId 、构成分组节点集。

配置信息封装于:RaftProperties对象中,采用K-V模式将配置ratis需要的配置信息传递给Bulider构建器。

节点信息封装于:RaftPeerId对象中,包含当前节点的组内唯一命名。

状态机信息:StateMachine具体实现实例,是当前分组业务处逻辑处理的具体实现类,也是被分离在raft协议之外的具体业务实现逻辑。

二、proxy静态模型

如图2.1所示,RaftServerProxy 实现了接口 RaftServer,即proxy就是一个raft服务。

同时 proxy包含了九个主要属性,proxy所有功能都是依赖于这九个属性实现的。

    1、stateMachineRegistry:StateMachine.Regisstry - 状态机注册服务

        registry是proxy对所有状态机的管理服务,但是直到ratis - 2.3.0版本,该注册服务都是名不副实。registr只是简单实现了Function的一个接口定义。具体实体类在RaftServer接口中采用了lambda表达式(gid ->stateMachine)作为其实现类。没有起到其状态机注册器的作用,应为该注册器始终只有一个状态机被注册。具体代码可见 RaftServer$Builder#setStateMachine方法。

    2、properties:RaftProperties - RaftServer配置项

        简单的K-V模式的封装对象,对Ratis具体配置项的封装。为Raft服务的运行提供系统、应用层面的变量。Ratis服务通过简单的 key 获取配置的value,决定具体的运行方式。配置项详情见RaftServerConfigKeys类(包含了配置项及其默认值)

    3、liftCycle:LifeCycle - RaftServer生命周期状态机

        RaftServer生命周期状态机,是对RaftServer整体状态的控制器。包含了对RaftServer状态规则信息变更、运行期间服务状态的获取判定的等操作。

        其中状态的变更必须符合以下规则

图2.2

其规则控制就在LifeCycle中。

    4、peerSupplier:Supplier<RaftPeer> - Raft节点协议通信封装实体

        peer是对RaftServer当前节点的通信必要信息的封装。包含:唯一名称、三组协议通信地址的包装。为客户端请求提供通信地址信息。

        同时peer实例化通过MemoizedSupplier包裹,MemoizedSupplier是Supperlier的一个具体实现类,实现了对Supperlier执行结果单例缓存通过proxy final的修饰实现peer属性的不可变性。

    5、implExecutor:ExecutorService -  线程池(异步任务执行器)

        implExecutor单独针对RaftServer执行动态添加节点或者动态添加分组操作的执行线程池。将RaftServer写类型的管理与业务逻辑分离开。

        implExecutor采用Executors.newSingleThreadExecutor()工具构建一个只包含单个线程、无限工作队列的线程池。

        主要包含两个操作:

        1、节点的动态添加 - org.apache.ratis.server.impl.RaftServerProxy.ImplMap#addNew

         2、异步动态添加分组 - org.apache.ratis.server.impl.RaftServerProxy#groupAddAsync

    6、executor:ExecutorService  - 具体业务逻辑执行线程池

        executor通过配置项

            1、raft.server.threadpool.proxy.cached - 是否采用缓存线程池【默认值为:true】

            2、raft.server.threadpool.proxy.size - 线程池最大线程数【默认值为:0】

            通过这个两个配置项,构建具体的业务逻辑处理线程池,配置项对应关系如下图

图2.3

    7、serverRpc:RaftServerRpc - reft服务底层通信组件

        serverRpc是对RaftServer的底层通信组件,包含三种协议的RPC的具体实现逻辑。涉及到Raft节点的底层通信,这里不想洗介绍。  

    8、impls:ImplMap - raft代理服务具体代理对象

        impls就是对proxy具体代理对象的封装,通过一个CucurrentHashMap对象注册分组和具体的Raft服务。为后期具体的业务逻辑提供指定分组的具体服务对象。proxy在处理客户端请求时,通过请求中包含的分组信息选择具体的服务处理请求。这也决定了所有的客户端请求都必须要包含请求处理的所在分组。

    9、id:RaftPeerId - 节点信息,就是一个简单的节点唯一命名        

        单纯的节点名称,只是当前服务节点的标识符。

三、初始化

图2.4

如图2.4所示,proxy的启动涉及到8个类共32个操作。

1、Counter通过RaftServer内部静态类Builder构建一个RaftServer构建器

2、第3~11通过RaftServer构建器设置:所属分组、配置信息、节点信息、分组对应的状态机,并与最后执行build进行构建。

3、第12步是通过构建器的静态方法执行proxy的构建

4、第13步RaftServer$Builder使用反射的方式调用ServerImplUtils#newRaftServer方法。将porxy的构建交由ServerImplUtils执行。

5、从ServerImplUtils的生命线看,ServerImplUtils主要做了两件事

    1、第15步通过RaftServerProxy的构建器,构建proxy的实例。

        在执行proxy的构造器是,主要初始化上边介绍的属性。

    2、第23步初始化proxy的分组,在初始化分组时,通过proxy内部类ImplMap属性注册分组对的真实Raft服务(RaftServerImpl)

        添加分组实际上也是proxy的初始化的Raft服务的核心服务RaftServerImpl,proyx只是起到了一个代理服务和服务管理的作用,真实的业务处理器还是交给了RaftServerImpl执行。

四、启动

图2.5


图2.6    

proxy的启动比较简单,只是启动proxy中的各个组件

1、第2步执行图2.6中第一行业务逻辑,通过getImpls()获取所有分组信息,并在executor线程池中分别执行每个分组中注册的RaftServerImpl实例的start方法,异步并行的启动多个分组(可惜的是,到现在为止还未看到有直接多分组启动的方式)。

2、第3步设置lifeCycle生命周期状态控制器的状态,在设置状态变更之前通过方法参数传递需要执行的定制操作(这里的定制操作就是启动对应的底层通信组件),在组件正常启动后设置lifeCycle的状态。

3、第8步启动Raft服务的监控器-pauseMonitor,pasuseMonitor只是收集Raft在运行中的状态和执行情况信息,和业务无关。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容