Ctdb Rados(二):多场景断网高可用

原文地址: https://www.tony-yin.site/201...

ping

以前写过一篇文章【Ctdb Rados方式致使All Banned的问题】,谈到了当ctdbrecovery 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

问题1

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

问题2

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数字什么的,后来才发现没有加qq表示安静模式,不打印任何标准输出,若是有匹配的内容则当即返回状态值0。

场景二

“断网”这个词不够具体,在实际生产环境中,一个集群中,通常都会有多个网络,就拿本人的ceph集群环境来讲(物理机环境,并不是前文说起的虚拟机开发环境),ceph有个public networkcluster network,而ctdb也有它的node networkpublic networkcephpublicctdbpublic是同一网段,cephcluster是单独网段,ctdbnode是单独的网段。因此ctdb master断网能够分为三种状况:

  • 拔掉ctdb master node网段网线
  • 拔掉ctdb master public网段网线
  • 断掉ctdb master network服务

当拔掉ctdb master public网段网线,这没有什么好说的,ctdb master节点服务还存在,只是master节点上的public address不可用了,会漂移到其余节点上。

问题1

当拔掉ctdb master node网段网线后,master节点仍然有public网卡,(这里注意)它仍然能够获取其余ctdb节点的状态,而其余节点却不能够获取它的状态,由于masternode节点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

问题2

因为如今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
}

问题3

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...
相关文章
相关标签/搜索