原文地址: https://www.tony-yin.site/201...
以前写过一篇文章【Ctdb Rados方式致使All Banned的问题】,谈到了当ctdb
将recovery lock
设置成rados
的方式后,断网master
节点会形成全部ctdb
节点All Banned
,主要缘由是master
意外断网没有释放锁,其余节点没法获取到锁,当时的解决方案是每5
分钟检查一次ctdb
状态,若是连续两次发生了All Banned
的状况,则手动删除lock
,这种作法在最近的测试中遇到了一些问题,本文对这些问题进行剖析并对相应的解决方案进行分享。node
完整代码地址: https://github.com/tony-yin/C...
若是基于原来的作法,ctdb
发生All Banned
的状况,须要十分钟的监控时间加上两分钟左右的recovery
时间,也就是说大概须要十二分钟才能恢复ctdb
服务,这样看来高可用有点名实其副了,这个也会明显地影响存储业务的正常运行。后来,咱们讨论出新的方案:每5s
检查一次ctdb
的状态,All Banned
的次数累计到5
次才肯定为该故障场景,而后手动删除lock
,最终要保证ctdb
可以在2min
内完成恢复。git
cron tab
最短周期只支持分钟级别,因此如何5s
检查一次即是一个问题。github
代码是死的,人是活的,虽然cron tab
只支持分钟级别,可是咱们能够每分钟调用一个脚本,而后在这个脚本中遍历12
次,每次调用ctdb monitor
脚本,而后sleep 5s
,这样就能够达到每5s
检查一次ctdb
的效果了。shell
# ctdb_monitor * * * * * root /etc/ctdb/cron-seconds # cron-seconds #!/bin/bash for((i=1;i<=12;i++));do ../monitor_ctdb sleep 5 done
这样检查到ctdb
发生All Banned
状况,只须要花费25s
,剩下的就是recovery
的时间了。bash
当ctdb master
节点的network
服务断掉,其余两个节点(个人开发环境是三节点的虚拟机环境)便会选举一个为master
节点,而后去获取lock
,由于原master
没有释放锁,致使全部节点All Banned
,即便咱们手动删除了锁,可是这时候其余两个节点仍然处于Banned
的状况,须要等到Ban Timeout
才会再次尝试获取锁并开始恢复过程,这个timeout
的时间是300s
,即5min
,这显然是咱们不能接受的,因此咱们要在删除lock
后,重启全部节点的ctdb
服务。网络
不过该如何触发该重启操做呢?测试
咱们在删除lock
后将ctdb
全部节点的ip
做为对象存进rados
中,而后在每5s
监控的脚本中,查看rados
中是否存在本节点的ip
对象,若是有,则尝试重启ctdb
操做,重启后便删除该对象。spa
function save_nodes_ip() { nodes=$(ctdb listnodes) for node in $nodes; do echo "$node" > $node rados -p rbd put $node $node rm -f $node done } function get_current_node_ips() { ips=$(/usr/sbin/ip addr | grep "inet " | awk '{print $2}') echo $ips } function monitor_nodes_ip_in_rados() { ips=$(get_current_node_ips) for ipinfo in $ips; do ip=${ipinfo%/*} if $(timeout 10 rados -p rbd ls | grep "$ip" -qw); then systemctl restart ctdb rados -p rbd rm $ip fi done }
至于为何三个节点的ip
都要存入rados
,这个是由于原master
节点恢复网络后,ctdb
服务的状态为failed
,一样须要重启ctdb
服务才能正常恢复原master
节点。 命令行
注意:rest
这边有两个问题,当时浪费了我很多时间,问题不是多么深奥,可是不易发现。。。
第一个问题即是ips=$(/usr/sbin/ip addr | grep "inet " | awk '{print $2}')
这行代码,原来的写法是ips=$(ip addr | grep "inet " | awk '{print $2}')
,当时发现ip
老是获取不到,而后不管是命令行仍是脚本运行均可以正常获取到,后来仍是同事提醒才发如今crontab
脚本中,shell
命令默认是/usr/bin/
下的,而ip
命令则是/usr/sbin/
下,因此这里的命令咱们须要全路径。(这个须要格外注意!!!被坑的不要不要的。。。)
第二个问题即是rados -p rbd ls | grep "$ip" -qw
这行代码,当时没注意写成了rados -p rbd ls | grep "$ip" -w
,发现if
判断时常有问题,一开始还觉得不能grep
数字什么的,后来才发现没有加q
,q
表示安静模式,不打印任何标准输出,若是有匹配的内容则当即返回状态值0。
“断网”这个词不够具体,在实际生产环境中,一个集群中,通常都会有多个网络,就拿本人的ceph
集群环境来讲(物理机环境,并不是前文说起的虚拟机开发环境),ceph
有个public network
和cluster network
,而ctdb
也有它的node network
和public network
,ceph
的public
和ctdb
的public
是同一网段,ceph
的cluster
是单独网段,ctdb
的node
是单独的网段。因此ctdb master
断网能够分为三种状况:
ctdb master node
网段网线ctdb master public
网段网线ctdb master network
服务当拔掉ctdb master public
网段网线,这没有什么好说的,ctdb master
节点服务还存在,只是master
节点上的public address
不可用了,会漂移到其余节点上。
当拔掉ctdb master node
网段网线后,master
节点仍然有public
网卡,(这里注意)它仍然能够获取其余ctdb
节点的状态,而其余节点却不能够获取它的状态,由于master
的node
节点ip
不存在。因此形成的结果就是原master
节点还默认本身是master
节点,而其余的节点却又选举出了新的master
,咱们的脚本由于All Banned
手动删除了lock
,这时候其余节点能够正常恢复ctdb
服务,可是当ctdb master
节点断网再恢复后,它还觉得本身是master
,会不断去获取锁,而原来的锁已经被咱们手动删除,这时候新的锁被新的master
掌握,因此此时产生脑裂,咱们要牺牲原master
节点,也就是断网节点,因此须要重启它。这个重启触发机制咱们是经过在每次删除lock
以后在rados
中存入ctdb
全部节点的ip
做为object
(这就是为何要存入全部节点的ip
),而后只要发现有这个object
便执行ctdb
重启操做,而后便删除这个对象。至于为何要存全部对象是由于除了原master
须要重启以外,另外两个正常节点发生All Banned
的状况,默认timeout
时间是300s
(这个上面也提到过),咱们为了减小恢复时间,直接在删除lock
后重启ctdb
;
因为如今ctdb
的锁是放在rados
中,而不是之前的cephfs
的方式了。因此当master
断网再恢复时,它会不断地去rados
获取他原来的锁,这是获取锁的进程愈来愈多,会阻塞住rados
服务,咱们能够经过ps -ef | grep rados_helper
看到进程不断变多,那么rados
服务不能正常读写就影响到咱们上一条的机制,不能读rados
中是否含有本节点ip
的对象,就没办法进行重启操做,那么这样它就会不断地继续获取lock
,因此咱们在这里又加了一个机制,若是ps -ef | grep rados_helper
的数目超过6
个,就默认启动重启ctdb
服务。
function monitor_get_lock_timeout() { count=$(ps -ef | grep rados_helper | wc -l) if [ $count -ge $RADOS_HELPER_PROCESS_MAX ]; then systemctl restart ctdb update_last_ctdb_restart_time fi }
ctdb
目前重启的机制有点多,有自身自带的故障重启,也有咱们监控脚本的异常状况,很容易发生重复重启,还有可能rados_helper
堆积的进程不少,好比20
个,咱们的脚本是5s
一次,也许20
个的时候重启了,过5s
,进程释放也须要时间,可能此时还有10
个,那么大于咱们规定的6
个,就会继续重启,这种重复重启没有必要,因此咱们要加上ctdb
重启的周期限定2min
。
function get_ctdb_restart_interval() { last_time=$(get_ctdb_restart_last_time) if [ -z "$last_time" ]; then interval=$(expr $RESTART_CTDB_INTERVAL_MAX + 1) else current_time=$(date +%s) interval=$(expr $current_time - $last_time) fi echo $interval }
考虑并解决以上提到的问题,基本上能够覆盖以上三种断网的场景了,在监控和管理ctdb
的过程当中,必定要当心,不能影响到业务正常运行。
生产环境网络结构错综复杂,每每在虚拟机上开发的功能当时好好的,到了物理机上面测试会发生各类问题,此时,咱们首先要搞清楚网络拓扑结构,熟悉硬件配置,各网段的做用和相互之间的关联,这样遇到问题咱们能够顺藤摸瓜,一样ctdb
的原理也须要掌握才能了解它各类行为的触发机制,才能更好的定制化监控和管理。以后我会花点时间好好地研究一下ctdb
,而后再单独作分享。
完整代码地址: https://github.com/tony-yin/C...