过了,分数不算高,但整个备考过程比我预想的值。
我本职不做数据库运维,日常工作偏安全方向,跟数据库打交道基本就是看日志、摸资产、做配置核查那一套。真要说 SQL 水平,写个多表 JOIN 没问题,但"优化器为什么选这个索引"这种问题我从前基本是放弃治疗的。所以决定考 PCTA 的时候有朋友问我图什么——说实话,一开始就是看到有免费考证的活动,想着白拿的证不考白不考(699 的报名费自费的话也不算小数目)。但真看进去之后发现,分布式数据库这套东西对我现在的工作是有用的:做资产梳理的时候我知道该去哪看,看日志的时候我知道一条请求在后端到底经过了几跳,这比只会背几条命令强太多了。
所以这篇不是百科全书式的知识整理,网上那种已经很多了。这篇记录的是我作为一个没有 DBA 底子的人,在备考过程中真正卡住过、差点选错、或者理解反了的地方。如果你也是非科班或者刚接触 TiDB,可能比看纯知识点罗列更有用。
一、关于考试本身,先把坑说在前面
几个官方口径的信息,我在报名前反复确认过(以平凯星辰这边的中文版为准,和英文站的口径不完全一样,别混着看):
-
50 道题,单选 26 + 多选 24,每题 2 分,满分 100,60 分及格
-
时长 60 分钟
看起来 60 分钟做 50 道题不算紧张,但实际体感完全不是这么回事。多选题才是真正的分水岭,24 道多选占了 48 分,而且多选题的判定比较严格,靠排除法蒙对的概率远低于单选。我给自己定的节奏是:单选控制在 20 分钟以内,剩下 35 分钟给多选,最后 5 分钟回看标记题。实际执行下来多选还是有点赶,建议平时练的时候就掐表。
还有一个容易忽略的点:及格线官方说的是"以正确率 60% 为基准,根据试卷难度系数略有小幅波动"。这句话我理解下来就是——别把目标定在 60 分,冲着 75 分以上去练,心理上才稳。
二、我给自己换的学习路径:别背职责表,跟着一条 SQL 走
网上大部分笔记的第一部分都是三大组件的职责对照表:TiDB Server 干什么、PD 干什么、TiKV 干什么。这张表我也背了,但背完做模拟题还是错。
后来我换了个办法:不背组件,跟着一条 SQL 走完全程。
比如一条 UPDATE t SET c = 1 WHERE id = 100。从客户端发出去开始,它在集群里经历了什么:
-
客户端通过 MySQL 5.7 协议连上来。因为 TiDB Server 是无状态的,前面随便挂个 HAProxy / LVS 做负载均衡就行,连到哪个节点都一样。这是我第一次直观理解"无状态"这个词的实际价值——它意味着计算层可以随便加机器
-
TiDB Server 收到 SQL,向 PD 要一个 TSO。这一步要注意,TSO 只能从 PD 的 Leader 拿,Follower 不给。TSO 是个 int64,物理时间 + 逻辑时间拼出来的,单调递增但不保证连续(这个"不连续"是考点,别想当然以为时间戳是挨着的)
-
Parser 出 AST,Optimizer 做代价估算生成分布式执行计划。这里优化器要决定:走索引还是全表扫、要不要下推到 TiKV、走 TiKV 行存还是 TiFlash 列存
-
Executor 把关系型数据翻译成 KV 操作,通过 Coprocessor 把过滤条件下推到 TiKV,TiKV 在本地算完再把结果传回来
-
到 TiKV 这一层,先要定位 id=100 这个 key 在哪个 Region。Region 的路由信息 TiDB Server 会缓存,缓存失效了再问 PD
-
写操作走 Raft:Leader 节点 Propose、Append 日志、复制给 Follower,多数派(3 副本里 2 个)落盘成功才能 Commit,然后 Apply 到 RocksDB
-
事务提交走 Percolator 的两阶段提交,Prewrite 阶段加锁,Commit 阶段释放
这一趟走下来,三个组件的职责自然就记住了,而且记住的是因果关系不是孤立条目。考场上遇到"某组件挂了会怎样"这类题,脑子里有这条链路就能推。
这个方法唯一的问题是费时间。我大概花了三个晚上才把这条链路的每个环节都搞明白卡在哪,但后面复习基本没再回头看过组件表。
三、我整理的高频易错点(这部分是重点)
下面这些是我做题和看文档过程中真正弄错过、或者觉得最容易混淆的点。我不按知识模块排,按"坑的形状"排。
1. Region 分裂的两个阈值,别只记一个
这是我栽的第一个跟头。我一开始只记住了"Region 默认 96MB 分裂",做题时遇到 144MB 就懵了。
实际上有两个参数:
-
region-split-size:默认 96MiB。PD 检测到 Region 超过这个值,会下发分裂调度 -
region-max-size:默认 144MiB。这是 Region 大小的硬上限
网上有些资料写"Region 到 96MB 就不再插入新数据",这个说法我查了文档觉得不太准确,至少不够严谨,建议以官方文档的参数定义为准。另外还有个 region-merge-size(默认 20MiB),Region 小于这个值且 key 数量也少的时候会被合并——分裂和合并是成对出现的,光记分裂不记合并,多选题就丢分了。
还有一点容易漏:Region 是按 key range 划分的,左闭右开 [start_key, end_key)。这个区间开闭考过不止一次。
2. TiKV 的两个 RocksDB 实例
TiKV 节点上跑着两个 RocksDB:
-
rocksdb raft:存 Raft 日志 -
rocksdb kv:存真正的用户数据
然后 rocksdb kv 里面又有三个 Column Family,default / write / lock。三个 CF 共享一份 WAL,各有自己的 MemTable 和 SST。
关于 default 和 write 的分工,我看课程视频里的说法是:TiDB 把长度大于 255 字节的值存到 default CF,小于等于 255 字节的直接存到 write CF。这个点比较细,但确实出现在课程里了,我倾向于认为它是考点——因为这种"刚好有个阈值"的细节特别适合出选择题。lock CF 存的是锁信息(Percolator 的锁)。
3. 事务隔离级别,TiDB 和 MySQL 不是一回事
我带着 MySQL 的固有认知去做题,在这里连错两次。
TiDB 支持的是 RC(读已提交)和 RR(可重复读),但此 RR 非彼 RR。TiDB 的 RR 实现的是 Snapshot Isolation,不是 MySQL InnoDB 那种基于 MVCC + next-key lock 的可重复读。TiDB 的 RR 下不存在幻读问题(因为快照读),但也不支持 SERIALIZABLE 和 READ UNCOMMITTED。
另一个大坑:乐观事务模式下,写冲突是在提交时才检测的,不是在执行 SQL 的时候就报。也就是说你开个事务改一行,另一个事务也改同一行,两个都能改成功,谁先 commit 谁赢,后 commit 的报 write conflict。这个行为跟我熟悉的 MySQL 完全不一样——MySQL 是后改的直接阻塞等待。TiDB 从 v3.0 开始支持悲观事务,v3.0.8 之后默认开启,悲观模式下行为才接近 MySQL。
4. AUTO_INCREMENT 不保证连续
这个几乎是必考。分布式环境下 TiDB 的自增 ID 只保证唯一、保证递增趋势,但不保证连续。每个 TiDB Server 会向 PD 批量申请一段 ID 在本地缓存分配,所以不同节点分配的号段是交错的。
如果需要避免自增主键带来的写热点(所有写入都挤在最后一个 Region),要用 AUTO_RANDOM 或者 SHARD_ROW_ID_BITS + PRE_SPLIT_REGIONS。这三个东西的适用场景我特地做了区分:
-
AUTO_RANDOM:替代表自增主键,随机但保持唯一,解决热点 -
SHARD_ROW_ID_BITS:针对非聚簇表且没有主键的情况,把隐藏 rowid 打散 -
PRE_SPLIT_REGIONS:建表时预先切分 Region,避免冷启动所有写都打在一个 Region 上
5. 聚簇表与非聚簇表
CLUSTERED 和 NONCLUSTERED 的区别:
-
聚簇表:主键就是 key,数据按主键顺序组织
-
非聚簇表:额外生成一个隐藏的
_tidb_rowid作为 key,主键只是个唯一索引
这个区别直接影响上面第 4 点的热点处理方式——非聚簇表才有 rowid 可以打散。
6. Online DDL 的 Owner 机制
同一时刻整个集群只有一个 TiDB Server 是 Owner,负责执行 DDL。其他节点收到 DDL 请求会把它写进 TiKV 里的 job queue,由 Owner 的 worker 取出来执行。
一个容易记混的细节:Add Index 有自己独立的队列,可以和其他 DDL job 并行执行。这个设计的原因是加索引太慢了,如果和普通 DDL 排一条队会堵死。
DDL 执行完之后通过 Schema Load 机制通知所有 TiDB Server 更新 schema 缓存。
7. GC 不是数据库的 GC
TiDB 的 GC 专指 MVCC 历史版本的垃圾回收,默认 10 分钟触发一次。清理的界限叫 safe point,由 PD 维护,值等于当前 TSO 减去 tidb_gc_life_time(默认 10min)。
这里有个隐藏考点:如果你的查询需要的历史版本被 GC 掉了,会报 GC life time is shorter than transaction duration。调大 tidb_gc_life_time 能解决,但代价是历史版本堆积、查询变慢。这是个典型的权衡题。
8. 缓存表的 64MB 限制和租约
v6.0 之后支持把小表整张缓存到 TiDB Server 内存里:ALTER TABLE t CACHE。
条件是表数据 ≤ 64MB。核心机制是租约(lease),默认 tidb_table_cache_lease = 5s:
-
租约有效期内:整张表只读,不能写
-
租约过期后:写操作直接写 TiKV,读也回到 TiKV
所以缓存表不是"永远不失效的缓存",它有最多 5 秒的数据延迟窗口。另外缓存表上不能直接做 DDL,得先 ALTER TABLE t NOCACHE。
9. TiFlash 的几个"不"
TiFlash 是 TiKV 的列存副本,通过 Raft Learner 角色同步数据。Learner 只同步日志,不参与投票和选举——这是个关键设计,保证 OLAP 副本挂了不会影响 OLTP 的可用性。
TiFlash 的 MPP(大规模并行处理)有几个限制必须记住:
-
只支持等值连接(equi-join),非等值连接跑不了 MPP
-
计算全部在 TiFlash 节点的内存中完成
-
官方建议 TiFlash 承载的 OLAP 查询 QPS 不要超过 50,它是吞吐型不是并发型
还有个我觉得很妙的设计:TiFlash 的 Region 和 TiKV 完全对应,同步分裂与合并。这就省掉了两套分片逻辑的对齐问题。
10. 周边工具:记"什么时候用哪个"比记参数重要
PCTA 会考 Dumpling / Lightning / DM / BR / TiCDC / sync-diff-inspector 这几件套。我一开始死磕命令行参数,后来发现考试更爱考场景匹配:
| 工具 | 干什么 | 关键特征 |
|—|—|—|
| Dumpling | 数据导出(逻辑导出) | 输出 SQL 或 CSV,--consistency 控制一致性级别 |
| TiDB Lightning | 数据导入 | 三种 backend:local / importer / tidb。local 模式最快,但导入期间目标表不可读写,且需要大量本地临时磁盘做排序 |
| DM | MySQL/MariaDB → TiDB 的全量+增量迁移 | 支持分库分表合并 |
| BR | 物理备份恢复 | 备份到 S3/GCS/NFS,恢复时目标表必须不存在 |
| TiCDC | 增量数据同步 | changefeed 模型,可输出到 Kafka / MySQL / 下游 TiDB |
| sync-diff-inspector | 数据一致性校验 | 校验上下游数据是否一致 |
Lightning 的 backend 选型我特地记了一下:local 模式速度最快但会"占表",tidb 模式最慢但可以在线导入。这个取舍是高频考点。
BR 的坑:恢复的时候目标表必须不存在,BR 不会覆盖已有数据。另外一个常考的是 BR 备份的是物理文件,恢复必须恢复到同版本的集群。
11. 端口和监控
端口这个东西没什么技巧,就是背。我按"谁对外提供服务"来记:
-
TiDB Server:4000(客户端连接)/ 10080(状态信息,个别版本有调整,以官方文档为准)
-
PD:2379(对外)/ 2380(PD 节点间通信)
-
TiKV:20160 / 20180
-
TiFlash:9000 / 3930 / 20170 / 20292 / 8234
-
Prometheus:9090,Grafana:3000
TiDB Dashboard 是集成在 PD 上的,访问地址是 http://{PD_IP}:2379/dashboard。这个我一开始以为是个独立组件,做模拟题的时候选错了。
监控体系是 Prometheus + Grafana + Alertmanager 三件套,这个跟大部分云原生组件一致,不用额外记。
12. TiUP 的命令体系
TiUP 是官方部署运维工具,考试会考命令的作用。tiup playground 本地起测试集群,tiup cluster 管生产集群:
tiup cluster deploy <cluster-name> <version> ./topology.yaml
tiup cluster start / stop / restart / destroy
tiup cluster display # 看集群状态
tiup cluster scale-out / scale-in
tiup cluster upgrade
tiup cluster reload # 改完配置重新加载
scale-out 需要写新的 yaml 描述要加的节点,scale-in 之后节点会进入 Offline 状态,PD 开始把上面的 Region 迁走,迁完变 Tombstone。这个状态流转过程我觉得值得记住——它解释了为什么缩容不是瞬间完成的。
13. TiKV 写入的三个线程池
这个知识点我第一轮直接跳过了,第二轮才看到,属于"考了就白给"的那种:
-
scheduler:接收并发的写请求,用 latch 解决同一个 key 上的写入冲突
-
raftstore:把 Raft 日志持久化并同步给其他副本
-
apply:从
rocksdb raft读出已提交的日志,写入rocksdb kv
记法很简单:收活儿(scheduler)→ 记日志(raftstore)→ 落数据(apply)。
14. Follower Read 和 Stale Read 不是一回事
两个都能从副本读,但语义完全不同:
-
Follower Read:读 Follower 副本,但要通过 ReadIndex 机制确认这个 Follower 的日志够新,所以读到的还是最新数据,目的只是分担 Leader 压力
-
Stale Read:故意读一个历史时间点的数据,比如
SELECT ... AS OF TIMESTAMP,用来规避跨地域读的延迟
Stale Read 能读到多老的数据,取决于 GC 有没有把那个版本清掉,所以第七点说的 tidb_gc_life_time 这里又串上了。
考试爱考的问法是"TiDB 的所有读都必须走 Leader" —— 有这两个特性在,这句话就是错的。
15. 一些零碎但爱考的限制
-
单个事务的大小限制:默认 100MB(
txn-total-size-limit) -
单个 KV entry 的限制:默认 6MB(
txn-entry-size-limit) -
不支持存储过程、触发器、外键(外键在很新的版本里才开始有实验性支持,考试按"不支持"记)
-
TiDB 的
EXPLAIN结果和 MySQL 长得不一样,重点看task列(区分是在 TiDB 侧执行还是下推到了 TiKV/TiFlash)和operator info
最后一条其实是个实用技巧,不只是考试:看 TiDB 的执行计划,第一眼应该看 有没有下推,而不是看有没有走索引。一个没下推的走索引查询,往往比下推了的全表扫还慢。
四、多选题:我的策略是"宁可少选"
24 道多选占了将近一半的分,而且错选基本就没分了。我最后采取的策略很保守:
-
完全确定的选项才选,模棱两可的一律不选
-
遇到"以下说法正确的是"这种,如果四个选项我只确定三个,就选三个,不赌第四个
-
特别留意绝对化表述。“只能”“必须”“所有”"任何时候"这类词语出现时,八成是错的——分布式系统的设计几乎到处都是例外和权衡
第三条帮我捡回来好几道题。比如"TiDB 的所有读操作都必须经过 Leader"——错,有 Follower Read 和 Stale Read;“Region 分裂后数据一定会均衡”——错,PD 的调度有阈值和等待时间,不是立即均衡。
五、动手做了什么(以及做砸了什么)
光看视频我估计过不了。以下是我实际在虚拟机里跑过的:
起集群。 用 tiup playground 起了个最小集群,一条命令的事,吃内存比较大但对我来说够用了。后来又照着官方文档用 tiup cluster 在三台虚拟机上部署了一遍,这一步主要是为了记住 topology.yaml 长什么样。
看 Region 分布。 用 sysbench 灌了点数据,然后查 information_schema.tikv_region_status,看 Region 是怎么随数据量涨起来的。这个比看文档直观一百倍。
造一次故障。 直接 kill 掉一个 TiKV 进程,然后用 tiup cluster display 看状态变化,观察 Region 的 Leader 是怎么漂到别的节点上去的。等了一会儿它自己恢复成 healthy 了——这是我对"默认高可用"这四个字第一次有实感。
跑 BR 备份恢复。 备份到本地 NFS,然后故意删表,再恢复回来。踩了个坑:第一次恢复失败了,因为目标表还在,报错提示表已存在。删了表之后才成功。这比我背十遍"BR 恢复到空表"都管用。
做砸的部分: Lightning 的 local 模式我一直没跑通,虚拟机磁盘空间不够,跑一半就报空间不足退出了。最后是看文档理解的,没有实操。这块我到现在心里也没底,建议有条件的话还是实机跑一遍,尤其是注意磁盘空间的预估。
没做的: TiCDC 和 DM 我只看了文档没实际部署。DM 需要额外准备上游 MySQL 实例,我偷懒了。考场上遇到 DM 的题基本靠文档记忆,算是这次备考比较遗憾的地方。
六、考场上的实际感受
考完出来几个印象。
第一个是架构原理的占比确实高。三大组件的职责、协作流程、Region 和 Raft 相关的题加起来,我感觉能到三分之一以上。官方那门《TiDB 数据库核心原理与架构》课后的练习题一定要做——我有印象考场上有几道题的考点在课后题里出现过,不是原题,是同一个知识点换个问法。这个提示网上很多人提过,我一开始没当回事,考完才后悔没早点刷。
第二个是多选题里"选正确的"比"选错误的"难太多。后者好歹能用排除法,前者要求每个选项你都得单独判断对错,四个选项就是四道题。
第三个是有些题考得很细,比如某个参数的默认值、某个特性是从哪个版本开始支持的。这部分我基本靠刷题覆盖,但没覆盖全,最后那几道不确定的多选我都只选了确定的选项。
最后是时间。60 分钟听起来宽裕,但多选题真的要反复读题,我最后只剩三分钟扫了一遍标记题,有两道想改但没敢改——多选题改答案的风险比单选题大得多,想清楚再动。
七、如果重来一次,我会怎么安排
我前后大概花了三周,基本是每天下班后一到两个小时,周末多花点。回头看,时间分配上有几处挺浪费的。
最值的是这三件事:官方 101 课程 1.5 倍速过一遍(讲师语速确实慢,2 倍速也完全能听清,但 1.5 更适合边听边记)、课后练习题、然后自己动手起集群造一次故障。这三件事的产出占了我觉得七成以上的得分把握。
最不值的是死记命令行参数。我花了一整个晚上背 TiUP 和 Lightning 的各种 flag,结果一道都没考。考试不关心你怎么敲命令,它关心的是这个工具解决什么问题、有什么限制、什么场景下不能用。想明白这一点之后我复习速度快了很多。
还有个判断:那些特别新的版本特性(TiProxy、Resource Control、Runaway Query 这些)我最后只粗略过了一遍没深究。不是说不会考,而是对"通过考试"这个目标来说性价比不高,有余力再看比较划算。事实上考场上我确实没遇到几道。
要重来的话,我会把 TiCDC 和 DM 的实操补上,别偷懒。这两块在周边工具模块里占比不小,光看文档真的记不牢,考到就只能赌。
最后一个建议,官方文档和课程视频要配合着看。视频适合建立整体认知,文档适合搞清楚"为什么"。视频里一笔带过的东西,文档里往往有完整的前因后果,而考试偏偏爱考这些因果——比如"为什么 Add Index 要单独开一个队列"这种。
写在最后
考完之后最大的收获倒不是那张证书,是终于把"分布式数据库到底怎么工作的"这件事从概念变成了具体的、能画出来的流程。我现在的日常工作里,看 TiDB 相关的日志和监控面板的时候,脑子里是有那张架构图的,知道一条慢查询可能卡在哪个环节、一个告警背后是哪个组件在出问题。这种感觉挺踏实的。
证书长期有效,不用年审,这点挺好。下一步看情况要不要冲 PCTP,据说难度是另一个量级了。
(笔记整理得比较随性,有些地方是我自己的理解,如果有说得不对的地方欢迎在评论区怼我,我改。)