# Gp TiDB Course 101 潜在的非标准写作
+ 2022-05-16 16:35:29.291985

| 风险 | 建议 | 文件:实例 |
| :-- | :-- | :-- |
|  , | __potential-issue__ | chapter-01/04.md:由于数据是按照 'key value' 的形式（KV）存储在 TiKV 上的,所以,关系型数据（表、索引和行） 和 KV 结构之间存在很大的区别,如果希望执行 SQL ,必须能够在关系型数据和 KV 存储间相互转换。,chapter-02/04.md:由于数据是按照 key value 的形式（KV）存储在 TiKV 上的,所以,关系型数据（表、索引和行） 和 KV 结构之间存在很大的区别,如果希望执行 SQL ,必须能够在关系型数据和 KV 存储间相互转换。,chapter-02/16.md:TiDB 数据库支持 online DDL ,也就是 DDL 操作不会锁表,DML 语句是不会阻塞的。下面,我们一起来看一下 DDL 的执行所需要的各个模块。,chapter-03/03.md:下面我们会介绍 TiKV ,TiKV 的主要核心功能是负责 TiDB 数据库的数据持久化,这个功能是靠集成在 TiKV 中的 RocksDB 实现的,所以我们会着重介绍 TiKV 中 RocksDB 的数据写入（也就是持久化）与读取,另外介绍 RocksDB 中 Column Families 的功能,这个功能对后面事务和 MVCC 的支持有很大的影响。,chapter-03/06.md:当有删除操作时,并不需要像 B+ 树一样,在磁盘中找到相应的数据后再删除,只需要在 MemTable 中插入一条数据当作标志,如 delete key:1233 ,当读操作读到 MemTable 中的这个标志时,就会知道这个 key 已被删除。随后在日志合并中,这条被删除的数据会在合并的过程中一起被删除。,chapter-03/06.md:每个 SST 文件中的 key 都是排好序的。如果需要定位一个 key ,我们先二分查找所有文件的起始和结束 key,定位哪个文件有这个 key ,然后二分查找具体的文件,来定位 key 的位置。总的来说,就是在该层的所有key里面进行二分查找。,chapter-03/06.md:磁盘上的文件被分成多层进行组织。我们叫它们为 Level-1,Level-2 ... 等等,或者简单的 L1 , L2 ... 等等。一个特殊的层,Level-0 ( L0 ),会包含刚从内存 MemTable 落盘的数据,到达 4 个会触发 compaction 向下一层,如果积压达到 20 个,会触发 write stall。每个层（除了 Level0 ）都是一个独立的排序结果。,chapter-03/07.md:最后,RocksDB 内部还有一个 Block Cache 功能,我们可以设置内存中的一个空间给 Block Cache ,这个 Block Cache 中是我们经常访问的数据,所以查询操作会优先选择从 Block Cache 中读取数据,如果数据没有被缓存到 Block Cache 中,那么我们就开始从 MemTable 中启动上面叙述的读取流程。,chapter-03/08.md:- 支持跨列族原子写。意味着您可以原子执行 Write ( { cf1, key1, value1 } ,  { cf2, key2, value2 } )。,chapter-03/08.md:每当一个单独的列族（Column Family）刷盘,我们就创建一个新的 WAL 日志（ log ）文件。所有列族（Column Family）的所有新的写入都会去到新的 WAL 日志（ log ）文件。但是,我们还不能删除旧的 WAL ,因为他还有一些对其他列族（Column Family）有用的数据。我们只能在所有的列族（Column Family）都把这个 WAL 日志（ log ） 里的数据刷盘了,才能删除这个 WAL 日志（ log ）文件,确保你的所有列族都会有规律地刷盘。,chapter-03/09.md:分布式事务要解决的问题是,比如我们需要同时将 < 1,Tom > 改为 < 1,Jack > ,< 2,Andy > 改为 < 2, Candy > （ < 员工编号,员工姓名 > 的 key - value ）,而 < 1,Tom > 和 < 2,Andy > 存储在不同的 Region 甚至 TiKV 上,那么当操作结束之后,有可能会出现,< 1,Tom > 改为 < 1,Jack >  成功,< 2,Andy > 改为 < 2, Candy > 失败或者反之。这样就破坏了事务的原子性,下面我们看看 TiDB 如何解决这个问题。,chapter-03/12.md:但是,如果有了 MVCC 机制,我们知道,在 TSO 为 120 时的读取,不仅可以读取出 < 2, Candy > ,还可以读出  < 1,Jack > 和 < 4,Tony > ,因为事务一没有提交,我们可以读取提交之前的值。,chapter-03/13.md:1. Write CF 中,由于只有事务一提交了,所以会有事务一的记录,key = 1 和 key = 2 两个值的提交记录,value 更改都是 start_ts = 100. 还有一个 key = 4 ,我们看他的 start_ts 为 80,所以这条记录是以前提交的。,chapter-03/24.md:下面接着看,在 Raft 层 committed 后,我们要做的就是将 rocksdb raft 实例中的这条 raft log 应用到 rocksdb kv 实例中。这个过程叫做 Apply ,也是最后一个流程。只要  leader 角色 region 所在的 TiKV 节点完成了 Apply 这一步,那么我们的客户端（比如 TiDB Server）就算写入完成了。,chapter-03/26.md:一开始,我们先介绍一个概念叫:term,所谓 term 就是 Raft  共识算法将时间分成的小段（ 也可以理解为在 Raft 共识算法眼中,时间被分为了一个 term 接着一个 term ）,每个 term 的大小可能是不一样的,我们用连续递增的数字来标识这些 term ,保存在每个节点中,在 term 的初始阶段一定是选举阶段,当 leader 诞生之后,这个 term 的剩余时间里整个 raft 集群对外提供正常的服务,如果没有发生异常,这个 term 将一直持续下去（ term 的标识不会发生改变 ）,如果发生异常（比如 leader 宕机或者网络问题）,那么当前 term 将结束,新的节点会递增之前的 term 标识,然后进行新一轮的选举。这里我们还要注意一点,Raft 是要保证在一个 term 内,最多只有一个 leader 在集群中。,chapter-03/28.md:接下来,我们看一种特殊情况,就是在 election timeout 触发了选举后,有 2 个以上的节点都将自己的 term 递增,将自己变为 candidate 角色,并且投票给了自己。而他们又恰恰收到了相同数量的 follower 同意信息,这个时候怎么办呢？系统会重新发起新一轮投票,直到产生出唯一的 leader,为了避免永远不可能有 leader 被选举出来或者多次重复选举,我们可以采用一种叫做 random election timeout 的算法来降低重复的概率,这个算法可以理解为,每个节点在开始 leader 选举时,会随机设置一个区间范围内的 election timeout ,而不是采用统一的值,这样可以很高概率避免多个 candidate 票数相同的情况。,chapter-03/29.md:下面我们将几个时间概念和参数对应起来看一下,首先是咱么说的 election timeout ,它表示在无主状态下,多长时间节点发起选举,对应的参数是 raft-election-timeout-ticks,默认的值为 10。另一个概念是 heartbeat time interval ,表示发送心跳时经过的 tick 个数,对应的参数是 raft-heartbeat-ticks,默认的值为 2。,chapter-03/31.md:3. 如果确认当前节点是 leader ,则等待日志（ raft log ）被应用,直到日志（ raft log ）的序号,也就是 apply index, 超过了 ReadIndex,这样就能够安全地提供一致性读了。,chapter-03/38.md:我们再看下面的图,我们将 SQL 计算下推到了 TiKV ,这个工作由 TiKV 的 Coprocessor 组件完成,它的工作流程如下:,chapter-04/03.md:下面,我们看一下 PD 的架构与组成,PD 本身由至少由 3 个节点构成,PD 通过集成 etcd ,支持 auto failover,无需担心单点故障问题。同时,PD 也通过 etcd 的 raft,保证了数据的强一致性,不用担心数据丢失的问题。生产中,建议部署奇数个 PD 节点。,chapter-04/07.md:3. 同时,PD Client 则异步通过 gRPC 向 PD 获取 TSO ,这里要注意并不是一次 TSO 的请求对应发出后,PD Client 马上会向 PD 请求 TSO,当同一时间段（极短）有大量的请求并发到达 PD Client 时,PD Client 会进行批处理,将这些请求作为一个批处理请求只发送一次,但是如果 PD Client 收到 TSO 请求的间隔较长,仍然会一条一条请求向 PD 发送的。对应图中:3 和 5。,chapter-05/04.md:2. 异步获取 SQL 语句的 start_ts , 也就是 SQL 语句开始的 TSO。,chapter-05/06.md:TiDB Server 的 Protocol Layer 监听到客户端发来的 SQL 以后,开始对 SQL 文本进行处理,最先做的是从 PD 获取异步获取 SQL 语句的 start_ts , 也就是 SQL 语句开始的 TSO,之后,分别会经过 Parse（解析）和 Compile（编译）两个模块,最终产生执行计划传递给 Executor（执行器）模块。下面分别进行介绍。,chapter-05/12.md:TiDB 数据库支持 online DDL ,也就是 DDL 操作不会锁表,DML 语句是不会阻塞的。下面,我们一起来看一下 DDL 的执行所需要的各个模块。,chapter-07/06.md:1. 在 T0 时刻,client 写入 key = 1 ,value = 100；key = 999, value = 7,如下图: |
| ， | , | chapter-02/20.md:使用 ALTER TABLE users CACHE; 语句可以将小表载入到 TiDB Server 的小表缓存区中，但也就是从此 TiDB Server 开始为被缓存表加上一个租约（lease），租约（lease）由系统参数 tidb_table_cache_lease 定义，默认为 3，范围可以从 1 到 10，单位为秒。,chapter-02/20.md:如果图，当表开始从 TiKV 载入 到 TiDB Server 的缓存开始，便开始计时。,chapter-02/21.md:在租约（lease）时间内，我们的在 TiDB Server 上对于小表的读操作都可以在缓存中进行，但是写操作是被阻止的。也就是说这个时候表是无法修改的。,chapter-02/21.md:租约时间内，无法进行写操作,chapter-02/22.md:当租约（lease）过期后，缓存中的数据也就过期了，这个时候所有的读操作会从 TiKV 节点中获取数据，写操作也可以进行了。,chapter-02/22.md:租约到期，数据过期,chapter-02/23.md:当数据更新完毕后，租约（lease）开始重新计时，写操作继续被阻塞，这个时候数据被重新载入到 TiDB Server 的缓存中，读取操作又可以从 TiDB Server 的缓存中获取数据了。,chapter-02/23.md:数据更新完毕，租约继续开启,chapter-02/24.md:不支持对缓存表直接做 DDL 操作，需要先关闭,chapter-02/24.md:在租约（tidb_table_cache_lease）时间内，写操作会被阻塞,chapter-02/24.md:对于表加载较慢或者极少修改的表，可以适当延长 tidb_table_cache_lease  保持读性能稳定,chapter-02/24.md:当租约到期（tidb_table_cache_lease）时，读性能会下降,chapter-08/03.md:提供更灵活的数据放置管理能力，支持精细化的数据放置,chapter-08/04.md:- 跨地域部署的集群，无法本地访问,chapter-08/04.md:从图中可知，BeiJing 的一个用户需要跨区域到 NewYork 去读写 T3 表的数据，原因是我们没有办法在创建表的时候指定其存储的物理位置。,chapter-08/04.md:在 TiDB 6.0 版本之前，我们的 TiDB 集群在数据放置管理能力方面存在以下问题：,chapter-08/04.md:在图中，NewYork 的 3 位用户，分别需要访问 T4，T5 和 T6 三张表，而不凑巧的是这3张表的大部分 leader 角色的 region 数据都分布在了 TiKV-5 这一台服务器上，如果能够根据业务属性去放置数据，让三位用户分别从不同的服务器来读写T4，T5 和 T6 表将会避免热点的产生。,chapter-08/04.md:在图中，Tokyo 的 2 位用户都需要访问 T7 表，而 T7 表又是一张非常重要的表，我们希望它     的副本数为 5，同时 T8 表是一张历史表，我们希望 T8 表可以存储在性能一般的 TiKV-7，TiKV-9 和 TiKV-10 3 台服务器，而不占用性能较高的 TiKV-8 服务器，也就是冷热分离的数据摆放需求。,chapter-08/04.md:跨地域部署的集群，无法本地访问,chapter-08/05.md:关于冷热数据分离，我们看在 Tokyo 区域，T7 表的 leader 角色的 region 放置在了性能较好的 TiKV-8 服务器上，而 T8 表则使用了性能一般的 TiKV-7，TiKV-9 和 TiKV-10 3 台服务器。另外，我们也看到了，T7 表的副本数是 5 个，与其他表不同，这样就实现了按照业务等级配置资源和副本数。,chapter-08/05.md:在 NewYork 区域，我们将 T5，T6 和 T7 三张表设置为 leader 角色的 region 分别放在了TiKV-4，TiKV-5 和 TiKV-6 这 3 台服务器上，做到了根据业务隔离资源。,chapter-08/05.md:将 T2 表和 T3 表放在了 BeiJing 区域的集群，实现了跨地域部署的集群，支持本地访问。,chapter-08/05.md:有了 Placement Rules in SQL 之后，我们就可以做精细化的数据放置，如图：,chapter-08/05.md:跨地域部署的集群，支持本地访问,chapter-08/06.md:下面，我们看一下如何使用Placement Rules in SQL 功能，首先，我们需要为每一个区域、机柜和服务器配置标签。有了标签，我们就解决了在哪里的问题。也就是可以用 SQL 语句来指定数据对象放在什么位置了。,chapter-08/07.md:指定放置规则，首先需要通过 CREATE PLACEMENT POLICY 语句创建放置策略 (placement policy)。通过放置策略，我们可以指定 leader / follower / learner 角色 region 的位置，副本数等。,chapter-08/08.md:另外，不仅仅通过 create 语句在创建时指定数据放置，我们更可以通过 alter 语句修改数据对象的放置位置，但是由于这个操作会造成数据移动，所以不可以在业务高峰时进行。,chapter-08/08.md:有了标签和放置策略，我们就可以在创建schema（数据库），表和分区的时候规定其相应的位置了。这样我们就实现了精细化的数据放置。,chapter-08/09.md:业务数据整合，降低运维成本与复杂度,chapter-08/09.md:指定副本数，提高重要业务的可用性和数据可靠性,chapter-08/09.md:精细化数据放置，控制本地访问与跨区域访问,chapter-08/11.md:- 只读表，或者几乎很少修改,chapter-08/11.md:- 表的访问很频繁，期望有更好的读性能,chapter-08/11.md:- 配置表，业务通过该表读取配置信息,chapter-08/11.md:- 金融场景中的存储汇率的表，该表不会实时更新，每天只更新一次,chapter-08/11.md:- 银行分行或者网点信息表，该表很少新增记录项,chapter-08/11.md:TiDB 在 v6.0.0 版本中引入了缓存表功能。该功能适用于频繁被访问且很少被修改的热点小表，即把整张表的数据加载到 TiDB 服务器的内存中，直接从内存中获取表数据，避免从 TiKV 获取表数据，从而提升读性能。,chapter-08/11.md:以配置表为例，当业务重启的瞬间，全部连接一起加载配置，会造成较高的数据库读延迟。如果使用了缓存表，则可以解决这样的问题。,chapter-08/11.md:当表的数据量不大，访问又特别频繁的情况下，数据会集中在 TiKV 一个 Region 上，形成热点，从而影响性能。因此，TiDB 缓存表的典型使用场景如下：,chapter-08/11.md:由于 TiDB 将整张缓存表的数据加载到 TiDB 进程的内存中，并且执行修改操作后缓存会失效，需要重新加载，所以 TiDB 缓存表只适用于表比较小的场景。,chapter-08/11.md:目前 TiDB 对于每张缓存表的大小限制为 64 MB。如果表的数据超过了 64 MB，执行 ALTER TABLE t CACHE会失败。,chapter-08/12.md:使用 ALTER TABLE users CACHE; 语句可以将小表载入到 TiDB Server 的小表缓存区中，但也就是从此 TiDB Server 开始为被缓存表加上一个租约（lease），租约（lease）由系统参数 tidb_table_cache_lease 定义，默认为 3，范围可以从 1 到 10，单位为秒。,chapter-08/12.md:如果图，当表开始从 TiKV 载入 到 TiDB Server 的缓存开始，便开始计时。,chapter-08/13.md:在租约（lease）时间内，我们的在 TiDB Server 上对于小表的读操作都可以在缓存中进行，但是写操作是被阻止的。也就是说这个时候表是无法修改的。,chapter-08/13.md:租约时间内，无法进行写操作,chapter-08/14.md:当租约（lease）过期后，缓存中的数据也就过期了，这个时候所有的读操作会从 TiKV 节点中获取数据，写操作也可以进行了。,chapter-08/14.md:租约到期，数据过期,chapter-08/15.md:当数据更新完毕后，租约（lease）开始重新计时，写操作继续被阻塞，这个时候数据被重新载入到 TiDB Server 的缓存中，读取操作又可以从 TiDB Server 的缓存中获取数据了。,chapter-08/15.md:数据更新完毕，租约继续开启,chapter-08/16.md:不支持对缓存表直接做 DDL 操作，需要先关闭,chapter-08/16.md:在租约（tidb_table_cache_lease）时间内，写操作会被阻塞,chapter-08/16.md:对于表加载较慢或者极少修改的表，可以适当延长 tidb_table_cache_lease  保持读性能稳定,chapter-08/16.md:当租约到期（tidb_table_cache_lease）时，读性能会下降,chapter-08/17.md:内存悲观锁优化，在悲观锁性能瓶颈下，可以有效降低 10% 延迟，提升 10% QPS。,chapter-08/18.md:让我们回顾一下之前讲到的悲观锁实现原理，在 prwrite 阶段，我们需要将锁信息的占位符写入到 leader 角色和其他 follower 角色的 region 中，这些操作完成，prewrite 步骤才算完成。这样一来，网络和IO都会造成压力。,chapter-08/19.md:在内存悲观锁开启的情况下，lock 信息只保存在内存中，不用写入磁盘，不用通过 raft 写入多个副本，只要存在于 region leader。lock 信息写内存，延迟相对于通过 raft 写多副本，延迟极小。,chapter-08/20.md:如果在 prewrite 阶段，我们 leader 角色 region 锁在的 TiKV 节点出现意外下线，那么缓存中的锁信息就会丢失，事务出现失败。,chapter-08/22.md:但是也需要注意，锁丢失问题，如果影响业务的正确性逻辑，应关闭。,chapter-08/22.md:对于内存悲观锁这个新特性，给我们带来的好处为：,chapter-08/23.md:面向非专家的性能诊断功能 Top SQL，提供一体化、自助的数据库性能观测及诊断能力。,chapter-08/24.md:在 TiDB 6.0 之前，当我们遇到了某一个 TiKV 实例的 CPU 使用率突然增高时，如果想定位问题 SQL，只能有 slow query 或者 SQL Statements 这 2 个工具，但问题是，这两个工具都是面向整个 TiDB 集群的，并没有针对 TiDB Server 或者 TiKV 实例来做区分，也没有直接统计某类 SQL 的 CPU 消耗。,chapter-08/24.md:所以，经常会出现明明怀疑某几条 SQL 但是没有足够证据，或者面对 CPU 负载升高束手无策的场景。,chapter-08/25.md:同样，当我们的集群中 TiDB Server 或者 TiKV 实例 CPU 使用率突然增高的时候，我们依然没有办法找到到底是哪类正在执行的 SQL 引起了 CPU 使用率的突然增高。,chapter-08/26.md:- 通过图表及表格，可视化地展示 CPU 开销最多的 5 类 SQL 语句。,chapter-08/26.md:TiDB Dashboard 的 Top SQL 功能允许你可视化地监控和探索数据库中各个 SQL 语句在执行过程中的 CPU 开销情况，从而对数据库性能问题进行优化和处理。Top SQL 持续收集各个 TiDB 及 TiKV 实例每秒的实时 CPU 负载等数据（按 SQL 类型分别统计），并存储至多 30 天。你可以通过 Top SQL 展示的图表及表格快速分析某个 TiDB 或 TiKV 实例在某段时间中高 CPU 负载是来自于哪些 SQL 语句。,chapter-08/27.md:Top SQL 的使用非常简单，如下：,chapter-08/27.md:另外，你可以在时间选择器中调整时间范围，或在图表中框选一个时间范围，来更精确、细致地观察问题。更小的时间范围将能提供细节更丰富的数据，数据最高精度可达 1 秒。,chapter-08/27.md:如果图表中显示的数据已过时，你可以点击刷新 (Refresh) 按钮，或在刷新 (Refresh) 下拉列表中选择自动刷新。,chapter-08/28.md:柱状图中色块的大小代表了 SQL 语句在该时刻消耗的 CPU 资源的多少，不同颜色区分了不同类型的 SQL 语句。大多数情况下，你都应该关注图表中相应时间范围内 CPU 资源开销较大的 SQL 语句。,chapter-08/29.md:点击表格中的某一个 SQL 语句后，可以展开查看该语句不同执行计划的执行情况，例如 Call/sec（平均每秒请求数）、Scan Indexes/sec（平均每秒扫描索引数）等。,chapter-08/30.md:- 分析集群当前最消耗资源的 SQL 语句情况，希望对它们进行优化以便降低硬件开支。,chapter-08/30.md:- 通过监控图发现集群中有个别 TiKV 实例的 CPU 非常高，期望了解 CPU 热点来自于哪些 SQL 语句，以便对其进行优化、更好地利用上分布式资源。,chapter-08/30.md:- 集群整体 CPU 占用率突然发生了显著变化，期望了解变化前后主要的 SQL 资源开销区别。,chapter-08/30.md:- 集群整体 CPU 占用率非常高、数据库查询缓慢，期望快速知悉目前哪些 SQL 语句开销了最多的 CPU 资源，以便对它们进行优化。,chapter-08/31.md:TiDB Enterprise Manager (TiEM) 是一款以TiDB 数据库为核心的企业级数据库管理平台，帮助用户在私有部署 (on-premises) 或公有云环境中管理TiDB 集群。TiDB Enterprise Manager 不仅提供对TiDB 集群的全生命周期的可视化管理，也同时一站式提供TiDB 数据库参数管理、数据库版本升级、克隆集群、主备集群切换、数据导入导出、数据同步、数据备份恢复服务，能有效提高TiDB 集群运维效率，降低企业运维成本。,chapter-08/32.md:目前，一些企业在生产环境中部署了多套 TiDB 集群，随着集群数量增多、规模庞大和使用的深入。带来的集群管理问题也越来越多，主要体现在 2 个方面，一个是我们说的数量增多，包括我们管理的集群、节点、组件和工具的数量都在增长，在人力不变的情况下，工作越来越繁重！另一个是复杂度，本身随着版本的演进，我们的配置参数、命令行参数和管理接口语法变得非常复杂，人工的操作非常容易操作。,chapter-08/32.md:综上所属，随着企业对于 TiDB 数据库使用的深入，集群的管理问题越来越显现出来。,chapter-08/33.md:TiDB Enterprise Manager (TiEM) 是一款以TiDB 数据库为核心的企业级数据库管理平台，帮助用户在私有部署 (on-premises) 或公有云环境中管理TiDB 集群。它的出现解决了由于 TiDB 集群数量增多，带来的诸多管理问题。,chapter-08/34.md:- 支持 TiCDC 数据同步，快速构建从 TiDB 集群到下游系统 (TiDB、MySQL、Kafka） 的数据同步任务；,chapter-08/34.md:- 支持一键克隆 TiDB 集群，快速构建主备集群,chapter-08/34.md:- 支持异步工作流任务，确保用户操作体验。,chapter-08/34.md:- 支持用户可自定义参数组，沉淀积累运营中的最佳参数组合；,chapter-08/34.md:- 自动记录管理员操作，历史任务事后可追查、可回溯 |
| ： | : | chapter-08/04.md:在 TiDB 6.0 版本之前，我们的 TiDB 集群在数据放置管理能力方面存在以下问题：,chapter-08/05.md:有了 Placement Rules in SQL 之后，我们就可以做精细化的数据放置，如图：,chapter-08/11.md:TiDB 热点小表缓存(缓存表)功能适用于以下特点的表：,chapter-08/11.md:当表的数据量不大，访问又特别频繁的情况下，数据会集中在 TiKV 一个 Region 上，形成热点，从而影响性能。因此，TiDB 缓存表的典型使用场景如下：,chapter-08/11.md:我们可以采用如下方法将一张已经创建好的表缓存在 TiDB Server 的内存中：,chapter-08/11.md:注意点：,chapter-08/21.md:可以在线动态开启、关闭：,chapter-08/21.md:我们也可以通过 TiKV 配置文件进行配置：,chapter-08/22.md:对于内存悲观锁这个新特性，给我们带来的好处为：,chapter-08/26.md:Top SQL 具有以下功能：,chapter-08/27.md:Top SQL 的使用非常简单，如下：,chapter-08/30.md:作用：,chapter-08/30.md:使用场景：,chapter-08/33.md:TiDB Enterprise Manager (TiEM) 的主要应用场景包括：,chapter-08/34.md:- 支持数据同步任务管理：创建、暂停、恢复、删除。 |
