client-go使用txn模式访问tikv返回错误Key xxx is out of [region YYY]

【 TiKV 使用环境】生产环境
【 TiKV 版本】5.3.2

【复现路径】
偶现,无法复现

【遇到的问题:问题现象及影响】
使用client-go txn-client直接打开事务后执行get,直接返回错误,错误信息为:

tikv aborts txn: Error(Txn(Error(Mvcc(Error(Kv(Error(Other("[components/tikv_kv/src/raftstore_impls.rs:35]: \"[components/raftstore/src/store/region_snapshot.rs:216]: Key XXXX is out of [region YYY] 

【资源配置】

【附件:截图/日志/监控】
根据错误提示的代码位置https://github.com/tikv/tikv/blob/8e6e348505e7f1f7b5e023c00b30f90e8d1b4084/components/raftstore/src/store/region_snapshot.rs#L210

 check_key_in_range(
            key,
            self.region.get_id(),
            self.region.get_start_key(),
            self.region.get_end_key(),
        )
        .map_err(|e| EngineError::Other(box_err!(e)))?;

这里把KeyOutOfRegion这个错误映射成了Other error.

请问:

  1. 这个错误是在拿到regionsnapshot后检查keyrange时抛出,请问这个问题在raftstore中是否符合预期?
    代码中之前位置其实已经检查过keyrange并通过了,而最后一步使用snapshot读取时再次检查keyrange却失败了,这个问题是符合预期的吗? 我想知道如果符合预期,这个错误是由什么原因导致? 是RegionSplit吗?如果是,这个错误那么不应该转成Other类型,按我的理解理应转换成RegionErr? 让client-go进行重试?

Hello,txn 模式访问 tikv 时,region 相关处理如下:

  1. txn 向 PD 根据 key 获取 region 的对应信息
  2. txn 向对应 TiKV 带着 region 元信息(如版本信息)发送请求
  3. TiKV 收到请求后,检查 region 信息是否对上,这个过程主要是用来保证 tikv 中的对应 region 没有发生过变更,如 split, merge.
  4. TiKV 开始处理请求,在拿到 snapshot 后处理咱们这个 key 时,发现 key 已经不在这个 region 了

确实如你所说,在 3 以后,这个 region 可能是发生过变更,比如 split, 就会导致咱们这个问题,这可以通过在 tikv 中搜索这个 region 相关的日志观察到。
为什么不是 Region Error 而是 Other Error 呢?我猜原因应该是这样:

  • 首先 region error 一般在第 3 步处理的时候就会暴露出来,而咱们这一步处理已经在第 4 步也就是很核心了,之前没有考虑过在这一块处理 region error。
    1. 也是最关键的原因,这边直接返回 region error 也不行,因为事实确实是 key 不在这个 region 里面,设计初衷应该是怕真的这块逻辑出现了问题,所以直接丢这个错误是为了引起重视,并进一步排查是否是 region 信息发生了变更导致,而不是内部逻辑出现了问题。
    1. region split 操作本身是一瞬间的事情,所以踩到这一块的逻辑概率还是相对将大的,但又不是特别大,因为 get snapshot 这个操作也是瞬间的,所以如你所说,你这个场景就很难复现。所以我猜测这一块逻辑之前应该也是没有的,后来有同学踩到了才加入,然后又考虑到第二点原因,就是系统可能真的出现了问题,所以不报 Region Error 对用户来说可能是最稳妥的方式。
1 个赞