0
2
0
0
专栏/.../

TiDB大规模删除实践

 dbapower  发表于  2021-07-05

TiDB集群大规模删除实践

一、 背景

集群在写入了一定的时间后,是存在一些历史可以删除的数据的,为了对集群的空间释放,我和业务一并讨论和计划了待删除的表,但是在drop数据时发现集群QPS有抖动,duration异常升高,经过排查发现触发了compaction的流控,导致业务的写入产生了积压。

集群配置

集群版本:v3.0.5
集群配置:普通SSD磁盘,128G内存,40 核cpu
tidb21 TiDB/PD/pump/prometheus/grafana/CCS
tidb22 TiDB/PD/pump
tidb23 TiDB/PD/pump
tidb01 TiKV
tidb02 TiKV
tidb03 TiKV
tidb04 TiKV
tidb05 TiKV
tidb06 TiKV
tidb07 TiKV
tidb08 TiKV
tidb09 TiKV
tidb10 TiKV
tidb11 TiKV
tidb12 TiKV
tidb13 TiKV
tidb14 TiKV
tidb15 TiKV
tidb16 TiKV
tidb17 TiKV
tidb18 TiKV
tidb19 TiKV
tidb20 TiKV
wtidb29 TiKV
wtidb30 TiKV

二、现象

我们首先收到了如下报警:

image


乍一看引起的报警问题还是蛮多的,但其实看本质和操作时间点,是在集群drop大批量数据后(本案例是drop近30T数据),且到经过GC life time后触发的,因此基本定位到主要是因为drop大批量表,GC回收时导致的
看到pending_task,write_stall等报警,第一反应就是GC回收空间时占用IO导致了集群资源争用。
业务也发现积压和OPS抖动,duration升高,如下图

image

三、排查步骤

根据以往经验,pending_task和stall我们先看一下集群的繁忙状态:

image


果然,我们得到了预期的结果,集群在drop操作后爆出了server is busy,官网关于server is busy有如下相关内容:

通过查看监控:Grafana -> TiKV -> errors 确认具体 busy 原因。在ERROR页面我们看到了server is busy 有峰值,这是 TiKV 自身的流控机制,TiKV 通过这种方式告知 tidb/ti-client 当前 TiKV 的压力过大,稍后再尝试,本案例是因为大批量drop导致的busy。

同时,我们发现告警中包含了write_stall,关于write stall,一个 TiKV 包含两个 RocksDB 实例,一个用于存储 Raft 日志,位于 data/raft。另一个用于存储真正的数据,位于 data/db。通过 grep "Stalling" RocksDB 日志查看 stall 的具体原因。
• level0 sst 太多导致 stall,可以添加参数 [rocksdb] max-sub-compactions = 2(或者 3),加快 level0 sst 往下 compact 的速度。该参数的意思是将从 level0 到 level1 的 compaction 任务最多切成 max-sub-compactions 个子任务交给多线程并发执行,这个我们现在开的是4。
• pending compaction bytes 太多导致 stall,磁盘 I/O 能力在业务高峰跟不上写入,可以通过调大对应 Column Family (CF) 的 soft-pending-compaction-bytes-limit 和 hard-pending-compaction-bytes-limit 参数来缓解:
• 如果 pending compaction bytes 达到该阈值,RocksDB 会放慢写入速度。默认值 64GB,[rocksdb.defaultcf] soft-pending-compaction-bytes-limit = "128GB"。
• 如果 pending compaction bytes 达到该阈值,RocksDB 会 stop 写入,通常不太可能触发该情况,因为在达到 soft-pending-compaction-bytes-limit 的阈值之后会放慢写入速度。默认值 256GB,hard-pending-compaction-bytes-limit = "512GB"。
• 如果磁盘 IO 能力持续跟不上写入,建议扩容。如果磁盘的吞吐达到了上限(例如 SATA SSD 的吞吐相对 NVME SSD 会低很多)导致 write stall,但是 CPU 资源又比较充足,可以尝试采用压缩率更高的压缩算法来缓解磁盘的压力,用 CPU 资源换磁盘资源。
• 比如 default cf compaction 压力比较大,调整参数 [rocksdb.defaultcf] compression-per-level = ["no", "no", "lz4", "lz4", "lz4", "zstd", "zstd"] 改成 compression-per-level = ["no", "no", "zstd", "zstd", "zstd", "zstd", "zstd"]。

其实手册里已经写得很详细了,上面关于write stall的多个处理方式都是可以借鉴的。
我们在日志中发现了如下内容:

2020/06/30-12:36:33.758200 7f3586fff700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 69565867323 rate 13421767
2020/06/30-12:36:34.692021 7f359727e700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 69653348050 rate 10737413
2020/06/30-12:36:34.692218 7f3597e7f700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 69653348050 rate 8589930
2020/06/30-12:36:35.767359 7f35887fd700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 69556916359 rate 10737412
2020/06/30-12:36:36.668152 7f35853ff700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 69372668753 rate 13421765
2020/06/30-12:36:36.668323 7f3587dfc700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 69372668753 rate 10737412
2020/06/30-12:36:37.834539 7f359727e700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 68959655469 rate 13421765
2020/06/30-12:36:37.834705 7f35965ff700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 68959655469 rate 10737412
2020/06/30-12:36:37.834780 7f35861fe700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 68959655469 rate 8589929
2020/06/30-12:36:37.834845 7f3586fff700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 68959655469 rate 6871943
2020/06/30-12:36:37.834912 7f3597e7f700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 68959655469 rate 5497554
2020/06/30-12:36:39.076138 7f35887fd700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 68881689347 rate 6871942
2020/06/30-12:36:40.659559 7f3587dfc700 [WARN] [db/column_family.cc:823] [write] Stalling writes because of estimated pending compaction bytes 68785639852 rate 8589927

这里日志很明显是因为compaction到达了阈值限制,引发流控,进一步导致业务写入产生了积压。
监控里也能看到相关超阈值的情况:
这里可以看到max到了270

image


这里可看出和drop后经过gc lifetime的时间是吻合的,11:35完成了drop操作,经过了gc life time周期之后(这个集群是默认的10m),11:45出现了异常。

image


这里能看出compaction相关的监控增长非常明显,compaction pending bytes也能看出超出了阈值。

image

我们通过tikv-ctl来对所有kv的进行在线配置,临时调高其阈值,来避免因为流控引发的业务写入积压问题。 soft_pending_compaction_bytes_limit默认64G,hard_pending_compaction_bytes_limit默认256GB。关于这两个参数的含义,上文已经有做说明,当超过阈值时,主要是RocksDB的写入速度会受到影响。

./tikv-ctl --host=tidb01:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb02:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb03:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb04:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb05:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb06:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb07:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb08:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb09:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb10:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb11:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb12:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb13:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb14:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb15:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb16:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb17:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb18:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb19:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb20:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=wtidb29:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=wtidb30:20160 modify-tikv-config -m kvdb -n write.soft_pending_compaction_bytes_limit -v 256GB




./tikv-ctl --host=tidb01:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb02:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb03:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb04:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb05:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb06:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb07:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb08:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb09:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb10:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb11:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb12:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb13:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb14:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb15:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb16:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb17:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb18:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb19:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb20:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=wtidb29:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=wtidb30:20160 modify-tikv-config -m kvdb -n write.hard_pending_compaction_bytes_limit -v 512GB





./tikv-ctl --host=tidb01:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb02:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb03:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb04:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb05:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb06:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb07:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb08:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb09:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb10:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb11:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb12:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb13:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb14:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb15:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb16:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb17:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb18:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb19:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=tidb20:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=wtidb29:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB
./tikv-ctl --host=wtidb30:20160 modify-tikv-config -m kvdb -n default.soft_pending_compaction_bytes_limit -v 256GB


./tikv-ctl --host=tidb01:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb02:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb03:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb04:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb05:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb06:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb07:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb08:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb09:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb10:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb11:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb12:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb13:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb14:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb15:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb16:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb17:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb18:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb19:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=tidb20:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=wtidb29:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
./tikv-ctl --host=wtidb30:20160 modify-tikv-config -m kvdb -n default.hard_pending_compaction_bytes_limit -v 512GB
29

改完后能看到QPS稳定了,之后逐渐恢复正常,同时write stall消失:

image


image


各类 异常 报警 也 恢复 了 正常
image
等待compaction峰值小时后,要记得调回默认值,否则会导致compaction下不去,这时候占用空间会比较大。

四、相关知识点

开启 Region Merge

从 TiDB v3.0 开始,Region Merge 默认开启。本案例中的集群版本是3.0.5,默认就开启了。
drop table 后会有空 region ,会增加 raftstore 心跳的负载,通过开启 Region Merge 能减少 Region 的个数。与 Region Split 相反,Region Merge 是通过调度把相邻的小 Region 合并的过程。在集群中删除数据或者执行 Drop Table/Truncate Table 语句后,可以将小 Region 甚至空 Region 进行合并以减少资源的消耗。
通过 pd-ctl 设置以下参数即可开启 Region Merge:
pd-ctl config set max-merge-region-size 20
pd-ctl config set max-merge-region-keys 200000
pd-ctl config set merge-schedule-limit 8

相关配置介绍

调度相关的配置项。
max-merge-region-size
• 控制 Region Merge 的 size 上限,当 Region Size 大于指定值时 PD 不会将其与相邻的 Region 合并。
• 默认: 20
max-merge-region-keys
• 控制 Region Merge 的 key 上限,当 Region key 大于指定值时 PD 不会将其与相邻的 Region 合并。
• 默认: 200000
split-merge-interval
• 控制对同一个 Region 做 split 和 merge 操作的间隔,即对于新 split 的 Region 一段时间内不会被 merge。
• 默认: 1h

加速merge操作速度

Region Merge 速度慢也很有可能是受到 limit 配置的限制(merge-schedule-limit 及 region-schedule-limit),或者是与其他调度器产生了竞争。具体来说,可有如下处理方式:
• 假如已经从相关 Metrics 得知系统中有大量的空 Region,这时可以通过把 max-merge-region-size 和 max-merge-region-keys 调整为较小值来加快 Merge 速度。这是因为 Merge 的过程涉及到副本迁移,所以 Merge 的 Region 越小,速度就越快。如果生成 Merge Operator 的速度很快,想进一步加快 Region Merge 过程,还可以把 patrol-region-interval 调整为 "10ms" ,这个能加快巡检 Region 的速度,但是会消耗更多的 CPU 资源。
• 创建过大量表后(包括执行 Truncate Table 操作)又清空了。此时如果开启了 split table 特性,这些空 Region 是无法合并的,此时需要调整以下参数关闭这个特性:
• TiKV: split-region-on-table 设为 false,该参数不支持动态修改。
• PD:
• key-type 设为 txn 或者 raw,该参数支持动态修改。
• key-type 保持 table,同时设置 enable-cross-table-merge为 true,该参数支持动态修改。
注意:
如果删除了很多数量的 table ,才需要修改上述参数,只删除一个表或者量级很少就不需要开。
在开启 placement-rules后,请合理切换 txn和 raw,避免无法正常解码 key。
• 对于 3.0.4 和 2.1.16 以前的版本,Region 中 Key 的个数(approximate_keys)在特定情况下(大部分发生在删表之后)统计不准确,造成 keys 的统计值很大,无法满足 max-merge-region-keys 的约束。你可以通过调大 max-merge-region-keys 来避免这个问题。

大批量删除注意事项

在删除大量数据的时候,建议使用 Delete * from t where xx limit 1000; 这样的方案,通过循环来删除,用 Affected Rows == 0 作为循环结束条件。
如果一次删除的数据量非常大,这种循环的方式会越来越慢,因为每次删除都是从前向后遍历,前面的删除之后,短时间内会残留不少删除标记(后续会被 GC 清理掉),影响后面的 Delete 语句。所以可以考虑分区表和物理分表,我们这边测试发现物理分表的性能高于分区表,因此最终没有采用分区表的方式。

流控

TiKV 在 3.0.6 版本开始支持 GC 流控,可通过配置 gc.max-write-bytes-per-sec 限制 GC worker 每秒数据写入量,降低对正常请求的影响,0 为关闭该功能。该配置可通过 tikv-ctl 动态修改:

tikv-ctl --host=ip:port modify-tikv-config -m server -n gc.max_write_bytes_per_sec -v 10MB

五、总结

通过本文,希望能帮助您了解到TiDB在删除大批量数据时应该注意的问题,并提前进行规避,以及整个排查问题的思路,后续有相关大批量删除的新注意事项,也欢迎您随时提出,我会对文章进行补充,谢谢。

0
2
0
0

版权声明:本文为 TiDB 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
暂无评论