前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >极端场景下jraft的验证

极端场景下jraft的验证

作者头像
richard.xia_志培
发布2022-06-14 14:36:39
1K0
发布2022-06-14 14:36:39
举报
文章被收录于专栏:PT运维技术PT运维技术

最近1-2周, 业务侧基于性能和一致性的需求,测试和验证基于sofa-jraft的框架。由于上线后事关生产环境的稳定性,于是加入调研jraft/raft相关领域调研,确保生产环境即使在极端情况下,也在我们考量的范围之内。

对于一个陌生的组件的极端场景的考虑,一般分2个阶段。

第一阶段,不了解组件的原理,当成黑盒处理,模拟常规极端场景。

例如机器掉电,网络中断,网络丢包,进程被kill, 进程挂起hang

第二阶段,了解组件的原理,针对组件的特点,模拟进一步的极端场景。

例如在心跳时间的边界上模拟极端场景,内部各种超时时间的边界上模拟极端场景

列出较为完善的极端场景后,剩下就需要考虑实现极端场景模拟手段。

第一阶段极端场景(在未调研jraft的时候,将jraft当成黑盒):

-----------------------------------------------------------

1. 机器掉电 /网络中断形成孤点

主机的网线被剪断/机器掉电的情况下,相邻节点上处于ESTABLISH状态的连接,是无法感知对端tcp连接中断的,因为机器断电和网络完全中断可以列为一类。(而普通的关机触发的kill -15或者kill -9 在OS回收fd(close)的时候,TCP协议栈会发送fin或者RST, 详细差异在此不展开)。

能够使用iptables来模拟断网么?对于新增TCP连接可以,但对于存量的长连接,iptables无法处理。因此TC是个比较快的实现方式(当然也有其他的方式,如内核注入), 先断网5分钟,5分钟后网络恢复:

实施手段:

#tc qdisc add dev eth0 root netem loss 100%;sleep 300;tc qdisc delete dev eth0 root

---------------------------------------------------------------------

2. 网络分区

节点网络分区的情况(leader/follower),对称网络分区场景1中已经模拟。

2.1 非对称网络分区

模拟手段:(去leader的线路网络不通,去另一个follower的网络可以连通)

#例如:10.121.4.45 是leader,在其中一台follower中执行

实施手段:

#tc qdisc add dev eth0 root handle 1: prio

#tc qdisc add dev eth0 parent 1:3 handle 30: netem loss 100%

#tc filter add dev eth0 protocol ip parent 1:0 u32 match ip dst 10.121.4.45 match ip dport 3600 0xffff flowid 1:3

---------------------------------------------------------------------

3. 进程oom 被杀

kill -9 java进程;(随机杀掉leader/follower角色的进程)

观察集群写入的连续性和正确性

---------------------------------------------------------------------

4. 进程挂起hang

kill -19 java进程,让java进程挂起hang(随机leader/follower角色的进程)

实施手段:

#kill -19 java进程pid;sleep 300;kill -18 java进程pid

观察集群写入的连续性和正确性

---------------------------------------------------------------------

随着对jraft的深入了解,来得第二阶段。在描述极端场景之前,先描述一下

jraft默认情况下的相关配置:

代码语言:javascript
复制
Jraft的默认参数:
electionTimeoutMs:1000ms
electionHeartbeatFactor: 10 // 心跳间隔时间=100ms
Linux RTO default: 200ms
snapshot 的频率:3600s
fsync 刷盘 默认开启:true
replicatorPipeline  默认开启

第二阶段的场景(已经了解到jraft工作过程和相关的默认参数)

--------------------------------------------------------

1. 网络丢包(观察TCP协议栈RTO时间和jraft心跳时间的极端情况下表现):

模拟对称网络 丢包:

1.1 对称网络丢包

#tc qdisc add dev eth0 root netem loss 1% 30%

1.2 非对称网络 丢包

#tc qdisc add dev eth0 root handle 1: prio

#tc qdisc add dev eth0 parent 1:3 handle 30: netem loss 1% 30%

#tc filter add dev eth0 protocol ip parent 1:0 u32 match ip dst leader的IP match ip dport 3600 0xffff flowid 1:3

观察集群写入的连续性和正确性

-------------------------------------------------------------------

2. IO延时超过jraft heartbeat时间(100ms), 在leader和follower上分别先后执行(间隔时间为集群恢复达到稳定的耗时),观察集群的是否写入是否正常.

通过内核注入的方式让IO写产生300ms延时:

实施手段:

#stap -e ' probe kernel.function("vfs_write").return

{

mdelay(300);

printf(“vfs_write delay 200ms\n”)

}'

2.1 再以jraft开启fsync和不开启fsync 将以上case 模拟一次。

观察集群写入的连续性和正确性

-------------------------------------------------------------------

3. 新增加节点到集群:(当前功能不支持动态修改node)

3.1 在leader正常情况下,增加节点到集群,一次添加3个节点(故意让选举失败,造成集群不可以),观察集群不可用时间和Election timeout的关系( (理论上不可用时间为election timeout的时间)

3.2 在leader正常情况下,增加节点到集群,一次一个节点(官方推荐), 观察集群的可用性

观察集群写入的连续性和正确性

------------------------------------------------------------------

4. 从集群中减少节点(当前功能不支持动态修改node)

4.1 在leader正常情况下,增加节点到集群,一次3个节点(故意选举失败,造成集群不可以),观察集群不可用时间和Election timeout的关系

4.2 在leader正常情况下,增加节点到集群,一次一个节点,观察集群的可用性

观察集群写入的连续性和正确性

-----------------------------------------------------------------

5. 灾难恢复(牺牲一致性)

5.1 网络分区的情况下,少数节点形成的分区场景下,快速恢复集群可用?

2个机房(3节点+2节点)部署集群,3个节点在vpc_dev的private_a, 2个节点在vpc_test的private_a

通过TC 规则或者阻断vpc路由的方式,阻断3节点和2节点的连通,形成分区。

通过jraft CLI提供的resetPeers方法重置集群节点组 ---验证极端情况

观察集群写入的连续性(针对少数节点形成分区)

-------------------------------------------------------------------

6. 模拟leader 收到client请求后,收到follower的response后,还没有commit到状态机就挂了, 观察client端收到的response状态以及一致性.

3个节点组成集群, 将Election timeout的时间调整为60s, 心跳时间调整为6s,

6.1 # wrk 高并发压测,插入精心构造的顺序数据。采用场景2中对写入注入延时3s, 接着kill -9 leader的java进程, 观察wrk的报错,以及插入的id值, 6s内启动leader java 进程, 继续压测,观察最终构造的数据和集群中的数据的一致性:(一个心跳时间内启动,leader仍然是leader)

6.2 # wrk 高并发压测,插入精心构造的顺序数据。采用场景2中对写入注入延时3s, 接着kill -9 leader的java进程, 观察wrk的报错,以及插入的id值, 10s后启动leader java 进程, 解析压测,观察最终构造的数据和集群中的数据的一致性: (一个心跳时间内启动,leader可能是leader)

6.3 # wrk 高并发压测,插入精心构造的顺序数据。采用场景2中对写入注入延时3s, 接着kill -9 leader的java进程, 观察wrk的报错,以及插入的id值, 60s后启动leader java 进程, 解析压测,观察最终构造的数据和集群中的数据的一致性: ((一个Election timeout时间后启动,leader已经不是leader)

观察集群写入的连续性和正确性

---------------------------------------------------------------------

7. snapshot过大的场景测试

调整 snapshotIntervalSecs = 300,压测产生数据,产生10G左右的snapshot(故意让snapshot持久化耗时大于间隔时间), 模拟网络分区(见第一阶段场景2), 继续压测产生数据,数分钟后,将脱离集群的node,再次加入到集群,观察应用日志, 观察压测端写入jraft集群是否正常。

-------------------------------------------------------------------

8. 一致性读准确性

8.1 ReadIndex 的缺点(隐患点)

这时候的 commit index 并不能够保证是当前整个系统最新的 commit index,所以 Raft 要求当 leader 选举成功之后,首先提交一个 no-op 的 entry,保证 leader 的 commit index 成为最新的。如果在 no-op 的 entry 还没提交成功之前,leader 是不能够处理 ReadIndex 的。

精心构造顺序数据,间隔1s的速度写入集群(记录ns级时间戳),开启一个客户端以0.02s的速度读取jraft集群的最大序列(记录ns级时间戳),在leader上模拟IO延时2000ms, 接着kill -9 leader的进程,kill -9 生产者进程(写到一个脚本,保证2个kill 在1s内完成, 此刻的生产者会阻塞住2s左右),

观察客户端读jraft的连续性和正确性(读取最大序列是多少和中途报错类型)。接着手工插入一个序列(插入成功的序列的值+1)到jraft集群,观察客户端读jraft集群中最大序列是多少。

8.2 lease Read的缺点(隐患点)

故意将主机时钟调慢15秒

s=`date +%s`;s_d=((s-15));date -s `date -d " +

时钟回拨造成租约时间无效。(官方不建议lease read)

观察集群读的连续性和正确性

--------------------------------------------------------------------

除了以上极端场景,还有jraft 版本升级的问题(大版本),官方虽未给出详细方案,由于开发团队和sofa-jraft作者属同事关系,理论上升级方案不会是大问题。

如果12个极端场景测试下来均符合预期,那么线上的安稳性把握性就非常大了(除非触发深度bug)。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-07-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PT运维技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档