解读TiKV 状态变化

Tiit 707 2024-03-25

背景说明

1、store 状态是什么?

  • 首先,这里说的状态,是 store 的状态。即,这里不谈 region 的状态。

  • 其次,这里的 store,可以简单类比为 TiKV 节点。

  • 最后,这个状态是指整个集群中的store 状态,存储在 PD(ETCD)中的状态(可能跟 store 真实状态有偏差、不一致)。

分布式集群节点状态,是通过心跳来判断的。心跳依赖网络,所以网络异常导致无法准确判断节点状态。但是,心跳可以展示“正常”状态。

同样的,我们 TiKV 集群的 TiKV(Store)节点状态也是通过心跳判断,存储在 PD(ETCD),有 PD 负责维护。而状态展示也是 PD(ETCD) 中的数据 —— 注意,并不是直接去取节点的实际状态。

分布式集群、状态等是个很大的话题,这里简单说明下,方便后续内容理解

2、工具使用

既然研究 Store 状态,必然需要经常查看,即需要查询 PD(ETCD) 存储的数据。我们这里有两个工具可以使用

2.1、etcdctl

这个是 etcd 本身直接提供的查询工具。我们这里需要用的命令如下:

ETCDCTL_API=3 ./etcdctl  --endpoints $(ip:port) get --prefix=true /pd/
  • ETCDCTL_API: 指定 etcd 的 api 版本。一般用 3(还有就是 2)

  • etcdctl:这个是 etcd 的工具,可以通过 tiup 安装:tiup ctl:$(version) etcd get

    • 版本不重要,因为 etcd 一般不会经常变

  • endpoints:访问的 api 接口的地址。一般就是 pd 的访问地址(比如 dashboard)

  • get:表示要做的事情。我们这里的测试,get 就够了。

  • “/pd/”:表示要取的数据的“目录”

    • Etcd 一般以类似目录格式存放 key。

    • 比如 “/” 下可以有多组key,下一层可以是 pd 可以是 cluster。

    • 说不清楚,试试就明白了。

  • prefix:表示是否是前缀。

    • 另外,如果设置为 true,是递归访问的。比如这里的 "/pd/",那么 pd 下有还有 目录 x,那么就会继续遍历 目录 x

    • 即 如果这个设置为 false,那么表示完整的 key 取查询。

    • 如果设置为 true,那么表示前缀。比如这里的 “/pd/ ”,表示取 “/pd/*”,或者说取 pd 目录下的索引 key

2.2、pd-ctl

这个本质也是访问 etcd 中存储的数据。但是,稍微做了一层封装:从etcd 中取出来的数据,经过处理、组装之后,再返回给客户展示。

我们这里主要查看 store 相关数据。所以,命令主要如下:

tiup ctl:v6.5.3 pd -u 10.2.8.4:32379 store

store 后面可以带的字命令:[delete | cancel-delete | label | weight | remove-tombstone | limit ] <store_id> [--jq="<query string>"]

这里是 官方文档参考

2.3、直接通过 pd 的 api 查询

这个可以到 dashboard 上查看 “高级调试 -> 内部调试数据” 查看具体的 API。这里,store 相关的 api 如下:

http://{ip:port}/pd/api/v1/store/{storeid}http://{ip:port}/pd/api/v1/stores

理论说明

关于store 状态相关,可以参考这里 官方文档。这里有部分说明。

各种状态

store 状态有如下 5 种状态。这是从官方文档摘录。

  • Up:表示当前的 TiKV Store 处于提供服务的状态。

  • Disconnect:当 PD 和 TiKV Store 的心跳信息丢失超过 20 秒后,该 Store 的状态会变为 Disconnect 状态。

  • Down:当 PD 和 TiKV Store 的心跳信息丢失超过 30 分钟后,该 Store 的状态会变为 Down 状态,

  • Offline:当对某个 TiKV Store 通过 PD Control 进行手动下线操作,该 Store 会变为 Offline 状态。

    • 这个是 PD 发现 store 是 offline,就会触发调度搬迁 region。

    • pd-ctl store delete

    • 该状态只是 Store 下线的中间状态,处于该状态的 Store 会将其上的所有 Region 搬离至其它满足搬迁条件的 Up 状态 Store。

  • Tombstone:当该 Store 的 leader_countregion_count 为 0 后,该 Store 变为 Tombstone 状态。

    • 可以使用 remove-tombstone 接口安全地清理该状态的 TiKV。

  • “搬迁 region” 到底是做啥事情、动作?是先 add peer,然后再 remove peer ?一个 region,怎么才算搬迁成功?

  • 如果部分 region 无法完成搬迁,会一直是 offline 状态。那么,应该怎么处理?

综述:

我个人理解,状态可以分为两类:

  • 间接状态:需要通过心跳来判定、转换的状态。

    • 包括 DisconnectedDown

  • 直接状态:记录存储到 PD(ETCD) 中的。

    • 在正常情况下(即没有丢失状态),那么直接查询到直接展示的状态。包括 UP/Offline/Tombstone

各种状态切换

下图是官方文档上的。

下图是获取 store 状态的时候的源码截图(点这里查看源码)。大约情况是:

  • 获取原始数据状态

  • 如果状态是 UP,根据 最后一次心跳做判断

根据状态转换和源码截图,可以得到如下信息:

  • 如果离最后一次心跳超过20s(不到30分钟),那么就是 Disconnected

  • 如果离最后一次心跳超过30分钟,就是 Down

    • 即,如果 stop 了 TiKV 节点,那么该 TiKV 在 30分钟以内也是 Disconnected

    • 并且,如果 stop 之后 20s 以内查看 TiKV 状态,应该是 Up 状态。

  • 如果用户执行了 store delete,那么就是 Offline

    • 即,表示要把该节点从 集群中剔除。

    • 但是,还有数据要搬迁(可以类比为“离职员工交接”)。

    • 所以,该状态是中间状态 —— 是要把事情处理完了(搬迁完了),才能走。

  • 如果 Offline 节点的数据搬迁完了,那么就可以转成 Tombstone。

    • 搬迁完,即 leader 和 region count 都是 0.

    • 数据搬迁完了(交接完了),那么可以退出集群了——即,该集群不会再跟该节点联系了。

    • 可以人工去删除数据。

  • 那么,正常情况下,就是 UP 状态咯。

    • 除了上述异常情况,那么就是正常情况咯。

各种状态会带来什么

如下截图,据说后续会改成 NodeState,很好的反应出要做啥事情。

  • UP:这种状态下,可以对外提供服务。不会做其它额外的事情。

  • Disconnected:好像不会做啥事情(?)

    • 注意,这会导致 region 的 leader 重新选举,导致业务性能下降一波。

  • Down:这种情况下,会对该 store 上的 region 进行 补副本

    • 注意,是max-store-down-time 来控制的,在变成 down ,之后会任务改 store 不可用,会对 该store 上的 region 补副本。

  • Offline:这种情况下,需要对该 store 上的 region 进行 迁移

    • 迁移的意思是 补副本 + 删除 该 store 上的 副本 —— 这里的“删除”,可以仅仅是 PD 中的信息删除。

    • 看 NodeState 可以知道,它是正在删除 region 过程中,所以是 Removing。。。

  • TombStone:这种情况下,与集群没有关系了,所以该节点做啥都无所谓咯。

测试说明

初始化状态

刚刚部署好的集群,仅仅启动 PD ,集群中 store 是啥状态?

1、通过 etcdctl 查看,可以知道没有 store 相关数据。

2、通过 pd-ctl 查看,是报 500 的错误 —— 应该是因为没有数据导致的。

3、通过 tiup 查看集群状态,可以看到 TiKV 节点都是 Down 状态

启动之后状态

基于上面情况,启动整个集群之后,状态如下

stop之后状态(stop -R tikv)

1、立马查看:理论上说是 UP 状态

2、20秒之后查看:理论上说是 Disconnected(持续30分钟)

3、30分钟之后查看:理论上说是 Down

4、删除 Store(scale-in)

实际案例

案例1

集群说明:客户测试环境,k8s集群,3tikv 单副本系统。
问题说明:其中一个 tikv-3 由于某种原因变成了 Offline 状态,并且一直无法正常启动。查看状态可以知道,tikv 上还有9个region(leader)。
  • 当前状态

当前 tikv 是 offline,并且无法正常启动。offline 表示已经不在集群中了。而 offline 会导致 region、leader 迁移到其它 tikv 节点。

  • 当前问题

由于是单副本,即 tikv-3 的region 只有 tikv-3 有,其它 tikv 是没有的。由于 tikv-3无法正常启动,所以无法把 region 迁移出去,所以无法完成 offline,导致一直卡在这里、恢复正常。

  • 解决问题

    • 查看 tikv-3 所有region,然后执行命令"tikv-ctl --db /path/to/tikv-data/db recreate-region --pd <endpoint> -r <region_id>"

    • 可惜,执行这个操作之后,是没有效果的(报错)

    • 可以考虑想办法把 tikv-3 正常启动 —— 这个比较难,如果可以的话,也不会让其下线了。

    • 只能丢失数据,放弃 tikv-3 上的 region。在其它 tikv 上补上这个 9个 region(空的)

    • 只能重建集群了(还好是测试环境)

案例2

背景情况:

  • 最后心跳时间是 14:30左右

  • 当前状态是 Down

  • region/leader count是0

  • 查询时间大约在 21:30 +5:30左右

集群是 k8s 集群,在没有人为操作的情况下,在 23:30 +5:30 左右变成了 tombstone

理论上来说,需要执行 “delete”使其状态变成 offline,然后 region/leader count为0 则可以切换为 tombstone。

但是,在至少2个小时 Down中都没有变化,突然就变成了 tombstone。

  • 不了解 k8s 的自动切换的原理 —— 即原来的 store 4 由于启动不了,所以替换为了 store xxxx,但是仍然是 tikv-1实例。

  • 另外,怀疑是客户手动 delete 了 pod ?

案例3

由于 compaction 导致某个磁盘空间突然飞涨,导致无法启动、运行。

Workaround :磁盘扩容。

案例4

情况汇总: 初始情况:

  • 客户1pd + 3tidb + 3tikv(tikv0<store1>/tikv1/tikv2);

第一阶段

  • 由于pv 扩容, rollout 导致多了个 pod 运行 tikv0(store-n);现在 store1 和 store-n 同时存在;

  • store-1 是有问题,本身启动不了,Down 了;

  • 客户执行了 pd-ctl delete store-0 ,但是删除失败

  • store-n 和 store-1 都用tikv-0 的地址,所以导致 store-n 注册pd 失败启动不了;

第二阶段:

  • 由于 autofailover,导致自动扩容了 tikv-3;

  • 但是由于资源不够导致 挂起;

  • 客户有发现之后,就手动吧 tikv-3 scale-in 了;导致现在的 tikv-3 也是 down 状态

要恢复集群,就是不不正常的 store 剔除让正常的 store 启动起来

  • 不正常的 store-1,是因为还有 region 残留,可以直接通过 remove peer 来达到清零的效果(有三副本,所以删除了系统自动会补副本)。

  • 正常的 store-n 启动起来。原来无法启动,是因为 store-1 占用了 tikv0 的实例(address),导致无法启动。那么,store-1 正常剔除之后,自然就启动正常了。

MoreAndMore:k8s(operators)

一开始打算的时候,没想研究这个:因为太复杂,完全不懂。

但是,在分析案例的时候,发现这几个问题或多或少都跟 k8s 相关:如果是 OP 环境,很容易就知道怎么玩了,但是 k8s 环境就完全不知道。所以,k8s 就自然而然的要研究下。

Restart pod

在 OP 环境,如果 tidb 异常重启(比如 OOM),那么就是进程变化而已。那么,在 k8s 环境,如果 tidb OOM ,会发生什么呢?

本质上来说,Pod 也是一个进程。所以,发生重启的话,Pod变化了(进程 变了),但是其它都没变(磁盘、配置等),所以 tikv(store) 节点是都没有变化的。

Autofailover

Autofailover 本质上来说,就是 scale-out + scale-in ,即

  • 异常 Pod 缩容

  • 扩容一个新的正常 Pod 来代替

MoreAndMore:offline 迁移到底做了啥

Offline 状态下的迁移 region,主要做了如下事情:

  • 先 transfer leader 到非 offline 的节点

  • 然后 replica 一个 peer,

  • 最后 remove offline 的那个 peer

即,这个过程是跟 offline 的 tikv 无关的,不需要对 offline 的 tikv 做交互。

  • Transfer leader 是 raft 协议保证的

  • Replica 是从 leader 来做的——但是 leader 不在 offline 的 tikv

  • remove offline 的那个 peer,是删除 pd 中的记录就可以了

参考

Pd-ctl store

ETCDCTL_API=3 .tiup/components/ctl/v6.5.3/etcdctl  --endpoints http://10.2.8.4:32379 get --prefix=true /pd/


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:绕过 MVCC 影响的 TiDB Delete 数据的几种方式
下一篇:Java jdbc 驱动 maxPerformance 配置避坑的方法
相关文章