联系我们
18591797788
hubin@rlctech.com
北京市海淀区中关村南大街乙12号院天作国际B座1708室
18681942657
lvyuan@rlctech.com
上海市浦东新区商城路660号乐凯大厦26c-1
18049488781
xieyi@rlctech.com
广州市越秀区东风东路华宫大厦808号1608房
029-81109312
service@rlctech.com
西安市高新区天谷七路996号西安国家数字出版基地C座501
单 OBProxy 入口、事务内强读走 Leader、事务外只读走弱读并路由到 Follower。
OB 通过弱一致性读将只读请求路由到 Follower 副本,写请求始终走 Leader 强一致性。
ODP 提供两种自动读写分离模式:
| 模式 | 参数 | 行为 | 推荐度 |
|---|---|---|---|
| 基础读写分离 | enable_read_write_split=true |
仅将事务外的读请求(包括 autocommit=1 的单条查询)自动视为弱读并路由到副本。一旦进入显式事务(如执行了 BEGIN 或 START TRANSACTION),后续所有读写请求均发往主库。 |
推荐 |
| 事务拆分读写分离 | enable_transaction_split=true |
在显式事务内部,如果读请求位于 DML 语句之前,ODP 也会将其视为弱读并路由到副本 | 不推荐 |
基础读写分离严格保证了事务内的数据强一致性,避免了因主备延迟导致的「读不到自己刚写入的数据」等问题,兼顾了性能与安全,是生产环境的推荐选择。
事务拆分读写分离存在数据一致性风险。由于副本同步可能存在延迟,事务内读取到的可能是旧数据,导致业务逻辑基于过期数据进行判断或计算,进而引发数据错误。仅在能容忍短暂不一致且对事务内读性能有极端要求的特殊场景下才考虑使用。
BEGIN
autocommit=1
SELECT
例如:
SELECT * FROM order_table WHERE id = 100;
这种查询通常是:
它和后面的写没有绑定关系,所以可以让它走 Follower。
就是:
BEGIN 了autocommit=0
SELECT 和后面的 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=false
route_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;