原文地址: https://www.tony-yin.site/2018/04/20/Ctdb-Rados-All-Banned/

lock object

ctdb最近专门为ceph提供了一种raods object作为文件锁的方式,lock file可以放在对象存储中,而不是cephfs,从而大大降低了系统宕机的延时。在此方案的实践中,我们发现master节点宕机会导致严重的All Banned的问题,本文则围绕该问题展开讨论和提供本人的解决方案。

很多系统都在用ctdbHA,今天我们讨论的是基于cephfsctdb HA方案。ctdb的作用是在一个共享文件系统中,当所有节点都访问同一个文件时,ctdb会选举出一个master节点获得lock,我们之前的做法是把这个lock file放在cephfs的共享目录中,但是当其中某个节点down了之后,会导致cephfs这个目录卡死,进一步导致lock file在其他节点都获取不到,只有等到锁超时了之后才能获取到,而这个超时时间默认是300s,再加上ctdb的监控检测和恢复的时间,切换的时间少则十几分钟,多则几十分钟,这对于高可用场景来说无疑是灾难级的。

具体场景

ctdb的编译和安装我就不说了,大家可以参考磨渣的文章:CTDB使用rados object作为lock file。在ceph集群中所有节点安装好ctdb后,起服务后通过systemctl status ctdb可以发现reclock是通过ctdb_mutex_ceph_rados_helper的方式,就说明ctdb rados的方式配置成功了。

然后我们可以通过rados -p rbd ls也可以看到自己配置的锁存在于rbd pool中。这时我们断电一个slave节点,一分钟左右后可以实现节点切换。但是我们的测试发现当断网master节点的时候,就会造成长时间的卡住,且节点并不会切换。详细查看可以发现断网后,master节点没有释放lock,然后其他的集群节点选举出了master节点后,试图获取锁,但是由于之前的master节点一直没有释放,所以一直获取不到,然后就不停的去获取,ctdb的机制是如果有不断的这种行为,就会让所有节点All Banned。因为slave节点并不拥有锁,所以不存在之前的问题。

这个问题是比较严重的,因为不存在超时机制,拥有锁的节点断网或者断电,所以不会因为超时就释放锁。所以就会一直就卡着,并且一直实现不了切换节点。这就意味着一旦这种情况发生,客户的业务就会发生中断,这是无法接受的。并且我们也发现了如果使用原来将lock file放在cephfs目录的方式,断网或者断电主节点并不会发生这种情况,后来大概看了下源码大概是因为cephfs自己的机制会强制释放共享目录中文件的锁。

具体报错如下:

[root@tony ~]# ctdb status
Warning: All nodes are banned.

解决方案

我们的解决方案没有尝试着修改ctdb的源码,而是通过定时监控ctdb的状态。如果是主节点上面的ctdb,并且如果是rados方式的话,每3分钟查看一下ctdb status的状态,如果有连续两次的状态都是All Banned的话,我们就认为目前主节点发生了不释放锁的问题,我们就主动地删除lock object。部分代码如下:

#! /bin/bash                                                                                                                                 

function check_if_master() {
    MASTER_PNN=$(ctdb recmaster)
    CURRENT_PNN=$(ctdb pnn)
    if [ $MASTER_PNN -eq $CURRENT_PNN ]; then
        echo true
    else
        echo false
    fi  
}

function get_lock_name() {
    LOCK_INFO=$(grep rados $CTDB_CONFIG_FILE | awk '{print $5}')
    LOCK_NAME=${LOCK_INFO:0:-1}
    echo $LOCK_NAME
}

function monitor_lock() {
    STATUS_FILE=/etc/ctdb/status.txt
    CTDB_STATUS=$(ctdb status 2>&1)
    ALL_BANNED="Warning: All nodes are banned."

    if [ ! -f "$STATUS_FILE" ]; then
        echo "$CTDB_STATUS" > $STATUS_FILE
    else
        if [ "$CTDB_STATUS" = "$ALL_BANNED" ]; then
            LAST_CTDB_STATUS=$(cat $STATUS_FILE)
            if [ "$LAST_CTDB_STATUS" = "$ALL_BANNED" ]; then
                LOCKNAME=$(get_lock_name)
                echo $(date)" Ctdb all nodes banned: Second time" >> /var/log/monitor_ctdb.log
                echo $(date)" Remove ctdb rados lock: "$LOCKNAME >> /var/log/monitor_ctdb.log
                rados -p rbd rm $LOCKNAME 
                echo -n "" > $STATUS_FILE
            else
                echo $(date)" Ctdb all nodes banned: First time" >> /var/log/monitor_ctdb.log
                echo "$ALL_BANNED" > $STATUS_FILE
            fi
        else
            echo -n "" > $STATUS_FILE
        fi
    fi
}                                                                                                                                            

CTDB_CONFIG_FILE=/etc/sysconfig/ctdb
if $(grep rados $CTDB_CONFIG_FILE -q); then
    if $(check_if_master); then
        monitor_lock
    fi
fi

完整代码地址:https://github.com/tony-yin/C...

总结

也许我的这种做法不是最优方案,希望遇到同样问题的同学可以一起讨论,拥有更好解决方案的可以一起分享。


Tony_Zby
7.1k 声望154 粉丝

世界太大,没事瞄一瞄


引用和评论

0 条评论