Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

结合NWR实现Flexible raft,用于自定义Quorum的大小 #975

Open
shihuili1218 opened this issue Apr 20, 2023 · 10 comments
Open

结合NWR实现Flexible raft,用于自定义Quorum的大小 #975

shihuili1218 opened this issue Apr 20, 2023 · 10 comments

Comments

@shihuili1218
Copy link
Contributor

简介

RAFT

SOFAJRaft 是一个基于 RAFT 一致性算法的生产级高性能 Java 实现,JRaft的运行过程分为两个阶段:

  • Leader选举,Leader选举用于在集群中选出一个数据最完成的成员当选Leader,处理日志复制;
  • 日志复制,用于Raft集群协商事务请求,客户端的指令。

在原始的RAFT算法中,Leader选举、日志复制,都要求获得多数派(即:⌊N / 2⌋ + 1)成员的支持。即:某个成员获得多数派成员的支持则晋升为Leader;某个日志复制到多数派则达成共识。

NWR

NWR模型,常用于动态调整一致性强度。具体描述如下:

  • N:成员总数
  • W:写入数据的Quorum数
  • R:读取数据的Quorum数

满足W+R>N的情况下,读Quorum和写Quorum一定存在交集,这个相交的成员一定拥有最新的数据,那么这个分布式系统一定是满足强一致性的。

目标

在一些场景中,我们期望能够动态调整Quorum的数量,使其更贴合自己的业务场景。例如:一个5成员组成的集群,在一个写多读少的场景中,则期望把多数派(3)调整为2,降低达成共识的条件,使得写请求能尽快的完成。同时,为了继续满足RAFT的正确性,将写Quorum调整为2需要付出代价是读Quorum要调整为4,这样才能满足W+R>N。

基于这个设计,用户甚至可以将Quorum调整到一个极端情况。例如:W=1,R=N,此时写效率最高,当然这需要付出的代价是不允许有成员宕机。

RAFT结合NWR

Raft中Leader选举存在两个功能:

  • 选出集群认可的成员处理写请求
  • 选出的成员,必须拥有最完整的日志,这用于确保已达成共识的不会被覆盖

这正好对应了NWR模型中的读场景,而处理事务日志对应NWR模型中的写场景。

NWR的计算方式

因为JRaft是支持成员变更的,N是动态变化的,因此我们所配置的W或R不能是一个整数,可以考虑为(0, 1]范围内的小数。再通过计算获得W和R的具体值。
例如:N=5,w=0.4,计算公式为:W=⌈N * w⌉,R=N - W + 1。得到以下表格

N W R
5 2 4
6 3 4
7 3 5
8 4 5
9 4 6
10 4 7
11 5 7
@funky-eyes
Copy link
Contributor

这个功能感觉不好吧,如果用户可能稀里糊涂的配了w,就跟kafka副本集一样,5台机器配了topic是2副本,此时挂了2个broker,必定有部分分区不可用,毕竟这个项目叫jraft,就是应该基于raft的原理基础上去实现,跟nwr模型结合反倒感觉违背了raft的共识,这还能叫raft吗?

@shihuili1218
Copy link
Contributor Author

这个功能会提供开关,给用户多一种选择。选择使用自定义Quorum,一定是在生产场景多次考量,且熟悉配置w或r的造成影响的前提下使用此功能。

这个功能必须要满足W+R>N的场景,在满足这个条件的前提下,无论用户怎么折腾,数据正确性是一定能保证的。当然你说的情况(可用性的降低)是使用此功能需要付出的代价,这是用户需要结合生产场景,在性能和可用性之间的取舍。

@funky-eyes
Copy link
Contributor

写请求更快的响应,说明是减少了写时日志同步的应答数吗?假设出现了网络分区怎么解决? req->leader -> follower->leader -> rep,这个时候在中间follower相当于没有超过半数了,加上网络分区,leader节点达标了写入了,假设是5台,2 3这样分区,2写入了这个数据,然后3台立马恢复了网络,这个时候会发生什么?或者2台机器正常,3台的盘写满了,或者盘出现了问题

@shihuili1218
Copy link
Contributor Author

写请求更快的响应,说明是减少了写时日志同步的应答数吗? -- 是的
假设是5台(写quorum为2),2\3这样分区,2写入了这个数据,然后3台立马恢复了网络,这个时候会发生什么? -- 3台恢复过来,集群是不能提供服务的,因为读quorum需要4个节点存活,这就是需要付出的代价:可用性降低、读请求延迟

@funky-eyes
Copy link
Contributor

我的意思是,那3台挂了或者网络断开了,leader的日志可能都没发过去,我举个极端例子
2台 /3台网络分区后,前两台写入了数据,后三台没有,然后集群一并宕机,此时后三台恢复启动,选出新leader,再启动前2台,此时数据不就丢了吗?因为提交的数据没有大于1/2了,前面2台client发请求到对应leader,leader都给client确切已写入的应答后挂了,这不就不一致了?还是说是我理解的有问题呢?

@shihuili1218
Copy link
Contributor Author

我整理以下你说的场景啊,集群{A, B, C, D, E},Leader为A,W=2,R=4。
分区后的集群为{A, B}、{C, D, E}。

  1. {A, B}是可以处理写请求的,Leader A将日志写入A和B,达成共识。
  2. {A, B}、{C, D, E}都宕机
  3. {C, D, E}恢复,注意此时,是不足选出Leader的,因为R=4。

@funky-eyes
Copy link
Contributor

明白了,是靠R进行限制达到一致性,这样就是降低了可用性了,按raft原本设计,5节点挂2个是还可以正常提供服务,而现在挂的次数>=w(写成员)就会导致服务不可用,不过对99.9%的情况而言,不太可能出现一下挂那么多节点,我认为这个功能是有比较好的价值,就是用到这块功能时,使用者用户需要明确知道其中的原理,否则可能会造成类似我上面存在的误解。
然后这个功能貌似对小于等于3节点其实是无影响的。这个任务是要做summercode的项目,还是开放到社区?

@shihuili1218
Copy link
Contributor Author

作为summercode的项目呢

@erdengk
Copy link

erdengk commented Apr 27, 2023

非常有意思的提议,我看到它作为ospp的项目之一,我准备申请它。

@1294566108
Copy link
Contributor

同样在OSPP关注到了,希望能继续参与JRaft的代码贡献

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants