从前有家叫“小同”的面馆,生意红火到排队排到了马路对面。老板想开分店,却撞上一堵墙:单店后厨和收银台绑在一起,店一多账就乱,食材也不够用。于是他做了一个大胆的决定——把“做饭”和“存菜”彻底分开:点单员和厨师只负责接单炒菜(计算),食材统一送进冷链仓库(存储),又请了一位运营经理管着所有仓库的货架台账(调度)。分店想开多少就开多少,顾客点菜的方式却一点没变。这套“连锁餐饮集团”的玩法,正是 TiDB 的架构灵魂。TiDB 是 NewSQL 阵营的明星,它保留了人们熟悉的 MySQL 点菜方式(协议兼容),骨子里却是分布式系统的筋骨——可以像乐高一样水平扩展,还能在营业的同时顺手把经营报表算出来。接下来,我们就走进这家“数据库连锁集团”,看看它的后厨、仓库和调度台是怎么协作的。
理解 TiDB 整体架构,是数据库工程师迈向分布式存储世界的必修课。它能帮你快速上手真实工业级系统,也能让你在架构选型、性能调优和故障排查时,像看自家厨房一样看清每个环节。
可视化演示
展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。
本节配有交互动效(进入视口后自动加载,约 3KB)。
系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T
系统总览
小同的面馆升级为连锁集团后,立下三条规矩:第一,点单员和厨师只管接待,不管仓库;第二,食材全部放进冷链仓库,按箱分装,三仓各存一份;第三,运营经理手里攥着一本总台账,谁家缺货、谁家爆仓,都由他来调配。这套规矩,就是 TiDB 的顶层设计——计算存储分离。计算的人不碰数据,存储的人不碰业务,各司其职才能各展所长。
把面馆翻译成数据库:TiDB 集群由三种角色组成。TiDB 节点是前台的“点单员+厨师”,负责解析 SQL、生成执行计划,然后把活儿派下去;TiKV 是“冷链仓库”,以键值对(Key-Value)形式把数据分片存在多台机器上;PD 是“运营经理”,既管着数据分片的位置台账,又负责故障发现与负载调度。三者合在一起,对外却依然透出 MySQL 的熟悉味道——老顾客用的菜单、点菜的习惯全都不用改,这正是 TiDB 兼容 MySQL 协议的杀手锏。
这套架构带来最直观的好处是水平扩展:面馆生意火爆,与其把单店后厨扩到无限大,不如多开几家分店。TiDB 里加一台 TiDB 节点就多一份并发处理能力,加一台 TiKV 节点就多一份存储容量,理想情况下集群规模翻倍,吞吐量也接近翻倍。
当然,真实系统里网络开销、元数据同步会让这条曲线打点折扣,但 TiDB 的方向正是让 $T_{\text{总}}$ 尽量贴近这条理想直线。面馆的规矩立住了,后面的故事都从这三条规矩展开。
- 单节点吞吐$T_{\text{单}}$ 表示一个 TiDB 节点每秒能处理的请求量,类似一家分店单日能接待的客人。
- 节点数量$n$ 表示水平扩展后计算节点的总个数,相当于连锁集团开的分店数。
- 规模叠加理想状态下,总吞吐 $T_{\text{总}}$ 等于单节点吞吐乘以节点数,说明加人就能加量,这就是线性扩展的直观含义。
TiDB计算层
走进连锁集团的前厅,你会看见一群手脚麻利的点单员和服务员。客人报出一串菜名,点单员要听懂需求(SQL 解析),然后心里快速盘算:是先煮面还是先备料?需不需要让后厨并行出菜?(执行计划优化)这些前厅人员有个特点——他们身上从不带食材,下班拍拍手就能去任何一家分店顶班,这就是“无状态”。
在 TiDB 中,TiDB Server 就是这群前厅人员。一条 SQL 进来,第一步是解析:把“我要一碗牛肉面”这样的自然语言拆成语法树,检查语法对不对、字段存不存在。第二步是优化:生成多个执行计划,挑成本最低的那个。第三步是执行:把任务拆成子任务,分发给 TiKV 集群并行处理,最后汇总成结果端给客户端。整个过程对应用透明,应用以为自己只在跟一台 MySQL 说话,实际上背后有一整支分布式团队在协作。
无状态设计是 TiDB 计算层最优雅的地方。因为不存数据,TiDB 节点挂了,新节点秒级顶上,业务几乎无感;因为不存数据,TiDB 节点可以随意加减,前端接入层挂一个负载均衡,就能把请求均匀地分给所有活着的节点。集群的查询能力不再是单机的天花板,而是一群节点能力的叠加。
前厅团队越招越多,接待能力越来越强,但他们始终有个原则:只管接单传菜,绝不去仓库搬货。接下来,我们跟着食材,走进冷链仓库看看。
- 单机查询能力$q_i$ 表示第 $i$ 台 TiDB 节点每秒能处理的查询数(QPS),相当于一个点单员在一小时内能接待的客人。
- 节点遍历$\sum_{i=1}^{m}$ 表示把第 1 台到第 $m$ 台节点的能力全部加起来,这m台就是前厅所有的点单员。
- 集群总能力$Q_{\text{集群}}$ 是整支点单团队的总接待能力,体现了无状态节点水平扩展带来的线性收益。
TiKV存储层
冷链仓库是连锁集团的命脉。为了让食材存取高效,仓库实行“编号定位”:每种食材对应一个编号(Key),编号后面跟着存放位置与数量(Value),一张巨大的键值对照表就是全部家当。这就是 TiKV 的存储模型——一份分布式的 Key-Value 大表,只不过这张表被拆成了无数个小格子,铺在多台机器的磁盘上。
每个小格子,在 TiDB 里叫 Region。Region 是一段连续 Key 范围的数据,默认约 96MB,就像仓库里统一规格的周转箱。为什么要用箱子?因为整仓库找一件食材太慢,按编号段分区后,找食材只要先定位到箱子,再在箱子内翻找。更重要的是,箱子是数据调度和复制的基本单位:每个箱子在三个不同的仓库里各存一份,某间仓库失火,另外两间还能供货。
TiKV 的 Key 并不是简单的业务主键,它在内部会做一层编码,把表 ID、行 ID 等信息拼装进 Key,让同一张表的数据在物理上连续存放,扫描时不用跨箱子乱翻。
有了箱子,有了编号,还缺一个关键角色:谁来记下每个箱子放在哪个仓库的哪个货架?这个角色,就是 PD。
- 表前缀$P_{\text{表前缀}}$ 是固定字节,用来标识这是表数据的起始标记,相当于仓库里“生鲜区”的区位标识。
- 表标识$ID_{\text{表}}$ 是全局唯一的表编号,每张表对应一个 ID,用来区分不同表的数据。
- 行前缀与行号$P_{\text{行前缀}}$ 表示行数据标记,$ID_{\text{行}}$ 是这一行在表内的唯一编号。四段拼接后,相同表的数据 Key 前缀一致,天然聚在一起。
PD调度中心
连锁集团的运营经理老周,手上有三样宝贝:一本总台账、一部对讲机、一只盖章机。总台账记着每个箱子(Region)目前在哪个仓库、哪一排货架;对讲机让他每天定时和每个仓库通话,确认“一切正常”;盖章机则是给每笔跨仓业务盖一个统一的时间章,保证所有仓库按同一个时间线记账。
在 TiDB 中,老周就是 PD(Placement Driver,调度中心)。PD 维护的路由元数据,是客户端和 TiDB 节点找到数据的导航地图。TiKV 节点会通过心跳持续向 PD 汇报状态:我活着、我还有多少箱子、我负载多高。一旦某节点心跳超时,PD 立刻判定节点失联,启动副本补足流程。PD 还像一位精明的调度员,发现某台 TiKV 的 Region 特别多、成为热点时,就把一部分箱子搬到空闲节点,让整个集群的负载像水面一样平。
怎么衡量“均匀”?PD 用一个平方和公式作为不均衡度的度量:每个节点 Region 数量的平方加起来,值越小越均衡。这种度量让“大的更大”被放大,从而逼着调度器优先处理最忙的节点。
老周的台账、对讲机和盖章机,让整个集群始终处于“有人管”的状态。但你可能好奇:台账上写着一个箱子有三个副本,这三个副本之间是怎么保持一致的呢?这就是 Region 与 Raft 协议的故事。
- 节点Region数$n_i$ 表示第 $i$ 台 TiKV 节点上存放的 Region 数量,也就是这家仓库的箱子数。
- 平方放大$n_i^2$ 对箱子数取平方,让箱子多的节点数值更大,突出“不均衡”的严重程度。
- 求和度量$\sum_{i=1}^{n}$ 把所有节点的平方值加总得到 $L$,$L$ 越小说明整体越均衡,PD 的调度目标就是让 $L$ 不断下降。
Region与Raft
三兄弟合伙开仓库,最怕的就是账目对不上。老周定的规矩是:每一箱食材入库时,必须至少两个兄弟在入库单上签字画押,这箱货才算正式入库;如果三个兄弟都签了,那最好,但缺一个也不耽误收活。签字画押的过程还要写进一本只追加、不修改的流水账本里,方便日后对账。这套制度,就是著名的 Raft 一致性协议。
Region 的每个副本分布在不同的 TiKV 节点上,其中一个被选为 Leader(主副本),负责接收读写请求;另外两个是 Follower(从副本),负责同步日志。当业务要写一条数据时,Leader 把日志广播给 Follower,只要收到多数派(三个里两个)的确认,就可以向客户端返回成功。这样即使一个 Follower 节点宕机,集群依然能正常写入,这就是高可用的底气。
更妙的是,Region 的大小不是写死的。数据越写越多,箱子装满了(超过约 96MB),Region 会自动分裂成两个,像细胞分裂一样;反过来,如果删除数据导致箱子太瘪,相邻 Region 又会合并。PD 正是靠着这套分裂与合并机制,让数据分布始终保持在健康状态。
三兄弟的账本制度,让每一箱食材都有据可查、有错可纠。但面馆越来越大,老周发现了一个新问题:老板每天要的“经营报表”越来越多,可报表查询要是翻流水账,前台就没法做生意了。于是,集团专门成立了一个分析师团队。
- 故障上限$F$ 表示集群允许同时宕机的节点数量,对应仓库三兄弟里“最多失联几人还能正常营业”。
- 副本总量$N = 2F + 1$ 表示要容忍 $F$ 个故障,至少要准备 $2F+1$ 个副本。三副本时 $F=1$,可以容忍一台机器宕机。
- 写入确认数$W = F + 1$ 表示写入时最少需要多少个副本确认才提交。三副本时 $W=2$,即多数派确认,既保证安全又不必等最慢的那个。
TiFlash列存
分析师团队的办公室里,没有锅碗瓢盆,只有一排排特制的大账本。普通仓库的流水账(行存)是按“时间逐笔”记录的,查某一天的交易很快;分析师的账本(列存)则是按“食材名称”整列记录的——“番茄”这一列记着全年每天用了多少斤。老板问“今年番茄用了多少”,分析师扫一眼那一列就算完了,而普通仓库得把整本流水翻个遍。
这排特制账本,就是 TiFlash。TiFlash 是 TiDB 家族里的列存引擎,专门服务分析型查询(OLAP)。它不参与前台收银的主链路,而是以 Raft Learner(学习副本)的身份悄悄旁听每一笔账目,异步复制 TiKV 中的数据。Learner 不参与投票,因此它的同步完全不影响前台交易性能——分析师抄账本归抄账本,收银台该多快还是多快。
TiFlash 就位后,TiDB 就成了一家“既做快餐又出报表”的两栖企业,这就是 HTAP(混合事务与分析处理)。行存服务高频交易,列存服务复杂分析,两边数据天然一致,省去了传统架构里“交易库到分析库的 ETL 搬运”,分析结果实时性大幅提升。对比一下全表扫描的代价,列存的优势一目了然:
分析师团队就位后,连锁集团的“营业”与“经营”两条线互相独立又彼此印证。现在,让我们从头到尾走一遍一笔真实的订单,看看所有角色如何串成一条流水线。
- 行数$R$ 表示表中的总行数,比如全年 36.5 万笔交易记录。
- 列数与字节$C$ 是表的全部列数,$B$ 是每列平均字节数;$c$ 是分析查询真正需要的列数,通常远小于 $C$。
- IO对比$IO_{\text{行}} = R \times C \times B$ 是行存全表扫描要读的数据量,$IO_{\text{列}} = R \times c \times B$ 是列存只读目标列的数据量。当 $c \ll C$ 时,列存 IO 大幅缩减,这就是分析加速的秘密。
核心流程
一位顾客走进面馆,喊了一声:“来一碗牛肉面,多加香菜!”接下来发生的事,就是 TiDB 的一次完整写入流程。点单员(TiDB 节点)接到 SQL,先解析语义,然后找老周(PD)查台账:牛肉面的食材记录在哪个 Region、主副本在哪个仓库?老周秒回路由信息。点单员直奔目标 TiKV 节点,主副本(Leader)把这条记录写进日志,同步给两个从副本,收到多数派点头后,一份热腾腾的“写入成功”就端给了顾客。
整个过程看似简单,背后却有一项关键保障:分布式事务。面馆做的是“牛肉面套餐”,面条和牛肉必须一起上桌,不能只成功一半。TiDB 采用两阶段提交(2PC):先让所有相关 Region 的 Leader 把写入操作“预备”好,等全部确认后,再统一“提交”生效。任何一步失败,整笔订单回滚,就像后厨发现牛肉不够,整份套餐就不出餐,绝不上半碗面。
这套流水线同样支持弹性运维。想扩容,新加一台 TiKV,PD 会自动搬一批 Region 过去;某台 TiKV 宕机,PD 心跳超时后,其他副本立刻补位成为新 Leader,业务在秒级内恢复。所有操作对前台顾客无感——他们只觉得这家店“永远在线、从不打烊”。
从接单到上菜,整套流水线环环相扣。最后,我们退后一步,看看这家“数据库连锁集团”在整个行业里到底值多少钱。
- 单程通信时延$RTT$ 表示客户端与数据库之间一个网络往返的时延,类似点单员跑一趟仓库的时间。
- 预备阶段第一个 $RTT$ 对应两阶段提交的 prepare 阶段,所有参与节点先“备好菜但不下锅”。
- 提交阶段第二个 $RTT$ 对应 commit 阶段,所有备好的菜同时“出锅上桌”。两个往返合计就是分布式事务的基本时延开销。
架构价值
当初的小面馆,如今成了遍布全国的连锁集团。它的成功密码可以总结为四句话:不怕单店倒闭(高可用)、账本从不扯皮(强一致)、分店想开就开(线性扩展)、老顾客无缝迁移(生态兼容)。这四点,正是 TiDB 作为 NewSQL 代表在工业界站稳脚跟的根基。
高可用来自多副本与 Raft:任意一台机器宕机,数据不丢、服务不停。强一致来自 Raft 日志复制与分布式事务:多副本不会出现“各说各话”的脏读。线性扩展来自计算存储分离与 Region 自动调度:加机器就能同时加容量和性能。生态兼容来自 MySQL 协议:应用层 ORM、运维工具、监控体系几乎零改造接入,企业迁移成本极低。
衡量这套体系“有多可靠”,有一个朴素而有力的公式。系统的可用性取决于平均无故障时间(MTBF)和平均修复时间(MTTR):出故障不可怕,怕的是修得慢;自动化故障转移正是把 MTTR 从小时级压到秒级的关键。
小同的面馆故事讲完了:前厅接单、仓库存货、经理调度、分析师算账,各司其职又浑然一体。TiDB 之所以能成为 NewSQL 的标杆,正是因为它把分布式系统的复杂藏在了熟悉的 MySQL 面孔之下。理解了这套整体架构,你就拿到了走进分布式数据库世界的第一把钥匙。
- 无故障时间$MTBF$ 是系统平均能连续运行多久才出一次故障,相当于面馆平均多久才遇到一次停电。
- 修复时间$MTTR$ 是出故障后平均花多久恢复,相当于停电后多久恢复供电。
- 可用性比率$A$ 是两者之比,分子是“健康时长”,分母是“健康+生病总时长”。MTTR 越小,$A$ 越接近 1,也就是全年 99.99% 的时间都在营业。
AI 应用场景
电商大促订单中心的实时分析
阶段:数据存储与特征服务
解决的问题:传统电商用 MySQL 分库分表,大促时订单写入暴增,扩容靠人工拆表,且分析报表要等凌晨 ETL,老板看不到实时 GMV。TiDB 的计算存储分离让扩容变成“加机器”;TiFlash 列存让“边交易边分析”成为可能,分析查询在列存副本上跑,不抢交易写入的 CPU。
具体案例:某头部电商在大促期间将订单库迁到 TiDB,3 个 TiDB 节点 + 5 个 TiKV 节点动态扩展到 10 个 TiDB 节点 + 15 个 TiKV 节点,QPS 翻了三倍;运营大屏的实时 GMV 查询直接打到 TiFlash,秒级出数,不再等待 T+1 报表。
金融风控系统的跨分片事务查询
阶段:特征存储与在线推理支撑
解决的问题:风控规则引擎需要同时查询用户基本信息、交易流水、设备指纹等多类数据,数据天然分散。传统方案要么引入分布式事务中间件,要么牺牲一致性。TiDB 原生分布式事务让跨 Region 的读写在分布式下依然 ACID,PD 的负载均衡则避免热点用户的数据集中打爆某台机器。
具体案例:某消费金融公司风控系统每天处理百万级进件,每个进件要读取 20 余项特征。接入 TiDB 后,风控决策时延稳定在 100ms 内,PD 自动把高频用户的 Region 分散到多节点,告别了单点热点导致的超时告警。
AI应用元数据与特征存储底座
阶段:AI 应用的数据基座
解决的问题:AI 推荐、画像系统动辄需要存储上亿用户的特征元数据与中间结果,同时要支撑高并发点查。TiDB 兼容 MySQL 协议,AI 团队用熟悉的 ORM 即可接入,不必为数据访问单独造轮子;计算存储分离让特征表可以随业务增长平滑扩容。
具体案例:某短视频推荐团队将用户画像标签、物品元数据存入 TiDB,支撑每日数十亿次 key-value 点查;向量检索部分交给专用向量数据库,TiDB 负责结构化特征与事务性元数据,两者配合构成完整的 AI 数据底座。
Python 演示
"""mini_tidb.py:简化版TiDB架构模拟器"""REGION_MAX = 50 # 每个Region最多容纳50条记录 class Region: """一个Region = 一段连续Key范围的数据分片""" def __init__(self, rid, start, end): self.rid = rid self.start = start self.end = end self.data = {} def in_range(self, key): return self.start <= key < self.end def put(self, key, value): self.data[key] = value return len(self.data) >= REGION_MAX # 超容量返回True class TiKVNode: """存储节点,对应一个TiKV实例""" def __init__(self, node_id): self.node_id = node_id self.regions = [] def count(self): return len(self.regions) class PD: """调度中心:维护路由,执行分裂与负载均衡""" def __init__(self, nodes): self.nodes = nodes self.route = {} # rid -> node_id def assign(self, region): """把Region放到当前Region最少的节点并登记路由""" node = min(self.nodes, key=lambda n: n.count()) node.regions.append(region) self.route[region.rid] = node.node_id return node def route_to(self, key): """根据Key找到对应Region和所在节点""" for node in self.nodes: for r in node.regions: if r.in_range(key): return r, node raise KeyError("no region for key: %s" % key) def split(self, r): """Region分裂:一半数据留给原Region,一半交给新Region""" keys = sorted(r.data) mid = len(keys) // 2 split_key = keys[mid] new_r = Region(len(self.route) + 1, split_key, r.end) r.end = split_key for k in keys[mid:]: new_r.data[k] = r.data.pop(k) target = self.assign(new_r) print("[分裂] Region%d -> Region%d, 新Region放到TiKV%d" % (r.rid, new_r.rid, target.node_id)) def balance(self): """把Region最多的节点上的Region迁到最少的节点""" src = max(self.nodes, key=lambda n: n.count()) dst = min(self.nodes, key=lambda n: n.count()) if src.count() - dst.count() >= 2: moved = src.regions.pop() dst.regions.append(moved) self.route[moved.rid] = dst.node_id print("[调度] Region%d从TiKV%d迁到TiKV%d" % (moved.rid, src.node_id, dst.node_id)) def main(): nodes = [TiKVNode(1), TiKVNode(2), TiKVNode(3)] pd = PD(nodes) pd.assign(Region(1, 0, 10000)) for key in range(200): r, node = pd.route_to(key) need_split = r.put(key, "value_%d" % key) if need_split: pd.split(r) if key % 40 == 0: pd.balance() print("最终Region分布:") for n in nodes: rids = [r.rid for r in n.regions] print("TiKV%d: %d个Region %s" % (n.node_id, n.count(), rids)) if __name__ == "__main__": main()
class PD模拟调度中心,负责路由登记、分裂决策和迁移调度,对应真实 TiDB 中的 PD 组件。pd.route_to(key)根据 Key 范围找到对应 Region 和所在节点,模拟 PD 路由查找。r.put(key, "value_%d" % key)写入数据并判断 Region 是否超过容量上限,超限时返回 True 触发分裂。pd.split(r)把 Region 的 Key 从中间一分为二,一半数据留给旧 Region,一半归新 Region。pd.balance()比较各节点 Region 数量,把最忙节点的 Region 迁到最闲节点,模拟 PD 负载均衡。pd.assign(new_r)把新建 Region 放到当前 Region 最少的节点,模拟“新箱子放空仓库”的调度策略。
常见误区
误区TiDB 跟 ShardingSphere、MyCat 差不多吧?就是把 MySQL 拆成多库多表,应用层连一个代理,本质还是 MySQL。
正解分库分表中间件是“代理”,数据最终还是存在一堆 MySQL 实例里,事务、扩容、故障恢复都很难做好。TiDB 本身就是一个完整的分布式数据库:TiDB 节点负责计算,TiKV 负责存储,PD 负责调度,数据以 Region 为单位打散在多台机器上,自带分布式事务、自动分裂和故障自愈。它不是在 MySQL 外面套壳,而是从底层重新设计的数据库。
为何常见:TiDB 兼容 MySQL 协议,很多工具链和连接方式与 MySQL 一致,容易让人误以为它只是 MySQL 的一个转发层。
误区TiKV 存三份副本,那每次写入必须三个副本都写成功才能返回,不然数据会丢。
正解Raft 协议走的是多数派提交:三个副本只要两个确认(Leader + 一个 Follower),写入就能成功返回。第三副本慢一点、挂掉了都不影响写入。这既保证了数据不丢(多数派里总有最新数据),又避免了“等最慢节点”的延迟。代价是也只能容忍少数派故障——三副本最多挂一个,挂两个就写不了了。
为何常见:生活中“三份备份”通常意味着三份都写才算稳,人们习惯性地把“备份”和“全量确认”划等号。
误区PD 听起来像“数据库的大脑”,业务数据应该都存 PD 里,TiKV 只是缓存。
正解PD 只存元数据——Region 的位置、节点的心跳状态、调度策略、全局时间戳,不存任何业务数据。业务数据全部在 TiKV(行存)和 TiFlash(列存)里。类比起来,PD 是运营经理的台账本,台账只记录“箱子在哪里”,箱子本身在仓库里。元数据量很小但极其关键,PD 自己会组成一个小集群来保证可用性。
为何常见:大脑、中枢、调度中心这类词容易让人联想到“所有数据都汇聚于此”,忽略了它只管“地图”不管“货物”。
误区Region 太小会频繁分裂,那把默认 96MB 调成几个 GB,省事又省心。
正解Region 是数据调度和容灾的最小单位。Region 过大,一次分裂、迁移的数据量巨大,PD 调度时网络开销和影响面都会被放大;某节点宕机后,其他节点补副本也要传很久。保持适中的 Region(默认约 96MB)能让数据分布更细粒度地均衡,故障恢复更快,热点处理更灵活。
为何常见:人们容易类比“大箱子搬起来省事”,却忽略了数据库里“更小粒度 = 更灵活调度”的规律。
误区TiFlash 用列存,TiKV 用行存,那 TiFlash 是不是一个需要单独部署、单独同步数据的分析数据库?
正解TiFlash 是 TiDB 集群内的一个角色,不是外部系统。它作为 Raft Learner 自动从 TiKV 异步复制数据,同一个集群同时拥有行存和列存两种引擎,两边数据保持一致,用户不需要手动同步。查询优化器会自动判断:分析型大查询走 TiFlash,点查和写入走 TiKV,对外仍是一个数据库。
为何常见:传统架构里“行存库 + 分析库”是两套系统,需要 ETL 同步,这种惯性思维让人误以为 TiFlash 也是另一套独立数据库。
面试题
Q1. TiDB 架构中负责 SQL 解析与执行的是?
- A.TiKV 存储节点
- B.TiDB 计算节点← 正确答案
- C.PD 调度节点
- D.TiFlash 列存节点
答案:B。TiDB 节点相当于前厅的点单员和厨师,负责解析 SQL、生成执行计划并分发执行;TiKV 管存储,PD 管调度,TiFlash 管分析加速。选 B。
Q2. TiKV 中数据分片的基本单位是?
- A.表(Table)
- B.索引(Index)
- C.分区(Partition)
- D.区域(Region)← 正确答案
答案:D。TiKV 把数据按连续 Key 范围切成 Region,默认约 96MB,是复制、调度和容灾的最小单位。表和索引是逻辑概念,分区是 MySQL 的物理概念,都不是 TiKV 的分片单位。
Q3. 三副本 Raft 集群最多可容忍几个节点故障?
- A.零个节点故障
- B.一个节点故障← 正确答案
- C.两个节点故障
- D.三个节点故障
答案:B。Raft 多数派写入要求至少 F+1 个副本确认(三副本即 2 个)。三副本下最多容忍 1 个节点故障;挂掉 2 个,剩下 1 个凑不够多数派,就无法写入。公式 N=2F+1 中 F=1。
Q4. 下列哪项不是 PD 的职责?
- A.维护路由元数据
- B.分配全局时间戳
- C.存储业务数据← 正确答案
- D.调度 Region 副本
答案:C。PD 是运营经理,管台账(路由元数据)、盖章(全局时间戳)、调配(副本调度),但台账本不装货物——业务数据全部存在 TiKV 和 TiFlash 里。选 C。
Q5. 以下哪些属于 TiFlash 的特点?
- A.采用列式存储格式← 正确答案
- B.以 Raft Learner 身份同步← 正确答案
- C.加速复杂分析查询← 正确答案
- D.完全替代 TiKV 存储
答案:ABC。TiFlash 用列存服务分析查询,以 Raft Learner 身份异步复制 TiKV 数据,不参与投票所以不影响交易链路。它是 TiKV 的补充而非替代,写入主链路仍在 TiKV,所以 D 错。
Q6. 一个 Region 的默认数据量约为多少?
- A.约为 64 千字节
- B.约为 1 兆字节
- C.约为 96 兆字节← 正确答案
- D.约为 1 千兆字节
答案:C。默认 Region 约 96MB,类似仓库里统一规格的周转箱。这个大小让分裂、迁移、故障恢复的粒度适中。64KB 和 1MB 过小,1GB 过大,都不符合 TiDB 的默认设计。
Q7. TiFlash 如何从 TiKV 同步数据?
- A.以 Raft Leader 身份同步
- B.以 Raft Learner 身份同步← 正确答案
- C.通过应用层双写直连
- D.通过解析 binlog 同步
答案:B。TiFlash 作为 Raft Learner(学习副本)加入 Raft 组,被动接收日志并异步应用。它不参与投票,因此同步数据不会拖慢事务提交;也不需要应用双写或 binlog 解析,保持集群内数据天然一致。
Q8. TiDB 计算节点无状态设计的核心价值是什么?
- A.不存数据因此可弹性扩缩容← 正确答案
- B.不需要网络就能独立工作
- C.单节点可处理海量数据
- D.可完全替代存储节点
答案:A。无状态意味着 TiDB 节点不持久化业务数据,挂了一台,新的节点秒级顶上;并发高了,随时加节点分担请求。它仍需要网络访问 TiKV 和 PD,单机能力有限,也不可能替代存储层。
Q9. 以下属于 PD 调度能力的有?
- A.感知节点心跳状态← 正确答案
- B.自动迁移热点 Region← 正确答案
- C.直接执行 SQL 语句
- D.控制 Region 副本数量← 正确答案
答案:ABD。PD 通过心跳感知节点存活,通过负载统计迁移热点 Region,并控制每个 Region 的副本数量以维持容灾能力。执行 SQL 是 TiDB 计算层的职责,PD 不碰 SQL。
Q10. 关于 Region 分裂与合并的正确说法是?
- A.数据超限会自动触发分裂← 正确答案
- B.分裂让数据分布更细致← 正确答案
- C.合并会降低查询性能
- D.小 Region 合并减少元数据开销← 正确答案
答案:ABD。Region 超过容量会自动分裂成更小的 Region,让调度粒度更细;大量小 Region 会占用过多元数据内存与心跳流量,合并能降低开销、提升性能。因此 C 说“合降低性能”是反的,正确答案为 A、B、D。