导读
本文深入介绍了 TiKV 中的垃圾回收(GC)机制,包括其工作原理、处理流程以及如何通过 GC safepoint 清理旧版本数据。文章比较了传统 GC 和基于 compaction filter 的 GC 两种方式,指出了后者在优化性能方面的优势,讨论了监控 GC 进度、处理 GC 压力等常见问题。此外,文章还提供了针对物理空间回收问题的解决策略和操作建议,旨在帮助用户更好地理解和管理 TiKV 的 GC 过程,确保数据库的稳定与高效运作。
为什么需要 GC?TiDB MVCC 版本堆积相关原理及排查手段 TiDB 集群 GC 的定义、实现原理及常见问题:TiDB 组件 GC 原理及常见问题

1:00 新写入或更新,数据存在 default cf 2:00 更新,数据存在 default cf 3:00 删除 4:00 新写入,数据存在 default cf





GC worker GC manager


GC_keys,简言之,就是对于具体的 key, 扫描并删除符合条件的旧版本。详细过程我们已经在第一章描述过。 GC(range):就是对于一块连续的范围的数据调用 GC_keys, 对指定范围内中的每个 key 单独进行 GC 处理。 unsafe-destroy-range:对于连续范围的数据,直接物理清理。对应于上一篇文章提到的 truncate/drop table/partion.
线程数:GC worker 目前具体只有一个线程,当前代码中硬编码 ( https://github.com/tikv/tikv/blob/v6.3.0/src/server/gc_worker/gc_worker.rs#L1201 ),我们没有提供外部可配的配置。 GC_MAX_PENDING_TASKS ( https://github.com/tikv/tikv/blob/v6.3.0/src/server/gc_worker/gc_worker.rs#L1201 )GC worker 队列中最多可以接收的任务数,为 4096。
相关监控


同步 GC safepoint 到本地 全局指导实施具体的 GC 工作

传统的 GC,即以 region 为单位调用 GC(range) 进行 GC。 借用 compaction filter 进行 GC(5.0 以后默认方式):这里不做真正的 GC,而是等到 rocksdb 的 compaction 时借助 compaction filter 的方式进行旧版本的回收。

5.1.1 GC a round


GC 开始时,gc-safepoint 为 10 , 我们用 safepoint =10 GC 了 region 1 - region2 在 GC 完 region2 后,我们发现 GC safepoint 变成了 20 , 从这以后,我们拿着 20 继续 GC 剩下的 region. 所有的 region 的 gc 完毕后,我们继续从第一个 region 开始用 gc safepoint=20 进行 GC,直到所有的 region 都用 gc safepoint=20 GC 完毕。
5.1.2 常见问题
GC worker 成为瓶颈。因为所有的回收都需要打到 GC worker 上,而 GC worker 只有一个线程,所以表现为它的 CPU 跑满,具体可以查看监控:tikv-details->thread CPU-> GC worker
raftstore 读写压力变大:GC worker 在执行具体的 gc_keys 任务时,需要将所有的数据版本扫出来,再将符合条件的删除。
因为短期内 rocksdb 的写入量变大,导致 L0 文件快速堆积而触发 rocksdb 的 compaction
因为对 rocksdb 发起 DELETE, 在 rocksdb 内部最终也是转化为对当前 Key 写入一个新版本,所以在这种情况下,物理空间使用量反而会变大。
需要等 rocksdb 的 compaction 工作完成后才会真正的回收物理空间,而 rocksdb compaction 本身也需要先占用一大波临时空间。
5.2.1 Why compaction in rocksdb

1.1 rocksdb 会将数据直接 append 到 LOG 文件,也就是持久化到本地。 1.2 写入到一个活跃的 memtable 里面,因为在内存里,这个过程是非常快的,而且 memtable 里面的数据是有序的。
对若干个 SST 文件进行归并排序。 只保留 rocksdb 视角的最新 MVCC 版本(GC)。 压缩下层到 level1~level6。

a 这个 TiKV 的 mvcc key, 在 write_cf 里面对应的 key 是有 commit_ts 后缀的。初始化状态下,假设我们要 compact 左边两个绿色文件的 SST 文件,这两个文件分别在 L2 和 L3,compact 过后会存到 L3 这一层。 a 在 L2 的这个 SST 文件中有 a_90 a 在 L3 的这个 SST 文件中有 a_85 , a_82 , a_80 当前 gc_safepoint 是 89, 根据我们第一章 gc_key 的处理规则我们知道,此时我们需要保留老的旧版本为 a_85,即 a_85 之前的数据都可以删除。 从右边我们看到,新的 SST 文件中,只有 a_85 和 a_90 两个版本了。其他的版本及对应 default-cf 里面的具体数据,在 compaction 过程中一起删除掉了。
省去了读 rocksdb 的过程。 删除(写入) rocksdb 的过程。


当前 key 为 gc_safepoint 89 之前最新的版本 当前 key 在 L6 这一层,且当前 key 只剩下这一个版本了。意味着没有比 85 更早的历史版本了(确保 gc_keys 时不会产生额外的写入)
新的 SST 文件中依旧会包含一个 write_type::DEL 的版本。 gc_keys 会向 rocksdb 写入一次 (DELETE,a_85),这是 write_cf 在 compaction filter 打开情况下,生成 tombstone 的唯一方式。
5.3 相关配置
对于 tso > gc safepoint 的,保留并跳过 对于 tso <= gc safepoint 的:根据类型确认是否保留最新一个版本,过滤旧版本

region-compact-check-interval: 一般情况下不需要调整 region-compact-check-step: 一般情况下不需要调整 region-compact-min-tombstones 触发 RocksDB compaction 需要的 tombstone 个数。默认值:10000 region-compact-tombstones-percent 触发 RocksDB compaction 需要的 tombstone 所占比例。默认值:30 region-compact-min-redundant-rows (从 v7.1.0 版本开始引入)触发 RocksDB compaction 需要的冗余的 MVCC 数据行所占比例。默认值:50000 region-compact-redundant-rows-percent (从 v7.1.0 版本开始引入)触发 RocksDB compaction 需要的冗余的 MVCC 数据行所占比例。
5.4 相关监控


如果是 GC safepoint 之前,且不是最新版本的(a-v1,a-v5,b-v5):
filtered: 被 compaction filter 直接过滤(物理删除,无任何新增写入)的旧版本数量,代表着 compaction-filter 真正有效回收的旧版本数据。这个指标如果没有值,意味着没有旧版本数据需要回收。 Orphan-version: write_cf 里面的旧版本直接删除后,需要清理 default-cf 里面的数据,在删除 default cf 数据过程中失败了,此时会通过 GcTask::OrphanVersions 方式来清理 default-cf 里面的数据。这个有数据的话,可能是需要删除的数据过多导致 rocksdb 忙不过来。
GC safepint 之前的最新版本(需要保留的最老版本 a-v10, b-v12 ):
rollback/lock: 写入类型是 Rollback/Lock, 这种情况下,会有一个 tombstone 写入到 rocksdb 里面。 mvcc_deletion_met: write_type=DELETE, 且是最底层的 SST 文件。 mvcc_deletion_handled: 通过 gc_keys() 方式回收的 writetype=DELETE 的数据 mvcc_deletion_wasted: 通过 gc_keys() 方式回收时,发现这个数据已经被清理掉了。 mvcc_deletion_wasted+mvcc_deletion_handled = the number of keys that (type = delete,in the bottmost level, only have 1 version)
region-compact-min-redundant-rows ( 从 v7.1.0 版本开始引入) 触发 RocksDB compaction 需要的冗余的 MVCC 数据行数。默认值:50000 region-compact-redundant-rows-percent ( 从 v7.1.0 版本开始引入) 触发 RocksDB compaction 需要的冗余的 MVCC 数据行所占比例。
select min(START_KEY) as START_KEY,max(END_KEY) as END_KEY from information_schema.tikv_region_status where db_name='' and table_name=''
复制
tiup ctl:v7.5.0 tikv --to-escaped start_key
tiup ctl:v7.5.0 tikv --to-escaped end_key
-- example: --
tiup ctl:v7.5.0 tikv --to-escaped "7480000000000000FFB75F728000000000FF45431D0000000000FA"
Starting component `ctl`: /home/tidb/.tiup/components/ctl/v7.5.0/ctl tikv --to-escaped 7480000000000000FFB75F728000000000FF45431D0000000000FA
t\200\000\000\000\000\000\000\377\267_r\200\000\000\000\000\377EC\035\000\000\000\000\000\372复制
----compact write cf----
tiup ctl:v7.5.0 tikv --host "127.0.0.1:20160" compact --bottommost force -c write --from "zt\200\000\000\000\000\000\000\377\267_r\200\000\000\000\000\377EC\035\000\000\000\000\000\372" --to "t\200\000\000\000\000\000\000\377\272\000\000\000\000\000\000\000\370"
Starting component `ctl`: /home/tidb/.tiup/components/ctl/v7.5.0/ctl tikv --host 127.0.0.1:20160 compact --bottommost force -c write --from zt\200\000\000\000\000\000\000\377\267_r\200\000\000\000\000\377EC\035\000\000\000\000\000\372 --to t\200\000\000\000\000\000\000\377\272\000\000\000\000\000\000\000\370
store:"127.0.0.1:20160" compact db:Kv cf:write range:[[122, 116, 128, 0, 0, 0, 0, 0, 0, 255, 183, 95, 114, 128, 0, 0, 0, 0, 255, 69, 67, 29, 0, 0, 0, 0, 0, 250], [116, 128, 0, 0, 0, 0, 0, 0, 255, 186, 0, 0, 0, 0, 0, 0, 0, 248]) success!
---以上无效果的话,尝试compact default cf---
tiup ctl:v7.1.1 tikv --host IP:port compact --bottomost force -c default --from 'zr\000\000\001\000\000\000\000\373' --to 'zt\200\000\000\000\000\000\000\377[\000\000\000\000\000\000\000\370'复制
注意:根据前面清理 writeType::DELETE 的步骤我们知道,在最新版本是 DELETE 时,这个版本会变成要删除的 key 的唯一版本,他需要 compact 到 rocksdb 的最底层才会被清理,所以一般的,我们至少需要通过两次手动 compact 才能将物理空间回收,也就是上面的命令需要执行至少两次。
select * from information_schema.tikv_region_status where db_name='' and table_name=''
复制
Tikv-ctl 查询当前 region 的 mvcc properties ( https://docs.pingcap.com/zh/tidb/stable/tikv-control#打印-region-的-properties-信息 ),如果发现 mvcc.num_deletes 和 write_cf.num_deletes 都比较小,说明这个 region 已经处理完毕,跳过继续处理下一个 region。
tikv-ctl --host tikv-host:20160. region-properties -r {region-id}
-- example--
tiup ctl:v7.5.0 tikv --host "127.0.0.1:20160" region-properties -r 20026
Starting component `ctl`: /home/tidb/.tiup/components/ctl/v7.5.0/ctl tikv --host 127.0.0.1:20160 region-properties -r 20026
mvcc.min_ts: 440762314407804933
mvcc.max_ts: 447448067356491781
mvcc.num_rows: 2387047
mvcc.num_puts: 2454144
mvcc.num_deletes: 9688
mvcc.num_versions: 2464879
mvcc.max_row_versions: 952
writecf.num_entries: 2464879
writecf.num_deletes: 0
writecf.num_files: 3
writecf.sst_files: 053145.sst, 061055.sst, 057591.sst
defaultcf.num_entries: 154154
defaultcf.num_files: 1
defaultcf.sst_files: 058164.sst
region.start_key: 7480000000000000ff545f720380000000ff0000000403800000ff0000000004038000ff0000000006a80000fd
region.end_key: 7480000000000000ff545f720380000000ff0000000703800000ff0000000002038000ff0000000002300000fd
region.middle_key_by_approximate_size: 7480000000000000ff545f720380000000ff0000000503800000ff0000000009038000ff0000000005220000fdf9ca5f5c3067ffc1复制
Tikv-ctl 手动 compact 当前 region ,执行完毕后,继续循环执行上一步检查 region 的 properties 是否发生变化。
tiup ctl:v7.5.0 tikv --pd IP:port compact --bottommost force -c write --region {region-id}
tiup ctl:v7.5.0 tikv --pd IP:port compact --bottommost force -c default --region {region-id}
--example--
tiup ctl:v7.5.0 tikv --host "127.0.0.1:20160" compact --bottommost force -c write -r 20026
Starting component `ctl`: /home/tidb/.tiup/components/ctl/v7.5.0/ctl tikv --host 127.0.0.1:20160 compact --bottommost force -c write -r 20026
store:"127.0.0.1:20160" compact_region db:Kv cf:write range:[[122, 116, 128, 0, 0, 0, 0, 0, 0, 255, 84, 95, 114, 3, 128, 0, 0, 0, 255, 0, 0, 0, 4, 3, 128, 0, 0, 255, 0, 0, 0, 0, 4, 3, 128, 0, 255, 0, 0, 0, 0, 6, 168, 0, 0, 253], [122, 116, 128, 0, 0, 0, 0, 0, 0, 255, 84, 95, 114, 3, 128, 0, 0, 0, 255, 0, 0, 0, 7, 3, 128, 0, 0, 255, 0, 0, 0, 0, 2, 3, 128, 0, 255, 0, 0, 0, 0, 2, 48, 0, 0, 253]) success!复制
TiDB MVCC 版本堆积相关原理及排查手段
TiDB 组件 GC 原理及常见问题
💡 点击文末【阅读原文】,立即下载试用 TiDB!
