我第一次翻开OceanBase官方文档的时候,脑子里只有一个念头:这些字我都认识,怎么放在一起就看不懂了?
Zone、OBServer、租户、Unit、资源池、MemTable、SSTable、转储、合并、分区、副本、日志流、Paxos、全局时间戳……每个词单独拎出来都能找到解释,但串在一起就变成了一场术语风暴。尤其是我当时正打算把一套业务从MySQL迁到OceanBase,又赶上准备面试,越看越焦虑——不是不想学,是真的不知道从哪里下手。
后来我发现,问题不在我,也不在文档,而是在于缺一张"地图"。所有的术语看似零散,实际上都挂在几条明确的主线上:数据怎么进来、怎么存下去、怎么复制多份、怎么保证一致、怎么对外服务。一旦把每条术语挂到对应的环节上,你会发现原来就这么点东西。
这篇我先不聊SQL调优,也不聊部署细节,就把OceanBase最核心的术语逐个拆开,用"说人话的类比 + 文字版图示 + 实际使用中的坑"的方式过一遍。这是系列的第一篇,目标是让你看完之后,再回头看官方文档或者面试题,能有一种"哦,原来它在说这个"的通透感。
1. 为什么OceanBase的术语让人头大:先画一张记忆地图
1.1 不是术语难,是缺了一张全局地图
我见过太多人学OceanBase的方式是打开官方文档的"术语表",从第一条背到最后一条。结果背了三天,合上文档,依然不知道这些术语之间的关系。
这就像你还没看过城市地图,就开始背街道名称。每一条路名你都认识,但你不知道哪条路通向哪里,也不知道自己在哪。真正有效的学习路径应该是:先看地图,再记地名。
所以我建议你先接受一个最简单的结论:OceanBase是一个分布式关系型数据库,它的所有术语都在回答四个问题。
- 数据放在哪里、怎么组织?(部署架构、存储引擎)
- 多台机器上的数据怎么保持一致?(一致性协议、日志流)
- 多个业务怎么共用一套集群而不互相干扰?(多租户、资源隔离)
- 我们普通用户和DBA怎么连上去操作?(接入层、运维工具)
1.2 把术语分拣到四个抽屉里
我习惯把OceanBase的术语分成四组,就像收拾房间一样,先分类再存放。
| 抽屉 | 回答什么问题 | 代表性术语 |
|---|---|---|
| 架构部署层 | 这套系统由哪些部分组成,跑在哪几台机器上 | 集群、Zone、OBServer、OBProxy、RootService |
| 资源管理层 | 多个业务怎么共用集群资源,如何隔离 | 租户、Unit、资源池、sys租户 |
| 存储引擎层 | 数据在单台机器内部怎么写、怎么存 | MemTable、SSTable、LSM-Tree、转储、合并 |
| 分布与一致性层 | 数据在多台机器之间怎么切片、怎么复制、怎么同步 | 分区、副本、日志流、Paxos、Primary Zone、全局时间戳 |
这四个抽屉就是你的记忆地图。看到一个陌生术语,先归类,再想它在哪个环节里起作用,理解成本直接降一半。
1.3 用一条请求链路串起所有术语
如果只看静态结构,还是会觉得术语之间是割裂的。所以我再给你一条动态链路,把大部分核心术语串起来。这是一条SQL写入请求从发起到落盘的完整路径:
text复制客户端
│
▼
OBProxy(无状态接入网关,做路由转发)
│
▼
OBServer(存储该数据分区的Leader副本所在节点)
│
├──► 事务层:申请全局时间戳(TSO),记录事务版本
│
├──► 日志层:先写Clog(提交日志),保证不丢
│
├──► 存储引擎:写入MemTable(内存中的写缓冲)
│
└──► 后台任务:转储 / 合并 → 刷到SSTable(磁盘上的只读文件)
│
▼
通过Paxos协议,把Clog同步给其他副本所在的OBServer
这条链路里,OBProxy是入口,OBServer是干活的人,MemTable和SSTable是数据的两种存放形态,Paxos和Clog负责让多台机器上的副本保持一致,TSO负责给事务排队。每一个术语都有了自己的位置,后面再逐个拆解时,你就不会觉得是一盘散沙。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 集群骨架:Zone、OBServer、RootService这些"地基术语"
2.1 Zone:可用区粒度的故障域
Zone是OceanBase集群里最容易被忽略、但其实最重要的概念。它的官方定义是"一个逻辑可用区",通俗点说,就是一组物理上隔离的机器集合。
为什么要搞出个"Zone"来?因为分布式数据库必须考虑机房故障。如果整个集群的所有机器都在同一间机房里,一旦机房断电或者网络故障,整个数据库就全挂了。所以OceanBase把物理机分成若干组,每组定义成一个Zone,通常一个Zone对应一个机房、或者一个机架、甚至一个独立的故障域。
画成文字示意图就是这样的:
text复制OB集群(Cluster)
├── Zone1(机房A)
│ ├── OBServer 1
│ └── OBServer 2
├── Zone2(机房B)
│ ├── OBServer 3
│ └── OBServer 4
└── Zone3(机房C)
├── OBServer 5
└── OBServer 6
你注意看,一个集群里有多个Zone,每个Zone里有多个OBServer。数据会同时存到三个Zone里,任何一个Zone整体挂掉,另外两个Zone依然有完整数据,集群照常服务。这就是Zone的使命:通过物理隔离来对抗机房级故障。
在实际部署里,最常见的形态就是三Zone,也就是常说的"三机房三副本"。这个"三"正是后面Paxos协议里的多数派基础——三副本中只要有两个活着,就能继续工作。
2.2 OBServer:一台机器上的数据库进程
OBServer是OceanBase的核心服务进程,跑在一台物理机或者一台虚拟机里。你要把它理解为"安装在每台机器上的数据库内核程序",一个Zone里可以部署多个OBServer。
我在学习的时候有过一个误解,以为OBServer像MySQL那样是一个独立的实例,每个实例有一套完整的数据。实际上完全不是。**OBServer只是一个计算和存储的节点,它存的是整个集群数据的一部分。**每个OBServer上可能承载了某些分区的Leader副本,也可能承载了另一些分区的Follower副本。数据按照分区规则打散到所有OBServer上。
所以,你不能说"连上某个OBServer就能看到全部数据"。从任何一个OBServer进去,它只负责处理与自己相关的分区数据,其他分区的请求会通过内部路由转发到对应的节点上。这个设计也是OceanBase能水平扩展的根本原因:数据不够分了,加机器,然后把一部分分区迁过去就完事。
2.3 RootService:藏在集群背后的"总调度室"
RootService(简称RS)是OceanBase集群的"总调度室"。它不是一个独立安装的进程,而是常驻在某个OBServer内部的一个模块,负责一系列全局管理动作。
- 管理集群里有哪些OBServer,谁活着谁挂了
- 维护分区与副本的位置信息,也就是"路由表"
- 做负载均衡,把热点分区从忙碌的节点迁到空闲的节点
- 处理DDL语句,比如建表、加索引
- 在节点故障时触发副本重新选举和补齐
在OceanBase 3.x及更早版本里,RootService通常独立部署或固定在某一个节点上;到了4.x版本,它的职责进一步被分散和模块化,但功能本质没有变。
我个人的体会是,RootService你不用跟它直接打交道,但你心里得知道:集群里这些"全局的事",都归它管。 比如你执行CREATE TABLE,这个请求最终会被路由到RootService,由它决定表的分区怎么创建、副本放到哪几个Zone、选哪个OBServer作为Leader。
2.4 OBProxy与OBClient:入口处的两道岗
OBProxy是OceanBase的接入网关。客户端不直接连OBServer,而是先连OBProxy,由OBProxy把SQL请求转发到合适的目标节点上。
为什么非要加这么一层?因为OceanBase的数据是分片存储在几十上百个OBServer上的,客户端根本不知道某个表的数据到底在哪个节点上。OBProxy就像一个前台接待员,你只需要把请求递给它,它会看内部的路由表,找到对应的分区Leader所在节点,把请求转过去。
OBClient则是一个命令行客户端工具,类似MySQL里的mysql命令行,负责把SQL发送给OBProxy或者直连OBServer。简单记:OBClient是"提词器",OBProxy是"前台",OBServer是"业务窗口"。
这里有一个面试或者实操中很容易被问到的细节:OBProxy默认端口是2883,OBServer直连端口是2881。客户端连接串支持jdbc:mysql://host:2883/dbname,也可以直连host:2881。但直连只适合调试,生产环境必须走OBProxy做路由和限流。
3. 租户与资源隔离:理解OceanBase多租户的核心钥匙
3.1 租户不是"一个数据库实例"
多租户是OceanBase最独特的设计之一,也是新手最容易卡壳的地方。很多人下意识把"租户"理解为MySQL里的"一个独立实例",但二者并不完全等价。
在OceanBase里,租户(Tenant)是一个逻辑资源容器。它拥有独立的账号体系、系统表、Schema、事务隔离级别,在应用看起来,它和一套独立的MySQL实例体验非常接近。但在物理层面,它并没有独占任何一台机器,而是和其他租户共享底层的所有OBServer资源。
我常用的类比是"合租一栋楼":集群是一栋楼,Zone是楼里的几个单元,租户就是公寓。每个公寓有自己独立的钥匙和装修风格,但水电暖这些公共基础设施是大家一起用的。你住你的,我住我的,互相看不见,也不会互相把对方的房间弄乱。
这种隔离的核心价值在于:一套OceanBase集群,可以同时给多个业务线使用,彼此互不干扰。 运维只需要维护一套集群,成本大幅下降。
3.2 Unit与资源池:资源是怎么切分和绑定的
租户说要跑在集群上,总得有CPU和内存吧?这就引出了Unit和资源池。
Unit是OceanBase里资源的最小分配单位,它规定了"分多少CPU、多少内存、多少磁盘空间"。你可以把它理解成一个"资源水杯",里面装着固定量的CPU和内存。而资源池(Resource Pool)就是一组Unit的集合。
租户、Unit、资源池之间的绑定关系是这样的:
text复制创建租户时:
指定一个资源池
资源池里包含若干Unit
每个Unit规定了CPU/内存规格
租户 = 若干Unit组成的资源池 + 独立的schema/数据
举个例子,假设集群有3个Zone,每个Zone上有1台OBServer。你给租户A创建了一个包含3个Unit的资源池,每个Unit分配4核8G,那么这3个Unit会被自动分布到3个Zone的机器上,每个Zone上的OBServer分到1个Unit。这样租户A跑起来时,在每个Zone里都能使用4核8G的资源。
为什么要这样设计?因为OceanBase是高可用数据库,数据是三副本的,每个Zone里都得有资源来跑这些副本。如果资源池只建在一个Zone里,另外两个Zone的副本没地方放,数据就没法做多副本保护。所以Unit的分布天然要和副本的分布对齐——这是分布式数据库资源分配和MySQL有本质区别的地方。
3.3 sys租户和普通租户:你该进哪个门
OceanBase集群创建完成后,默认会存在一个叫sys的特殊租户。它是集群的"物业办公室",拥有对整个集群的管理权限,不面向业务。
- sys租户:管理集群、创建租户、查看所有租户状态、调整参数
- 普通租户:业务数据运行的地方,每个租户互不可见
操作的时候用root用户连接sys租户,用户名通常是root@sys,指定集群名为#obcluster。一个容易搞混的点是连接串格式,OceanBase的用户名由"用户名@租户名"组成,连接集群时可能还要加上#集群名。例如:
text复制jdbc:mysql://host:2883/test_db?user=root@test_tenant#obcluster
如果你在MySQL里习惯了user=root,到OceanBase这儿忘了带租户名,大概率会报错,这个坑我踩过不止一次。
3.4 一个常见误解:租户数和MySQL实例数不能划等号
我在学习的时候曾经以为,一个租户就等价于一台MySQL实例,所以租户之间的资源是硬隔离的。这个理解有一定道理,但在OceanBase里,租户是可以水平扩展的。
如果租户A的资源不够了,你不需要像MySQL那样去加一台独立的服务器,直接修改资源池,扩大Unit的规格,或者增加Unit数量。OceanBase会自动把新增的资源分配到各个OBServer上,并通过副本迁移让数据分布重新均衡。
这套机制带来的直接结果就是:资源可以动态伸缩。业务流量大了,扩一下Unit;流量回落,再缩回来。整个过程对业务透明,这在传统主从架构里几乎不可想象。
4. 存储引擎术语图解:从MemTable到SSTable的LSM-Tree之旅
4.1 为什么OceanBase不用B+树做核心存储
MySQL的InnoDB用的是B+树,随机写性能一直是痛点。OceanBase从一开始就选择了LSM-Tree(Log-Structured Merge-Tree,日志结构合并树)作为核心存储模型。
我先说结论:LSM-Tree的核心思想是把随机写变成顺序写,把写性能做到极致,然后用定期合并的方式去补偿读性能和空间占用。
B+树的痛点在于,一个随机UPDATE可能需要写多个页面,每次写都是磁盘随机IO。而LSM-Tree的做法是,所有的写操作先进入内存,攒够一批后再顺序刷到磁盘。因为是顺序写,磁盘的吞吐效率高了好几个数量级。
理解了这个背景,下面这几个存储术语就顺理成章了。
4.2 MemTable:写入先到内存
MemTable是存储引擎的内存组件,所有新增、修改、删除操作会先落到这里。你可以把它看成一张"草稿纸",所有改动先写在上面,速度快,不落盘。
但只写在内存里是不安全的,万一断电就全丢了。所以在写入MemTable之前,OceanBase会把这条操作的Redo日志先写到Clog(Commit Log,提交日志)里。Clog是顺序写磁盘,速度很快。也就是说,先记日志,再改内存,这个顺序保证了数据不会因为宕机而丢失。
4.3 SSTable与基线数据:磁盘上的"只读大文件"
SSTable(Sorted String Table)是磁盘上的只读数据文件。MemTable攒到一定大小,就会被刷到磁盘,变成一个SSTable文件。和B+树的数据文件不同,SSTable的显著特点是不可变。
一旦SSTable落盘,里面的数据就固定下来了,不会更新,不会删除。那业务上的UPDATE和DELETE怎么办?它们会被当作新的操作继续写进MemTable,后续再生成新的SSTable。所以同一行数据,可能同时存在于多个SSTable里,只是版本不同。
所有SSTable合在一起,就是数据的"基线"。基线数据是静态的、只读的,后台合并任务会定期把新增的SSTable和旧的基线合并,形成一个更大的新SSTable。
4.4 转储与合并:两个让新手混淆的关键动作
转储和合并是OceanBase里最容易被搞混的两个术语,我拆开讲。
**转储(Minor Compaction)**是把当前MemTable的内存数据刷到磁盘,生成一个新的小型SSTable。它不改变已有的SSTable,只是单纯地释放内存空间,避免内存被写满。转储的代价比较小,可以频繁触发。
**合并(Major Compaction)**是把所有转储出来的小SSTable和已有的基线SSTable一起,重新整理成一个大的SSTable。合并的过程会清理历史版本数据、重新组织索引,同时推进全局版本号。合并的代价比较大,通常默认每天触发一次。
我用一个图书馆来类比。转储就是你每天看完书把笔记写进一个草稿本,草稿本写满了就放到书架上,不整理。合并则是每隔一段时间,把所有草稿本和正本书籍统一重新排版、印刷成一本完整的新书。转储追求快,合追求整理。
| 对比项 | 转储 | 合并 |
|---|---|---|
| 触发频率 | 高,MemTable满就触发 | 低,通常每日一次或手动触发 |
| 代价 | 小,只刷内存数据 | 大,整理所有SSTable |
| 对读性能影响 | 轻微 | 完成后显著提升 |
| 对空间影响 | 可能增加文件数 | 减少文件数、清理冗余版本 |
| 全局版本号 | 不推进 | 推进 |
4.5 一次性理清:写放大、读放大与空间放大
聊存储引擎,躲不开三个"放大"。这是面试高频题,也是理解LSM-Tree设计取舍的关键。
- 写放大:逻辑上只更新一行数据,但实际写到磁盘的数据量远大于一行。LSM-Tree因为用顺序写,总体上写放大比B+树可控,但合并时仍然会重写大量数据。
- 读放大:因为同一行数据可能存在于多个SSTable里,读一条数据时可能需要翻查多个SSTable才能找到最新版本。解决手段是加布隆过滤器、分区索引、以及定期合并减少文件数量。
- 空间放大:多个SSTable里保存了同一份数据的不同版本和删除标记,占用的磁盘空间比实际有效数据大。合并能够回收这些冗余空间。
我的建议是不要死记三个放大的定义,而是记住一句话:LSM-Tree用空间换写性能,再用后台合并来补偿读性能和空间开销。 这三个放大效应正是OceanBase合并机制存在的根本原因。
5. 分区、副本与日志流:数据在分布式系统里如何安家
5.1 分区:一张大表怎么切成小片
OceanBase里一张表的数据量可能大到单台机器根本放不下,所以要把表按某种规则水平切分成多个小片,每一片就是一个分区(Partition)。
分区的切分方式有几种:
- Range分区:按某个键的范围切,比如按用户ID从1到1000、1001到2000
- Hash分区:按某个键的哈希值散列到不同分区
- List分区:按枚举值列表切分
- 组合分区:上述方式组合使用
分区规则在建表时指定,比如:
sql复制CREATE TABLE orders (
tenant_id NUMBER NOT NULL,
order_id NUMBER NOT NULL,
order_date DATE NOT NULL
)
PARTITION BY RANGE(order_date) (
PARTITION p_2024 VALUES LESS THAN (TO_DATE('2025-01-01','YYYY-MM-DD')),
PARTITION p_2025 VALUES LESS THAN (TO_DATE('2026-01-01','YYYY-MM-DD'))
);
分区让"表"从逻辑上被拆散,分散到集群不同的机器上。这样单表不再受单机磁盘和CPU上限的约束,并行查询也能同时跑在多个节点上。
5.2 Tablet和副本:从逻辑分片到物理拷贝
在OceanBase 4.x版本里,你还会经常看到Tablet这个概念。简单理解,Tablet是分区的物理载体,一个分区对应一个Tablet,Tablet上承载了实际的数据文件、SSTable和日志流。
分区是逻辑命名,Tablet是实际存放在OBServer里的物理实体。聊业务时我们说"这个表有多少个分区",聊实现机制时我们说"这个Tablet在哪些节点上有副本"。
副本则是同一个Tablet在多个节点上的物理拷贝。因为单机不可靠,所以每个Tablet的数据需要存在多份,分布在不同的Zone和不同的OBServer上。任何一个副本坏了,其他副本顶上。
副本类型通常有三种:
| 副本类型 | 是否参与投票 | 是否有完整数据 | 是否能被选为Leader | 用途 |
|---|---|---|---|---|
| Paxos副本(全能型) | 是 | 是 | 是 | 默认的读写副本 |
| 日志副本 | 是 | 否,只存日志 | 否 | 参与多数派、节省空间 |
| 只读副本 | 否 | 是 | 否 | 扩展读能力、不参与投票 |
大多数生产环境用的是全功能型副本,也就是Paxos副本,兼顾读写和高可用。
5.3 日志流:副本之间靠什么保持同步
有了多份副本,必须有一个机制让它们的数据始终一致。这个机制在OceanBase里的核心载体就是日志流(Log Stream)。
日志流可以理解为一组持续增长的Redo日志序列,记录了Tablet上所有的修改操作。当业务写入Leader副本时,Leader会把操作日志实时同步给Follower副本。Follower收到日志、重放日志,数据就和Leader保持一致了。
这里有一个关键点:不是每个SSTable文件都有一套日志流,而是一组Tablet共享一个日志流。OceanBase把多个相关的Tablet组合在一起,共享一个日志流,这样写入时只需要同步一份日志,效率更高。在4.x版本里,默认一个分区组对应一个日志流,日志流再和Paxos组绑定。
text复制Tablet A ─┐
├──► 共享日志流 LogStream 1 ──► 通过Paxos同步到各副本
Tablet B ─┘
5.4 副本类型与Primary Zone:谁来写、谁来读
副本之间不是完全平等的。每个Tablet的副本中,会有一个Leader,其余是Follower。所有写操作都发给Leader,由Leader把日志同步给多数派(即多数Follower)后返回成功,Follower则在后台追日志。读操作默认也走Leader,这样能保证读到最新数据。
Primary Zone控制的是Leader的位置偏好。假设你的集群有Zone1、Zone2、Zone3三个Zone,如果表的主Zone是Zone1,那么这张表所有分区的Leader副本都会优先落在Zone1,业务流量就打到了Zone1所在的机房。
这个设计非常实用。比如两地三中心部署:主用机房在A,灾备机房在B,那么把主Zone设为A,日常流量都走A机房。A机房挂了,Leader自动迁移到B机房,业务再切换过来,实现容灾。
5.5 "2-2-2架构"和Paxos组:一张图看懂高可用
OceanBase官方经常提到"2-2-2"部署架构,意思是三个Zone,每个Zone两台OBServer,一共六台机器。每个Tablet在这三个Zone里各存一个副本,三个副本构成一个Paxos组。
text复制Tablet-X 的副本分布:
Zone1(机房A) Zone2(机房B) Zone3(机房C)
OBServer1: Leader OBServer3: Follower OBServer5: Follower
OBServer2: 其他 OBServer4: 其他 OBServer6: 其他
三个副本中有一个Leader,两个Follower。写入一条数据时,Leader把日志发给两个Follower,只要有一个Follower确认收到,加上Leader自己,构成"3副本中的2个确认",就算多数派写入成功。
多数派机制的妙处在于:只要不是超过一个副本同时挂掉,集群就能正常服务。 单机故障、单机房断网都能扛住。这也是为什么OceanBase敢说"满足金融级高可用"的原因。
6. 事务与一致性术语:Paxos、选举、全局时间戳到底在干嘛
6.1 Paxos:会议室里的少数服从多数
Paxos是分布式系统领域的一个共识算法,OceanBase用它来让所有副本对"数据的值"达成一致。你不用背算法的全部细节,只需要理解它的核心思想:一个提案需要获得多数派的同意才生效。
我把Paxos想象成开会投票:Leader提出"我要把A的值改成100",然后把提案发给其他参会者。只要超过半数的参会者同意,提案就通过,大家按这个值执行。即使有人中途掉线,只要多数派还在,会议就能继续开下去。
这个"多数派"就是分布式系统高可用的数学基础。三副本能容忍一副本故障,五副本能容忍两副本故障,再多副本没有意义,因为同步成本太高、收益却不变。
6.2 选举与切主:主副本挂了会怎样
在一个Paxos组里,Leader坏了怎么办?答案是通过选举产生新Leader。
选举的大致流程是:Follower发现自己长时间没有收到Leader的心跳,就发起新一轮Paxos选举,投自己一票,同时请求其他副本支持。获得多数派投票的节点成为新Leader,然后继续对外提供服务。整个切主过程通常在秒级完成,业务会有短暂的写不可用,但不会丢数据。
对于开发人员来说,最直观的感受是:数据库连接可能被断开,重连之后客户端可能需要更新路由信息。 所以OceanBase的驱动和OBProxy会自动感知Leader切换,把新请求转发给新Leader。
6.3 全局时间戳:让分布式事务看起来像单机事务
单机数据库给每个事务分配一个递增的时间戳,事务之间天然有顺序。但在分布式数据库里,事务可能发生在不同的节点上,Global TSO(全局时间戳)就是用来给所有跨节点事务"排序"的。
你可以把TSO理解成一个发号器:所有事务启动前先向TSO服务申请一个全局递增的时间戳,作为这个事务的版本号。有了全局统一的版本号,其他事务在判断"这个数据我能看到吗"时,就有了统一的参考标准。
这里就引出了MVCC(多版本并发控制)。每一次修改都会生成一个新版本的数据,旧版本不会被立刻覆盖。读操作根据事务的版本号判断应该看到哪个版本的数据。这样读和写互不阻塞,写和写之间通过锁来串行化,大大提升了并发能力。
这也是OceanBase能同时保证强一致和高性能的一个关键设计。面试官如果问"OceanBase怎么实现分布式事务",你提TSO和MVCC,基本就答到点子上了。
6.4 分布式事务的两阶段提交:跨节点写入的"双保险"
当一个事务修改的数据分布在多个节点上时,就不能只靠本地事务了。OceanBase采用两阶段提交(2PC)来保证跨节点事务的原子性。
两阶段提交的"两阶段"分别是:
- 准备阶段:协调者问所有参与者"能不能提交"?参与者执行本地操作,写Undo日志,锁定资源,然后回答"准备好了"。
- 提交阶段:协调者收到所有参与者的"准备好了"后,通知所有参与者"正式提交"。如果有任何一个参与者说"不行",协调者就通知所有人"回滚"。
这样做的目的是避免"一半节点提交了、一半节点没提交"的情况。哪怕执行过程中某个节点宕机,协调者也能根据已有信息决定全局是提交还是回滚。
OceanBase对标准的2PC做了很多优化,比如将日志和事务状态合并,减少网络交互次数。这也是它在高并发场景下事务性能依然能打的原因之一。不过你作为使用者,只需要记住一点:跨节点写入是有额外协调开销的,所以设计表时尽量把相关数据放在同一个Tablet或同一个租户内,能显著减少分布式事务。
7. 面试、实操常碰到的术语联想题:从术语到动手
7.1 面试官问"OceanBase架构"时,他想听到什么
我看了不少OceanBase面试题,发现大部分人在架构题上挂掉,不是因为不懂术语,而是回答没有层次感,东一榔头西一棒子。
我建议按四层结构去组织答案:
- 第一层:接入层。客户端通过OBProxy接入,OBProxy做协议解析和路由转发。
- 第二层:服务层。OBServer是核心节点,承载SQL引擎、事务引擎、存储引擎。多个OBServer构成一个集群,数据按分区打散。
- 第三层:存储层。每台OBServer内部用LSM-Tree存储数据,写入先到MemTable,后台转储和合并到SSTable。
- 第四层:一致性层。每个分区的多副本组成Paxos组,Leader负责读写,日志通过日志流同步,多数派确认机制保证高可用。
按这个顺序讲,面试官能感觉到你对整个系统有全局认知。然后再根据追问展开到租户隔离、TSO、合并机制等细节,既系统又不散。
7.2 datagrip连接OceanBase:OBProxy起了什么作用
很多人在网上搜"datagrip连接oceanbase",说明用IDEA家工具连OceanBase也是新手绕不开的实操问题。其实连接配置很直接,关键是要理解连接串里的每个参数对应什么概念。
text复制JDBC URL:
jdbc:mysql://127.0.0.1:2883/test_db?useSSL=false&connectTimeout=5000
用户名: root@test_tenant#obcluster
密码: 对应租户的root密码
这里有几个容易踩的坑:
- 端口2883是OBProxy端口,2881是直连OBServer端口。如果你用2881连,可能只能访问该节点上的部分数据,虽然本地测试通常没问题,但生产环境一定走OBProxy。
- 用户名格式是"用户名@租户名#集群名",三个部分缺一不可。如果你只写root,驱动不知道你要进哪个租户,连接会被拒绝。
- MySQL驱动和OceanBase驱动都可以用,但OceanBase官方推荐使用兼容MySQL协议的高版本驱动,避免某些特性不兼容。
我在本机测试时还遇到过一个诡异问题:用MySQL Connector/J 5.1连接报"Unknown system variable 'transaction_isolation'",换成MySQL Connector/J 8.0就正常了。所以连接过程的Terminology坑往往不是概念本身,而是生态兼容性。
7.3 压测工具/运维工具与术语的关系
热搜里还有"oceanbase压测工具",说明很多人已经开始动手实测了。主要压测方式是用sysbench这类通用工具,配合BenchmarkSQL做TPC-C测试。但压测之前,有一些术语层面的准备容易忽略。
第一是租户资源。压测前要确认测试租户的Unit规格是否足够,如果资源池过小,压测结果会显示CPU和IO很快达到瓶颈,但这并不真实反映数据库能力。
第二是分区设计。如果压测表没有合理分区,数据会集中在一个Tablet上,读写只能压到一台OBServer上,整个集群的其他节点都在围观。合理分区、合理分布,压测才有意义。
第三是观察合并。压测过程中如果触发合并,读写性能会出现明显波动。所以专业压测一般会在测试前手动触发一次合并,让数据文件固定在整齐的基线状态,再开始打流量。
7.4 口头禅级别的几个术语速查表
最后给你一份速查表,是我自己看完文档后做的精简版,面试前翻一遍非常管用。
| 术语 | 一句话解释 | 常见误解 |
|---|---|---|
| Zone | 一组物理隔离的机器,对应一个故障域 | 以为Zone就是一台机器 |
| OBServer | 跑在每台机器上的数据库内核进程 | 以为是一个独立数据库实例 |
| 租户 | 逻辑资源容器,拥有独立数据和账号体系 | 以为是一个物理MySQL实例 |
| Unit | CPU/内存的规格单位,租户资源的最小切片 | 忘记Unit分布要跟随副本分布 |
| MemTable | LSM-Tree的内存写缓冲 | 以为数据直接写磁盘 |
| SSTable | 磁盘上的只读数据文件,不可变 | 以为可以直接更新里面某一行 |
| 转储 | MemTable刷成小SSTable,释放内存 | 和合并混为一谈 |
| 合并 | 所有SSTable整理成新基线,清理版本 | 以为会阻塞读写(实际有优化) |
| 分区 | 表按规则水平切分出的逻辑片 | 和分表中间件划等号 |
| 副本 | 同一Tablet在多个节点上的数据备份 | 以为副本只有一份 |
| 日志流 | 一组Tablet共享的Redo日志序列 | 和Binlog混为一谈 |
| Paxos | 多数派共识协议,保证副本一致 | 以为和传统主从同步一样 |
| Primary Zone | 指定Leader优先落在哪个Zone | 忘记它是管理流量位置的关键参数 |
| TSO | 全局递增时间戳,给事务排序 | 以为只有一个全局锁 |
我自己的学习体会是,这套术语看起来多,但只要你先画好"五个层次"的框架——接入层、服务层、资源层、存储层、一致性层——大部分新词都能自己找到位置。遇到不懂的,先问一句"它在哪个环节工作、解决什么问题",答案往往自己就浮出水面了。
后面我打算继续写这个系列,把SQL路由、合并带来的性能抖动、租户参数调优这些更深入的场景逐个拆开。先把这篇的术语地图记牢,再看那些内容,你会顺畅很多。
