前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >升级集群导致ETCD数据不一致/毁坏案例分析

升级集群导致ETCD数据不一致/毁坏案例分析

原创
作者头像
tangcong
修改2020-03-16 15:51:56
2.8K1
修改2020-03-16 15:51:56
举报

升级集群导致ETCD数据不一致/毁坏案例分析

背景

近期我们在测试环境升级ETCD集群(3.2升级到3.3)的时候,遇到了一些奇怪现象。当集群升级完后,收到了测试同学反馈集群出现各种BUG了:

  • 变更镜像不生效的
  • pod不调度的
  • 服务RS变更Service异常的
  • 扩容不生效的
  • 其他各种诡异的现象等

我们最开始怀疑K8S的controller-manager/scheduler/apiserver出bug了,一番调查后发现又是etcd出现严重问题了(恰好测试环境我们屏蔽了这个集群的告警,导致我们事后才知道),我们通过监控视图和日志观察到有如下异常:

  • 部分节点db size异常增长,各个节点大小不一样
  • 各节点revision不一致
  • 部分etcd节点compact异常,无compact相关日志
  • 各节点key数量不一致

我们尝试看日志是否为什么部分Key在有些节点有,有些节点无, 但是因为etcd的日志实在少的可怜,缺少关键的错误日志,我们一无所获,陷入迷茫和困惑中. 同时在社区上也未能搜索到有效信息,同时我们通过比对db的鉴权版本号也排除了不是我们上一次发现的严重的BUG(https://github.com/etcd-io/etcd/issues/11651,https://github.com/etcd-io/etcd/pull/11652),于是只能修改etcd代码并尝试复现了。

复现

首先我们采用尝试人工简单升级ETCD集群试试是否能复现,然并卵,未能复现,其实正如我们所预期一样,如果那么能复现社区早发现早解决了,不可能我们现在才遇到。

如何才能成功复现一个严重的BUG? 首先我们有如下推测:

  • 跟版本升级可能有一定关联
  • 跟重启可能有一定关联(上一个严重BUG是重启触发)
  • 跟鉴权的版本号auth revision没任何关系(已通过比对各个节点db源数据排除)
  • 观测现网监控异常时间段有哪些接口调用
  • 可能需要一定的QPS触发

我们采取以下方法及技术手段对推测进行了分析和落地:

  • 人工无法简单复现,我们采用混沌工程(chaos monkey)的方法来寻求自动化压测复现
  • monkey压测版本是从3.2升级到3.3,每次升级一个节点,不停写入数据,然后重启,压测较长时间后再继续升级其他节点,因为升级后不可逆,不能回退
  • 比对3.2和3.3版本发现两个大的改动,一个是lessor,一个是txn, 因此我们分别对3.2和3.3版本,在所有lessor和txn操作的关键路径增加debug日志和异常情况下增加详细的错误日志
  • chaos monkey增加kill和restart各个节点的机制,通过简单锁机制,保证每次只杀掉1个节点,确保当前集群永远可用
  • chaos monkey去除鉴权相关操作
  • 根据现网监控,chaos monkey 增加txn/range/lessor/txn的各接口调用,尤其是lessor/txn QPS适当加大,lesase ttl过期时间随机生成
  • 根据测试环境的监控显示我们的QPS当时在3000左右,连接数10000左右,因此我们chaos monkey也增加对应的QPS和client来满足条件
  • 调度部分测试集群到压测集群,以最逼真模拟现网, 毕竟这是在k8s集群下使用下产生的

当我们把chaos monkey程序按照以上分析结论优化完后,在两套集群上同时部署,令人振奋的是,没过多久,我们就收到了一致性差异告警,我们又成功复现了。

原理分析

收到告警后,我们立刻采取了以下措施:

  • 停止chaos moneky
  • 停掉集群,避免产生大量日志干扰我们排查
  • 观测数据不一致详情,发现3.2的两个节点数据一致,与3.3数据不一致
  • 脚本快速分析出3.2与3.3差异的KEY
  • 在各个节点中查询这个KEY的日志
  • 经过搜寻,我们得到了以下关键日志

node A(3.2+,Leader)

```

637802:Mar 11 21:52:23 localhost etcd[28065]: LeaseRevoke:{LeaseRevoke 24 0 ID:2229124347589447546 } {entry-index 17 25 <nil>} {entry-term 17 2 <nil>} {rev 11 2014102077 <nil>}

637803:Mar 11 21:52:23 localhost etcd[28065]: revoke lessor,lessor id:2229124347589447546

637804:Mar 11 21:52:23 localhost etcd[28065]: revoke lessor,lessor id:2229124347589447546,key:/masterleases/A

637805:Mar 11 21:52:23 localhost etcd[28065]: apply request:header:<ID:16363671783383239993 > lease_revoke:<ID:2229124347589447546 > ,response:&{0xc000d545e0 <nil> <nil>}

```

node B(3.2+,Follower)

```

637802:Mar 11 21:52:23 localhost etcd[28065]: LeaseRevoke:{LeaseRevoke 24 0 ID:2229124347589447546 } {entry-index 17 25 <nil>} {entry-term 17 2 <nil>} {rev 11 2014102077 <nil>}

637803:Mar 11 21:52:23 localhost etcd[28065]: revoke lessor,lessor id:2229124347589447546

637804:Mar 11 21:52:23 localhost etcd[28065]: revoke lessor,lessor id:2229124347589447546,key:/masterleases/A

637805:Mar 11 21:52:23 localhost etcd[28065]: apply request:header:<ID:16363671783383239993 > lease_revoke:<ID:2229124347589447546 > ,response:&{0xc000d545e0 <nil> <nil>}

```

node C(3.3+,Follower)

```

1392010:Mar 11 21:56:42 localhost etcd[26312]: applyEntryNormal:check index, entry-index: 25, consistent-index: 24

1392011:Mar 11 21:56:42 localhost etcd[26312]: shouldApplyV3, entry-index: 25, consistent-index: 25

1392012:Mar 11 21:56:42 localhost etcd[26312]: LeaseRevoke: ID:2229124347589447546 , entry-index: 25, entry-term: 2, rev: 2014102070

1392014:Mar 11 21:56:42 localhost etcd[26312]: request "header:<ID:16363671783383239993 > lease_revoke:<id:1eef70c8a23e4f7a>" with result "error:auth: user name is empty" took too long (1.464µs) to execute

```

从日志中我们可以看到节点C(3.3+)执行lease_revoke命令时失败了,错误是用户名为空。 此错误将继续放大,从而导致mvcc版本差异很大,进而可能无法执行txn命令,并且数据损坏。

BUG如何产生的

为什么3.3节点执行会报user name is empty呢? 我突然想起之前比对3.2和3.3差异的时候,偶然看到了一处与其相关改动点,当时没意识到有什么问题,我立刻再去对比差异,发现正是这个PR(https://github.com/etcd-io/etcd/pull/8031)在3.3的变动,导致3.3节点执行失败,在3.3以前lease revoke不需要鉴权,但是3.3这个PR增加了鉴权,导致lease过期的时候,3.3节点无法删除lease对应的key,进而出现数据不一致,版本差异,数据毁坏等一系列BUG。

详情参考issue: https://github.com/etcd-io/etcd/issues/11689

修复方案

我们讨论的修复方案有两种:

  • 3.3以上版本,在当集群中出现不一致的版本时,兼容这种低版本的没鉴权,跳过lease revoke的鉴权流程
  • 3.2版本确保lease revoke的时候auth info 不为空,用户想升级集群的时候先升级到3.2包含这个修复方案的最新版本,再继续升级到3.3版本,我们给社区提的PR也是这个方案
  • 详情参考PR: https://github.com/etcd-io/etcd/pull/11691

最佳实践

在成功发现和修复两个严重数据不一致BUG后,我们推荐以下ETCD最佳实践方案:

  • ETCD定期备份数据,推荐是至少是10分钟级别,可以使用开源的etcd-operator中的backup-operator
  • 任何重要变更前一定备份数据
  • 为ETCD添加自动化的一致性巡检告警,如revision差异监控、key数量差异监控
  • 多关注社区issue/pr,及时升级到最新稳定版本
  • 使用etcd 最新版本的3.4.4用户,推荐开启data corruption检测功能,当集群出现不一致时,拒绝集群写入,可读
  • 确保集群中各节点ETCD版本一致

最后关于ETCD数据不一致定位老大难的问题,我们也提交了PR,https://github.com/etcd-io/etcd/pull/11670,相信以后定位不一致问题会方便很多,目前已经合入master。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 升级集群导致ETCD数据不一致/毁坏案例分析
    • 背景
      • 复现
        • 原理分析
          • BUG如何产生的
            • 修复方案
              • 最佳实践
              相关产品与服务
              混沌演练平台
              混沌演练平台(Chaotic Fault Generator)提供高效便捷、安全可靠的故障演习服务,除可视化故障注入服务外,还提供行业经验模板,监控护栏等核心功能,致力于帮助用户及时发现业务容灾隐患、验证高可用预案的有效性,从而提高系统的可用性和韧性。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档