首页 > 数据库 > 国内数据库 > OceanBase 读写分离配置指南(SOP+回滚)
单 OBProxy 入口、事务内强读走 Leader、事务外只读走弱读并路由到 Follower。
OB 通过 弱一致性读将只读请求路由到 Follower 副本,写请求始终走 Leader 强一致性。
ODP 提供两种自动读写分离模式:
| 模式 | 参数 | 行为 | 推荐度 |
|---|---|---|---|
| 基础读写分离 |
enable_read_write_split=true |
仅将事务外的读请求(包括
autocommit=1 的单条查询)自动视为弱读并路由到副本。一旦进入显式事务(如执行了
BEGIN 或
START TRANSACTION),后续所有读写请求均发往主库。 |
推荐 |
| 事务拆分读写分离 |
enable_transaction_split=true |
在显式事务内部,如果读请求位于 DML 语句之前,ODP 也会将其视为弱读并路由到副本 | 不推荐 |
基础读写分离严格保证了事务内的数据强一致性,避免了因主备延迟导致的「读不到自己刚写入的数据」等问题,兼顾了性能与安全,是生产环境的推荐选择。
事务拆分读写分离存在数据一致性风险。由于副本同步可能存在延迟,事务内读取到的可能是旧数据,导致业务逻辑基于过期数据进行判断或计算,进而引发数据错误。仅在能容忍短暂不一致且对事务内读性能有极端要求的特殊场景下才考虑使用。
BEGINautocommit=1SELECT例如:
SELECT *
FROM order_table
WHERE
id =
100;
这种查询通常是:
它和后面的写没有绑定关系,所以可以让它走 Follower。
就是:
BEGIN 了autocommit=0SELECT 和后面的
UPDATE 属于同一个业务动作
BEGIN;
SELECT balance
FROM
account
WHERE
id =
1;
UPDATE
account
SET balance = balance -
100
WHERE
id =
1;
COMMIT;
这是一个完整业务:
这时第一条
SELECT 不能随便走 Follower,因为:
UPDATE 却在 Leader 上按旧值计算所以事务里的读,必须走强读,去 Leader。
proxy_route_policy=FOLLOWER_FIRST
前面说的是:这条 SQL 是强读还是弱读。
这个参数说的是: 如果是弱读,优先发给谁?
FOLLOWER_FIRST 的意思是:弱读请求优先路由到 Follower,只有备库不可用时,才回退到 Leader。
所以
proxy_route_policy 和
enable_read_write_split 是配合关系:
enable_read_write_split:决定「哪些读可以弱读」proxy_route_policy:决定「弱读优先找谁」。
只对「已经被判定为弱读」的 SQL 生效。比如这个环境:
一条弱读 SQL 来了以后,理论上可以发给:
FOLLOWER_FIRST 就是在说:
先在 Follower 里挑,不要一上来就选 Leader。
当
proxy_route_policy=FOLLOWER_FIRST 时,路由优先级为:
> Region(odp 与 observer 同 region)> 主备角色(先 follower 后 leader)> 合并状态(弱读优先选不在合并中的副本)> IDC(odp 优先选择同机房的副本)
ob_read_consistency=strong
这个参数是 OB 租户级默认读一致性。
这里容易误会:既然要做读写分离,为什么还把
ob_read_consistency 设成
strong?
原因是:
也就是说: 不是把整个租户都改成弱读,而是默认强读,只对符合条件的查询自动弱读。
适用于:业务通过同一 OBProxy 接入,事务内强读、事务外自动弱读。
-- OBProxy 配置
ALTER PROXYCONFIG
SET enable_read_write_split =
true;
ALTER PROXYCONFIG
SET proxy_route_policy =
'FOLLOWER_FIRST';
无需额外设置弱读参数;开启读写分离后,OBProxy 自动将事务外读请求视为弱读。
ALTER PROXYCONFIG
SET enable_transaction_split =
true;
ALTER PROXYCONFIG
SET proxy_route_policy =
'FOLLOWER_FIRST';
-- OB 内核参数
ALTER
SYSTEM
SET ob_proxy_readonly_transaction_routing_policy =
false TENANT =
'tenant_name';
风险: 事务内、DML 之前的读也会走 Follower,可能出现数据不一致,生产环境不建议开启。
| 项目 | 配置 |
|---|---|
| 副本拓扑 | 2F1A(2 个 FULL Follower + 1 个 FULL Leader) |
| Primary Zone | zone1(Leader 所在 Zone) |
| 弱读目标 Zone | zone2(Follower) |
| 接入方式 | 同一 OBProxy 节点处理读写分离 |
预期行为:
-- ① 开启基础读写分离,事务外普通 select 自动当弱读,写、事务内读、select for update 仍然走强读
ALTER PROXYCONFIG
SET enable_read_write_split =
true;
-- ② 备优先读路由策略。当一条 SQL 已经被判定为弱读后,决定优先发给谁。
-- FOLLOWER_FIRST = 弱读优先找 Follower,备库不行才回退 Leader
ALTER PROXYCONFIG
SET proxy_route_policy =
'FOLLOWER_FIRST';
-- ③ 关闭连接缓存(SQL 无法解析时避免复用 Leader 连接)。
-- 正常情况下,OBProxy 解析 SQL 后,知道该连哪台 OBServer。但有些复杂 SQL 解析不出表名时,OBProxy 会走兜底逻辑:
ALTER PROXYCONFIG
SET enable_cached_server =
false;
-- ④ 关闭 Primary Zone 路由(避免登录时固定到 Leader)
ALTER PROXYCONFIG
SET enable_primary_zone =
false;
-- ⑤ 代理层保持强读默认(由读写分离逻辑自动改写事务外读为弱读)
ALTER PROXYCONFIG
SET obproxy_read_consistency =
0;
-- ⑥ LDC:将 proxy_idc_name 设置为弱读 Zone 的 IDC
ALTER PROXYCONFIG
SET proxy_idc_name =
'IDC2';
-- 对应 zone2
-- 租户变量:保持强读默认
ALTER TENANT tenant_name
SET
VARIABLES ob_read_consistency =
'STRONG';
-- 内核参数:事务内 BEGIN 后的只读语句视为事务内读(不走弱读拆分)
ALTER
SYSTEM
SET ob_proxy_readonly_transaction_routing_policy =
false TENANT =
'tenant_name';
-- zone1(Leader Zone)
ALTER
SYSTEM
MODIFY ZONE zone1
SET REGION =
'Region1';
ALTER
SYSTEM
MODIFY ZONE zone1
SET IDC =
'IDC1';
-- zone2(弱读目标 Zone)
ALTER
SYSTEM
MODIFY ZONE zone2
SET REGION =
'Region2';
ALTER
SYSTEM
MODIFY ZONE zone2
SET IDC =
'IDC2';
-- 验证
SELECT zone,
name, info
FROM __all_zone
WHERE
name
IN (
'region',
'idc');
SHOW PROXYINFO IDC;
当存在 复杂 SQL 无法解析表名时,OBProxy 无法判断弱读副本位置,会将所有 Zone 视为 Follower 并随机路由。
弱读路由兜底优先级:
处理方式(二选一):
方式 1:统一 IDC 指向弱读 Zone(传统方案)
-- 所有 OBProxy 节点的 proxy_idc_name 均设为弱读 Zone 的 IDC
ALTER PROXYCONFIG
SET proxy_idc_name =
'IDC2';
ALTER PROXYCONFIG
SET enable_cached_server =
false;
-- 必须关闭
方式 2:指定副本类型路由(OBProxy ≥ 4.3.2,推荐)
ALTER PROXYCONFIG
SET route_target_replica_type =
'Full;Readonly';
-- 无需再手动对齐 region/idc
避免强读 SQL 因复制表等同 IDC 路由误发到 Follower,产生大量 Remote 计划:
ALTER PROXYCONFIG
SET enable_ob_protocol_v2 =
true;
-- 默认 True
ALTER PROXYCONFIG
SET enable_reroute =
true;
-- 默认 False,建议开启
ALTER PROXYCONFIG
SET enable_index_route =
true;
-- 默认 False,建议开启
| 节点 | IP | Region | IDC | 角色 |
|---|---|---|---|---|
| zone1 | 172.20.5.171 | Region1 | IDC1 | Follower |
| zone2 | 172.20.5.170 | Region2 | IDC2 | Leader |
| zone3 | 172.20.5.175 | Region1 | IDC1 | Follower |
| OBProxy | - | - | IDC1 | 代理 |
-- 租户 Primary Zone
ALTER TENANT tenant_name PRIMARY_ZONE =
'zone2;zone1,zone3';
-- ========== OBProxy ==========
ALTER PROXYCONFIG
SET enable_read_write_split =
true;
ALTER PROXYCONFIG
SET proxy_route_policy =
'FOLLOWER_FIRST';
ALTER PROXYCONFIG
SET enable_cached_server =
false;
ALTER PROXYCONFIG
SET enable_primary_zone =
false;
ALTER PROXYCONFIG
SET obproxy_read_consistency =
0;
ALTER PROXYCONFIG
SET proxy_idc_name =
'IDC2';
-- 弱读 Zone 的 IDC
-- ========== OB 租户 ==========
ALTER TENANT tenant_name
SET
VARIABLES ob_read_consistency =
'STRONG';
ALTER
SYSTEM
SET ob_proxy_readonly_transaction_routing_policy =
false TENANT =
'tenant_name';
-- 1. 确认副本分布与 Leader 位置
SELECT svr_ip,
role,
COUNT(*)
FROM oceanbase.DBA_OB_TABLE_LOCATIONS
WHERE tenant_id =
GROUP
BY svr_ip,
role;
-- 2. 确认 Primary Zone
SELECT tenant_name, primary_zone
FROM oceanbase.DBA_OB_TENANTS;
-- 3. 确认当前 OBProxy 配置
SHOW PROXYCONFIG
LIKE
'%read_write%';
SHOW PROXYCONFIG
LIKE
'%route_policy%';
SHOW PROXYCONFIG
LIKE
'%cached_server%';
SHOW PROXYCONFIG
LIKE
'%proxy_idc%';
SHOW PROXYINFO IDC;
-- 4. 确认 Zone LDC
SELECT zone,
name, info
FROM oceanbase.__all_zone
WHERE
name
IN (
'region',
'idc');
-- 按第三节顺序逐项配置
-- 建议:先在测试环境验证,再单 OBProxy 节点灰度,最后全量
-- 1. 事务外弱读验证
SELECT
/*+READ_CONSISTENCY(WEAK)*/ *
FROM test_table
LIMIT
1;
-- 2. 查看 SQL 审计中的 consistency_level
SELECT trace_id, svr_ip, consistency_level, query_sql
FROM oceanbase.GV$OB_SQL_AUDIT
WHERE tenant_id =
ORDER
BY request_time
DESC
LIMIT
20;
-- 3. 确认弱读落到 Follower 节点
-- consistency_level = 2 表示弱读
-- svr_ip 应为 Follower 所在 IP(如 172.20.5.171 / 172.20.5.175)
-- 4. 事务内强读验证
BEGIN;
SELECT *
FROM test_table
LIMIT
1;
-- 应路由到 Leader (172.20.5.170)
COMMIT;
-- 5. 检查 Remote 计划比例(应较低)
SELECT plan_type,
COUNT(*)
FROM oceanbase.GV$OB_SQL_AUDIT
WHERE tenant_id =
AND request_time > DATE_SUB(NOW(), INTERVAL 1 HOUR)
GROUP BY plan_type;
| 监控项 | 预期 | 异常处理 |
|---|---|---|
| Leader CPU/内存 | 事务负载集中 | 正常 |
| Follower CPU/内存 | 报表/查询负载集中 | 正常 |
| Remote 计划比例 | < 5% | 检查
enable_reroute、IDC 配置 |
| 弱读延迟 | <
max_stale_time_for_weak_consistency(默认 5s) |
检查副本同步 |
| 主副本误接收弱读流量 | 应为 0 | 检查
enable_cached_server |
| 参数 | 层级 | 推荐值 | 说明 |
|---|---|---|---|
enable_read_write_split |
OBProxy |
true |
开启基础读写分离 |
enable_transaction_split |
OBProxy |
false |
不开启事务拆分 |
proxy_route_policy |
OBProxy |
FOLLOWER_FIRST |
备优先读 |
enable_cached_server |
OBProxy |
false |
关闭连接缓存,避免解析失败时粘 Leader |
enable_primary_zone |
OBProxy |
false |
避免登录固定到 Leader |
obproxy_read_consistency |
OBProxy |
0 |
0=强读(由读写分离自动改写) |
proxy_idc_name |
OBProxy | 弱读 Zone 的 IDC | LDC 就近路由 |
route_target_replica_type |
OBProxy |
Full;Readonly |
4.3.2+ 可替代 IDC 对齐 |
ob_read_consistency |
租户 |
STRONG |
默认强读,事务内保持强读 |
ob_proxy_readonly_transaction_routing_policy |
租户 |
false |
BEGIN 后只读视为事务内读 |
原因:
enable_cached_server=true 且
enable_primary_zone=true 时,登录连到 Leader 后,无法解析的 SQL 会复用该连接。
处理:
ALTER PROXYCONFIG
SET enable_cached_server =
false;
ALTER PROXYCONFIG
SET enable_primary_zone =
false;
原因: OBProxy 无法解析表名,所有 Zone 被视为 Follower,随机路由。
处理:
proxy_idc_name 为弱读 Zone 的 IDCenable_cached_server=falseroute_target_replica_type='Full;Readonly'
原因:
proxy_idc_name 与 Follower 同 IDC,复制表走路由
same_idc 策略。
处理: 开启
enable_reroute=true,并观察 Remote 计划比例。
enable_read_write_split?
BIP 生产优先在应用层通过
/*+READ_CONSISTENCY(WEAK)*/ Hint 显式指定弱读,而非依赖 OBProxy 自动拆分。若必须使用自动拆分,需充分测试复杂 SQL 的路由行为,并接受弱读一致性风险。
-- 关闭读写分离,恢复默认路由
ALTER PROXYCONFIG
SET enable_read_write_split =
false;
ALTER PROXYCONFIG
SET proxy_route_policy =
'';
ALTER PROXYCONFIG
SET enable_cached_server =
true;
ALTER PROXYCONFIG
SET enable_primary_zone =
true;
-- 验证所有请求回到 Leader
SELECT svr_ip,
role,
COUNT(*)
FROM oceanbase.GV$OB_SQL_AUDIT
WHERE tenant_id =
AND request_time > DATE_SUB(NOW(), INTERVAL 10 MINUTE)
GROUP BY svr_ip;
如果在操作过程中遇到问题,欢迎在评论区留言交流,后续我们会持续分享更多实战运维干货,记得 关注不迷路 ,下次见~
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047467/viewspace-3178914/ ,如需转载,请注明出处,否则将追究法律责任。