[关闭]
@tony-yin 2018-05-09T09:30:37.000000Z 字数 2450 阅读 1699

Ctdb Rados方式导致All Banned的问题

Ceph Ctdb


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自己的机制会强制释放共享目录中文件的锁。

具体报错如下:

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

解决方案

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

  1. #! /bin/bash
  2. function check_if_master() {
  3. MASTER_PNN=$(ctdb recmaster)
  4. CURRENT_PNN=$(ctdb pnn)
  5. if [ $MASTER_PNN -eq $CURRENT_PNN ]; then
  6. echo true
  7. else
  8. echo false
  9. fi
  10. }
  11. function get_lock_name() {
  12. LOCK_INFO=$(grep rados $CTDB_CONFIG_FILE | awk '{print $5}')
  13. LOCK_NAME=${LOCK_INFO:0:-1}
  14. echo $LOCK_NAME
  15. }
  16. function monitor_lock() {
  17. STATUS_FILE=/etc/ctdb/status.txt
  18. CTDB_STATUS=$(ctdb status 2>&1)
  19. ALL_BANNED="Warning: All nodes are banned."
  20. if [ ! -f "$STATUS_FILE" ]; then
  21. echo "$CTDB_STATUS" > $STATUS_FILE
  22. else
  23. if [ "$CTDB_STATUS" = "$ALL_BANNED" ]; then
  24. LAST_CTDB_STATUS=$(cat $STATUS_FILE)
  25. if [ "$LAST_CTDB_STATUS" = "$ALL_BANNED" ]; then
  26. LOCKNAME=$(get_lock_name)
  27. echo $(date)" Ctdb all nodes banned: Second time" >> /var/log/monitor_ctdb.log
  28. echo $(date)" Remove ctdb rados lock: "$LOCKNAME >> /var/log/monitor_ctdb.log
  29. rados -p rbd rm $LOCKNAME
  30. echo -n "" > $STATUS_FILE
  31. else
  32. echo $(date)" Ctdb all nodes banned: First time" >> /var/log/monitor_ctdb.log
  33. echo "$ALL_BANNED" > $STATUS_FILE
  34. fi
  35. else
  36. echo -n "" > $STATUS_FILE
  37. fi
  38. fi
  39. }
  40. CTDB_CONFIG_FILE=/etc/sysconfig/ctdb
  41. if $(grep rados $CTDB_CONFIG_FILE -q); then
  42. if $(check_if_master); then
  43. monitor_lock
  44. fi
  45. fi

完整代码地址:https://github.com/tony-yin/Ctdb-Rados-Monitor

总结

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

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注