放弃手动分库分表吧!OceanBase 这一招,让 DBA 准时下班成了日常
作者: ShunWah 公众号: "shunwah星辰数智社"主理人。 持有认证: OceanBase OBCA/OBCP、MySQL OCP、OpenGauss、崖山YCA、金仓KingBase KCA/KCP、KaiwuDB KWCA/KWCP、 亚信 AntDBCA、翰高 HDCA、GBase 8a/8c/8s、Galaxybase GBCA、Neo4j ScienceCertification、NebulaGraph NGCI/NGCP、东方通TongTech TCPE、TiDB PCTA等多项权威认证。
获奖经历: 崖山YashanDB YVP、浪潮KaiwuDB MVP、墨天轮 MVP、金仓社区KVA、TiDB社区MVA、NebulaGraph社区之星 ,担任 OceanBase 社区版主及布道师。曾在OceanBase&墨天轮征文大赛、OpenGauss、TiDB、YashanDB、Kingbase、KWDB、Navicat Premium × 金仓数据库征文等赛事中多次斩获一、二、三等奖,原创技术文章常年被墨天轮、CSDN、ITPUB 等平台首页推荐。
前言:从一场播客说起
凌晨两点的告警、业务上线前夜的紧急扩容、跨库事务排查到眼花——这是无数 DBA 与"分库分表"长期相伴的日常。近期在聆听 OceanBase CTO 杨传辉(花名日照)关于数据安全"终极保障"的播客,以及研读日照老师对"原生分布式"的技术解读后,我对"分布式"这一术语有了全新的认识:它不再只是一个听起来很酷的名词,而是数据库内核层面真正解决海量数据扩展难题的架构能力。
OceanBase 官方明确将"无需分库分表满足业务敏捷性"列为其核心能力之一:原生分布式架构自动完成数据分片与事务管理,应用可以像使用单机数据库一样使用分布式能力。本文将结合 OceanBase 4.3 的实践,分享我对"原生分布式"概念的理解,并详细演示从零构建分区表、跨分区事务到动态扩容的完整链路,同时总结几条容易踩坑的实践经验。
一、OceanBase 原生分布式概述
OceanBase 数据库作为原生分布式数据库,区别于集中式数据库,其分区是独立的存储、高可用、事务单位,表的不同分区可以分布于不同服务器上,利用多机性能加快大表查询速度。同时,OceanBase 的原生分布式能力使应用程序可以像调用单机数据库一样使用,减少业务改造成本。
OceanBase 数据库采用 Shared-Nothing 架构,按日志流、分片组织用户数据。Tablet 具备存储数据的能力,支持在机器之间迁移,是数据均衡的最小单位。在分布式环境下,为保证数据读写服务的高可用,OceanBase 会把同一个日志流的数据拷贝到多个机器,称为副本。同一日志流的多个副本使用 Paxos 一致性协议保证副本的强一致,主副本具备强一致性读和写能力,从副本具备弱一致性读能力。
分区:数据分布的核心机制
在 OceanBase 中,分区是用户创建的逻辑对象,每个分区对应一个物理存储对象。OceanBase 支持多种分区策略,包括 HASH、RANGE 和 LIST 等,满足不同业务场景的需求:
- 按时间范围(RANGE)划分订单表:适合日志、流水类按时间演进的数据
- 按用户 ID 的哈希值(HASH)分布数据:适合实现负载均衡
-
支持二级分区:例如先按用户 ID 划分为一级分区,再按月份划分为二级分区
分区对业务完全透明,用户无需修改现有 SQL 查询即可使用分区功能。这种设计既保留了关系数据库的易用性,又实现了分布式系统的扩展性。
二、从零构建分区表实践
OceanBase 通过"自动分片"机制,让数据按分区键自动分片,存储层透明处理路由,无需业务层手动分库分表。
1、使用 root 用户登录集群的 sys 租户
[root@iZbp1h19y65t4hrdwapxz9Z ~]# obclient -h127.0.0.1 -uroot@sys -P2881 -Doceanbase -A
Welcome to the OceanBase. Commands end with ; or \g.
Your OceanBase connection id is 3221487617
Server version: OceanBase_CE 4.2.1.0 (r100000102023092807-7b0f43693565654bb1d7343f728bc2013dfff959) (Built Sep 28 2023 07:25:28)
obclient [oceanbase]>
2、创建数据库与分区表
2.1 创建数据库
obclient [oceanbase]> CREATE DATABASE ob_ecommerce;
Query OK, 1 row affected (0.021 sec)
2.2 创建订单表(按用户 ID 哈希分片,4 个分区)
obclient [oceanbase]> CREATE TABLE orders (
order_id BIGINT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
product_id INT,
amount DECIMAL(10,2),
order_time DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(order_id, user_id) -- 分区键需包含在主键中
) PARTITION BY HASH(user_id) PARTITIONS 4;
Query OK, 0 rows affected (0.106 sec)
2.3 创建日志表(按时间范围分片)
obclient [oceanbase]> CREATE TABLE user_behavior (
log_id BIGINT AUTO_INCREMENT,
user_id INT,
action VARCHAR(50),
log_time DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(log_id, log_time)
) PARTITION BY RANGE COLUMNS(log_time) (
PARTITION p202301 VALUES LESS THAN ('2023-02-01'),
PARTITION p202302 VALUES LESS THAN ('2023-03-01'),
PARTITION p202303 VALUES LESS THAN ('2023-04-01')
);
Query OK, 0 rows affected (0.046 sec)
3、插入数据并验证分布
3.1 插入订单数据(自动路由到对应 Hash 分区)
obclient [oceanbase]> INSERT INTO orders (user_id, product_id, amount) VALUES
(1001, 202, 99.99),
(1002, 305, 199.99),
(1003, 101, 50.00);
Query OK, 3 rows affected (0.020 sec)
3.2 查询数据分布
obclient [oceanbase]> SELECT partition_name, table_rows
FROM information_schema.partitions
WHERE table_name = 'orders';
数据会根据 Hash(user_id) 自动分布到对应分区。
4、执行跨分区分布式事务
OceanBase 原生支持跨分区事务,无需业务层引入额外的事务协调器:
obclient [oceanbase]> BEGIN;
Query OK, 0 rows affected (0.000 sec)
obclient [oceanbase]> UPDATE orders SET amount = 150 WHERE user_id = 1001;
Query OK, 0 rows affected (0.002 sec)
obclient [oceanbase]> INSERT INTO user_behavior (user_id, action, log_time)
VALUES (1001, 'update_amount', '2023-01-15 10:00:00');
Query OK, 1 row affected (0.001 sec)
obclient [oceanbase]> COMMIT;
Query OK, 0 rows affected (0.001 sec)
三、分区策略进阶测试
1、Hash 分区:均匀分布的利器
适合需要均匀分布的场景,例如按用户 ID 哈希分布数据:
obclient [oceanbase]> CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(255),
description TEXT,
price DECIMAL(10, 2)
) PARTITION BY HASH(id) PARTITIONS 4;
Query OK, 0 rows affected (0.136 sec)
2、Range + Hash 二级分区:时间维度+用户维度的组合
适合处理超大规模数据表,例如用户账单:
obclient [my_database]> CREATE TABLE user_bill (
user_id INT,
create_time DATETIME,
bill_amount DECIMAL(10, 2),
PRIMARY KEY (user_id, create_time)
)
PARTITION BY RANGE (TO_DAYS(create_time))
SUBPARTITION BY HASH (user_id)
SUBPARTITIONS 4
(
PARTITION p0 VALUES LESS THAN (TO_DAYS('2023-01-01')),
PARTITION p1 VALUES LESS THAN (TO_DAYS('2024-01-01')),
PARTITION p2 VALUES LESS THAN (TO_DAYS('2025-01-01'))
);
Query OK, 0 rows affected (0.098 sec)
- 一级分区:使用 TO_DAYS(create_time) 将 DATETIME 转换为天数,便于 RANGE 分区
- 二级分区:每个一级分区再按 user_id 哈希拆分为 4 个子分区
3、联合主键分区
分区键必须包含在主键中,这是 OceanBase 分区表的硬性约束:
obclient [oceanbase]> CREATE TABLE user_orders (
order_id BIGINT,
user_id BIGINT,
amount DECIMAL(10,2),
PRIMARY KEY(order_id, user_id)
) PARTITION BY HASH(user_id) PARTITIONS 4;
Query OK, 0 rows affected (0.126 sec)
通过 DBA_OB_TABLE_LOCATIONS 系统视图可查看分区物理分布,验证分区的 Leader 位置和副本状态:
obclient [oceanbase]> SELECT * FROM oceanbase.DBA_OB_TABLE_LOCATIONS
WHERE TABLE_NAME='USER_ORDERS';
四、动态扩容与分区管理
1、Range 分区的追加扩容
对于 Range 分区,可在线追加未来时间段的分区:
obclient [oceanbase]> ALTER TABLE user_behavior
ADD PARTITION (
PARTITION p202304 VALUES LESS THAN ('2023-05-01'),
PARTITION p202305 VALUES LESS THAN ('2023-06-01')
);
Query OK, 0 rows affected (0.050 sec)
仅对新写入数据生效,历史数据仍保留在原分区,无需数据迁移,操作简单。
2、Hash 分区扩容的注意事项
Hash/Key 分区无法直接在线增加分区数量。可通过 ALTER TABLE … PARTITION BY 语句重新定义分区数,但这属于分区重建操作:
obclient [oceanbase]> ALTER TABLE orders PARTITION BY HASH(user_id) PARTITIONS 6;
Query OK, 0 rows affected (0.589 sec)
重要提醒:官方文档明确指出"分区表在表创建的时候需要指定,后续不支持将非分区表在线改造成分区表,也不支持分区数量、分区类型、分区键值的在线调整"。上述语句在数据量较小的测试环境中执行成功,生产环境中请务必:
- 提前规划好分区数量
- 大表执行前在测试环境充分验证
- 优先使用 Table Group(表组)进行分区管理
3、查看扩容后分布
obclient [oceanbase]> SELECT partition_name FROM information_schema.partitions
WHERE table_name = 'orders';
五、避坑指南:实践中的关键要点
结合实践,以下是几条容易踩坑的经验总结:
1. 分区键必须包含在主键中
OceanBase 要求"建分区表时,表上的每一个主键、唯一键所对应的字段里都必须至少有一个字段包含在表的分区键字段中"。如果分区键不在主键中,创建会失败。这也是为什么在订单表示例中,主键定义为 PRIMARY KEY(order_id, user_id)——分区键 user_id 必须包含在主键里。
2. Hash 分区不适合基于分区字段进行范围查询
官方文档明确指出"hash 分区下,不适合基于分区字段进行范围查询"。如果业务有大量基于时间或 ID 的范围查询,应优先选择 Range 分区。例如订单按时间查询频繁,则用 PARTITION BY RANGE(order_time) 而非 Hash。
3. 跨分区事务的代价
虽然 OceanBase 原生支持跨分区分布式事务,但跨分区操作仍会引入额外的协调开销。实践中,通过合理设计分区键让相关数据尽量落在同一分区,可以减少跨机操作。善用 Table Group 技术:如果多张表通过各自的分区键进行关联,且分区策略一致,可以把多张表放到一个表组中提高关联效率,让同号分区的 Leader 尽量调度在同一机器,有效减少跨机访问开销。
4. 分区数量无法在线调整
正如前文避坑提醒所言,OceanBase 官方文档不支持分区数量、分区类型、分区键值的在线调整。Hash 分区的分区数在创建时确定,后续修改属于分区重建。生产扩容建议:
- Range 分区通过 ADD PARTITION 追加新分区
- Hash 分区提前规划,或通过 Table Group 管理分区分布
- 真正的水平扩容依赖集群节点增加,OceanBase 会自动进行 Tablet 的迁移与负载均衡,无需业务干预
5. TABLEGROUP 提升分区关联性能
对于需要频繁 JOIN 的表,创建相同分区策略的 Table Group 可实现 Partition Wise Join,避免跨节点数据传输:
CREATE TABLEGROUP tg_orders SHARDING = 'ADAPTIVE';
CREATE TABLE orders (...) TABLEGROUP = tg_orders PARTITION BY HASH(user_id) PARTITIONS 4;
CREATE TABLE order_detail (...) TABLEGROUP = tg_orders PARTITION BY HASH(user_id) PARTITIONS 4;
六、总结
从业务层手动分库分表,到数据库内核原生分布式,海量数据管理正在经历一场范式转移。OceanBase 通过分区、表组、日志流和 Paxos 副本机制,将分布式复杂性封装在数据库内部,让 DBA 从繁琐的分片路由、扩容迁移和跨库事务协调中解放出来,把精力聚焦在业务数据治理和性能优化本身。当数据库具备了原生分布式能力,"准时下班"自然从奢望变成了日常。
参考资源:
- OceanBase 官方文档:分区概述与分区表设计
- OceanBase 解决方案:无需分库分表
- OceanBase 官方博客:原生分布式从根源解决分库分表难题