sofastack / sofa-jraft

A production-grade java implementation of RAFT consensus algorithm.
https://www.sofastack.tech/projects/sofa-jraft/
Apache License 2.0
3.57k stars 1.14k forks source link

【JRaft RheaKV】基于Learner节点完成异地灾备的方案,完整操作流程是怎样的?问题描述中的过程有何问题? #1133

Closed en-hui closed 1 month ago

en-hui commented 1 month ago

Your question

使用learner如何完成异地数据灾备? 在此issue中我已了解learner的基本使用方式:https://github.com/sofastack/sofa-jraft/issues/115

我的操作步骤: 设置初始化服务列表 initialServerAddress 为 127.0.0.1:8181,127.0.0.1:8182,127.0.0.1:8183,127.0.0.1:8184/learner,127.0.0.1:8185/learner,127.0.0.1:8186/learner 启动六个节点分别记作 p1, p2, p3, p4, p5, p6,初始化时设置p1, p2, p3为备选节点;p4, p5, p6为learner节点

// 定义conf,提前书写,便于理解以下步骤中用【】包裹的代码 List allPeerId = Arrays.asList(p1, p2, p3, p4, p5, p6); List cityA = Arrays.asList(p1, p2, p3); List cityB = Arrays.asList(p4, p5, p6); // 不太理解作为客户端,为什么构造可以同时指定peer和learner,尝试全部节点都指为peer也没问题 Configuration conf = new Configuration(allPeerId);

1、程序运行一段时间后,直接停掉p1, p2, p3三台节点,此时服务不可用 2、使用cliService查询leader,显示leader为p2【cliService.getLeader(groupId, conf, leader);】 3.1、此时查询peer会报错java.lang.IllegalStateException: Fail to init channel to leader 127.0.0.1:8182 【cliService.getPeers(groupId, conf)】 3.2、此时查询learner会报错java.lang.IllegalStateException: Fail to init channel to leader 127.0.0.1:8182【cliService.getLearners(groupId, conf)】 4、使用cliService操作集群,将p4, p5, p6设置为备选节点,结果均为OK 【cliService.resetPeer(groupId, p4, conf)】【cliService.resetPeer(groupId, p5, conf)】【cliService.resetPeer(groupId, p6, conf)】 但使用【cliService.getLeader(groupId, conf, leader);】查询leader,此时为0.0.0.0:0 5、此时尝试将p1, p2, p3设置为learner节点,结果为Status[UNKNOWN<-1>: Fail to get leader of group rhea_example--1, Unknown leader, Unknown leader, Unknown leader] 【cliService.resetLearners(groupId, conf, cityA)】

假设城市A部署的节点为p1、p2、p3;城市B部署的节点为p4、p5、p6; 根据以上操作步骤,A、B城市的异地灾备切换失败

请问我的操作步骤哪里不规范,是对哪些api理解不透彻呢? 对于api中的peer应该如何理解,如下api应该如何使用,是否需要根据peer和learners的真实情况构造配置对象(理论上写客户端不知道此时真实的节点角色情况

/**
 * Construct a Configuration instance with peers and learners.
 *
 * @param conf     peers configuration
 * @param learners learners
 * @since 1.3.0
 */
public Configuration(final Iterable<PeerId> conf, final Iterable<PeerId> learners)
fengjiachun commented 1 month ago

4、使用cliService操作集群,将p4, p5, p6设置为备选节点,结果均为OK

这一步里的 conf 是只有 p4 p5 p6 三个 peer 且非 learner 吗?如果是,那么应该很快会选出新的 leader,如果一只没有 leader,请翻下日志

上面这一步有 leader 了,再执行后续的操作

fengjiachun commented 1 month ago

以下几个问题我也简单回答解释下:

3.1: 因为 leader 不是让你搞挂了吗? 3.2: 同理啊,这个信息需要从 leader 上获取

5: 新集群都还没 leader 呢,执行这个无意义

en-hui commented 1 month ago

4、使用cliService操作集群,将p4, p5, p6设置为备选节点,结果均为OK

这一步里的 conf 是只有 p4 p5 p6 三个 peer 且非 learner 吗?如果是,那么应该很快会选出新的 leader,如果一只没有 leader,请翻下日志

上面这一步有 leader 了,再执行后续的操作

List allPeerId = Arrays.asList(p1, p2, p3, p4, p5, p6); // 不太理解作为客户端,为什么构造可以同时指定peer和learner,尝试全部节点都指为peer也没问题 Configuration conf = new Configuration(allPeerId); 我在执行第四步时,使用的conf,也是包括了全部节点,这样的用法是错误的?

执行 cliService.resetPeer(groupId, p4, conf) 这一步,他是什么含义?为什么指定p4,p5,p6就可以让p1,p2,p3的peer身份失效?由后面的 conf决定全部peer?

最后这个conf,使用的原则是什么,假设集群包含元数据,放全部也可以? 当集群没主的时候,就应该放期望的peer?

fengjiachun commented 1 month ago

我在执行第四步时,使用的conf,也是包括了全部节点,这样的用法是错误的?

你是用全部 6 个节点,已经挂了 3个 (abc),你让集群怎么选主捏 😮‍💨

fengjiachun commented 1 month ago

cliService.resetPeer(groupId, p4, conf)

这一步是更新集群的成员列表

fengjiachun commented 1 month ago

https://www.sofastack.tech/projects/sofa-jraft/raft-introduction/

上面链接是我以前对 raft paper 的一个重点知识的提炼,有空的话,比较推荐粗略看下,上面几个 api 的使用,其实稍微有一点会依赖对 raft 的理解

en-hui commented 1 month ago

好的,感谢。 我按照您的方式修改了conf,解决了无法选主的问题。 以上步骤均可成功完成,且符合预期