raft 相关问题,希望 v2 大佬来解答一下

2018-02-22 14:10:13 +08:00
 ray1888
  1. 如何确定大多数 (因为执行的 log 为 commited log,而 commited log 需要大多数机接收到,所以如何确认大多数是一个问题)
  2. 如何令新节点接入到集群中
  3. 因为只有一个 leader 并且 leader 是要等待 follower 确认接收才使状态机运行到下一状态,如果应对大请求的时候,follower 是否可以用于应对请求
3868 次点击
所在节点    程序员
12 条回复
MarsWang
2018-02-22 14:44:27 +08:00
问题 1:leader 和 follower 保持心跳,leader 知道所有 follower 是否存活,自然也就知道一个 log 发出去之后是否成功过半。
问题 2:新节点从 leader 心跳中得知本地 log 不完善,需要进行追加补全本地 log,补全后和普通 follower 一样。
问题 3: 不存在 follower 应对请求的情况,新 log 都需要经过 leader 进行派发,follower 只能被动接收 leader 派发的 log。
ray1888
2018-02-22 14:56:26 +08:00
@MarsWang 问题一和二的地方我主要是实现上的理解问题。因为一个新节点加进来,除非我们在初始化新 raft 的时候已经把已经存在的 raft 集群全部当成配置文件去写入,否则他怎么知道他有多少个 peer 和怎样去链接已有的集群?
ray1888
2018-02-22 14:58:41 +08:00
@MarsWang 第三个问题的时候,那如果请求量太大的时候,那所有的回应都要经过 leader 的情况,这样会把整个集群拖垮吧,因为假设 leader 更换,单个 leader 是还是处理不了那么多的请求的时候,那 leader 切换这里也没什么意义了,切了一样崩
ray1888
2018-02-22 15:18:22 +08:00
@MarsWang 第三个问题论文里没有描述,但是在 tidb 里面的论文有提到 multi-raft 这个概念,应该是使用 multi-raft 来解决这个问题
zhqy
2018-02-22 15:19:09 +08:00
1 和 2:可以参考 etcd,two-phrase config change,新节点加入集群时候首先通知到集群新节点的信息,然后启动新节点,raft 集群中每个节点本身是维护着集群中所有节点的诸如 url 这些信息的。

3:你这里说的『应对请求』具体是什么意思呢? follower 当然是可以处理请求的,只不过需要转发给 leader,走完 raft 的一致性过程,只要本地状态机已经 apply 这个 log,就可以返回 response 给请求方了。
cloud107202
2018-02-22 15:22:25 +08:00
1. 在选举过程中 leader 知晓并负责管理全部节点,所以 leader 在任期内可以确定大多数成功。“而 commited log 需要大多数机接收到”这里描述不够精确:对于一个 client 发来的一个条目,leader 接收到之后广播给所有节点。leader 在确认集群多数节点写成功之后(收到大多数节点的 ack ),才进行 commited 动作(此时把条目 apply 到状态机才是安全的),稍后 follower 在 log replication 的过程中也会本地 commit 这个条目(因为后续心跳包里会包含 leader 已提交的 index 号)

2. https://github.com/maemual/raft-zh_cn/blob/master/raft-zh_cn.md#6-%E9%9B%86%E7%BE%A4%E6%88%90%E5%91%98%E5%8F%98%E5%8C%96

3. 这个算是分布式系统设计的常识,首先不同角色的职责是固定的,foller 不会应对请求。而论文所述的 raft 属于 single-leader replication 机制,只有 leader 一个单点应对请求。你说的这种情况属于 multi-leader 类型的系统,虽然能增加吞吐量,但是同一份数据在多个 leader 可能会并发修改造成冲突,所以这类的系统必须引入冲突检查和冲突恢复机制,实现更为复杂。针对 raft 有 multi-raft 的扩展层
https://github.com/deepfabric/elasticell/blob/master/docs/architecture/multi-raft.md 似乎 CockroachDB 和 TiDB 用到了类似的设计
MarsWang
2018-02-22 15:32:53 +08:00
@ray1888 添加新节点和下线节点,raft 论文上提到过:Cluster membership changes,配置项通过 log commit 来同步,有一个中间配置来过渡,新的配置同步成功后在切到新的配置。

问题 3 负载问题需要从另一个角度去考虑吧!比如 multi raft。
colorfuldays
2018-02-22 16:20:51 +08:00
问题 3 可以通过对数据进行 partition,不同的 raft-group 处理不同的 partition 来解决
swulling
2018-02-22 16:29:16 +08:00
> 1. 如何确定大多数 (因为执行的 log 为 commited log,而 commited log 需要大多数机接收到,所以如何确认大多数是一个问题)
> 2. 如何令新节点接入到集群中

大多数就是>N/2,N 是节点总数量。增加或者减少节点使用 two-phase 的方法,集群会首先切换到过度配置( joint consensus ),等这个被提交后,再切换到新的配置。具体可以看 paper 的成员变化那一节。


> 3. 因为只有一个 leader 并且 leader 是要等待 follower 确认接收才使状态机运行到下一状态,如果应对大请求的时候,follower 是否可以用于应对请求

Raft 为了实现简单,原始协议没有支持。
vizee
2018-02-22 18:41:39 +08:00
1. 按论文上的做法是大多数(>N/2) AppendEntries 成功后 leader 确认 log 复制成功后才 commit log, 并且在后续的 AppendEntries 中告诉 follower 领导人当前的 leaderCommit, 所以只考虑的是复制成功
2. 成员变更问题请看论文
3. 论文上需要以保证超过一半的节点收到日志, 实际应用的几个项目都优化了这点, 边提交边复制, 反正所有请求处理都在 leader 上
xiaottt
2018-02-24 18:08:08 +08:00
集群成员有配置的,就知道集群总成员是多少;而添加日志是 RPC 同步调用,当然可以确认绝大多数成功了;
新机器加入节点、旧机器下线,虽然生产更改概率很少,但确是算法重点强调的安全问题,说明论文没有好好看;
这个类似于数据库读写分离,所有变更的请求都必须在 leader 上,即使连到 fellower 也要转发到 leader 上;如果读操作看你是否容忍读取脏数据,否则就需要 fellower 向 leader 确认自己是否含有最新状态。
wqlin
2018-02-25 23:42:32 +08:00
谈谈我的理解:
问题1:每个服务器应该有记录集群数量,这样才能确定 majority 的数量。集群数量初始值可由配置文件读入,当有服务器上线 /下线时,才更新相应集群数量。
问题2:新节点加入 /旧节点退出在 [Raft 论文]( https://raft.github.io/raft.pdf) 第六节 Cluster membership changes 有描述,可以保证集群安全过渡到新状态。
问题3:Raft 是强领导协议,只能领导者才能处理客户端请求; follower 本身是消极的( passive),只接受领导者的 RPC 请求。如果客户端将请求发给 follower,那么 follower 会拒绝这次请求,告知客户端应该向 leader 请求。这与 ZooKeeper 类似,ZooKeeper 也是强领导机制。楼主说的这种允许多个节点提交,不知道能不能 multi-paxos 能不能实现(个人也不了解)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/431642

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX