引言
OBProxy,即OceanBase Database Proxy,也简称为ODP,是 OceanBase数据库的专属服务代理。通过应用OBProxy,由后端OceanBase集群的分布式特性所带来的复杂性得以屏蔽,从而使得访问分布式数据库的体验如同访问单机数据库一般容易。
OBProxy的核心特性是最佳路由,基本逻辑就是ODP 接收用户发出的 SQL 请求,并将 SQL 请求转发至最佳目标 OBServer 节点,最后将执行结果返回给用户。为了满足客户在不同场景下的路由需求,实现最佳的路由效果,OBPrxoy 支持丰富的路由功能,这就涉及到路由配置项的设置及组合,本文基于业务中一类常见的路由问题展开,对路由功能及对应配置项做详细介绍,指导用户在业务实践中如何正确的配置路由策略及快速排查路由问题。
路由问题
问题描述
只读地址访问到主副本
云客户通过租户的只读地址执行大查询获取数据,结果访问到了主副本,影响了主副本的正常业务。
原因分析
开启了 enable_cached_server 和 enable_primary_zone
在设置 obproxy 的参数 enable_primary_zone = true 和 enable_cached_server =true 的情况下,路由逻辑:
enable_primary_zone= true,用户登录时,会将登录请求发往租户的主副本
enable_cached_server =true,在OBProxy没有解析出表名、表分区计算失败等情况下,请求会复用前一个连接,也就是登录时选择的主副本,这就导致请求无法根据只读地址信息对路由做优化,造成后续的所有请求都发往了主副本。
解决方法
关闭 enable_cached_server 和 enable_primary_zone
路由功能
OBProxy提供了丰富的路由功能,用户可以根据实际需要,设置对应的配置项来控制各种路由策略。
强制路由
- 指定IP路由:target_db_server ,OBProxy 将请求直接路由到指定的 OBServer,具有最高优先级,示例:
ALTER PROXYCONFIG SET target_db_server = '127.0.0.1:2993;11.124.5.193:50109';
OBProxy收到的所有请求都会路由到127.0.0.1:2993,如果127.0.0.1:2993节点不存在或者故障,则路由到11.124.5.193:50109
2. 指定zone路由:proxy_primary_zone_name,OBProxy 将请求直接路由到指定的 zone,示例:
ALTER PROXYCONFIG SET proxy_primary_zone_name='z2';
OBProxy收到的所有请求都会路由到 z2
指定IP路由和指定zone路由,是强制性的路由,不会区分是否强读,适用于不关心Leader位置,需要路由到指定节点的场景。
如果是交易支付等强读业务,希望路由到Leader的场景,需要保强制路由配置项没有设置,避免产生大量远程路由、二次路由等问题。
3. 特定场景强制路由
- 非分布式事务路由,事务内语句强制路由至事务开启 OBServer 节点
- 会话级临时表路由,对会话级临时表进行查询时,会强制路由至第一次查询临时表的 OBServer 节点
- CURSOR/PIECES 路由,客户端使用 CURSOR/PIECES 流式获取/上传数据时,所有请求会强制路由至同一 OBServer 节点
强读路由
- 分区表路由
OBProxy 将 SQL 请求中的分区键值或表达式、分区名等条件解析为分区 ID,通过分区 ID 查找到分区的副本位置,将请求路由到Leader副本。
根据分区键值/表达式计算路由,示例:
CREATE TABLE T(C1 INT) PARTITION BY HASH(C1) PARTITIONS 8;
SELECT * FROM T WHERE C1=123;
SELECT * FROM T WHERE C1=ABS(123);
OBProxy将查询请求路由到对应分区Leader节点
根据分区名计算路由,示例:
CREATE TABLE T(C1 INT) PARTITION BY KEY(C1) PARTITIONS 8;
SELECT * FROM T PARTITION(P1);
OBProxy将查询请求路由到P1分区的Leader节点
在 OceanBase 数据库中,有 Local 计划、Remote 计划和 Distributed 计划三种表路由。Local 计划、Remote 计划均为单分区的路由。ODP 的作用就是尽量消除 Remote 计划,将路由尽可能的变为 Local 计划。如果表路由类型为 Remote 计划的 SQL 过多,说明该 ODP 的路由可能存在问题,需要排查。
2. 全局索引表路由
配置enable_reroute 和enable_index_route ,OBProxy 将语句中提供的索引值作为分区键来计算路由,示例:
ALTER PROXYCONFIG SET enable_reroute=true;
ALTER PROXYCONFIG SET enable_index_route = true;
CREATE TABLE T(C1 INT,C2 INT) PARTITION BY HASH(C1) PARTITIONS 8;
CREATE INDEX INDEX1 ON T(C2);
SELECT * FROM T WHERE C2=2;
SELECT * FROM T WHERE C2=2;
第一次使用索引查询,将随机路由,OBServer 将返回索引表的 Leader,OBProxy 会构建语句到索引表名称 [SELECT * FROM T WHERE C2=2;] -> [T_INDEX] 的映射
然后进行二次路由,直接获取 T_INDEX 表的映射,计算路由
3. 复制表路由
OBProxy对复制表采用随机路由的策略。示例:
CREATE TABLE T_DUP(C1 INT) DUPLICATE_SCOPE = 'cluster';
SELECT * FROM T_DUP WHERE C1=123;
OBProxy将查询请求随机路由到T_DUP表的任意副本
4. 计算失败后的路由
当OBProxy 无法获取SQL请求中的表名或者无法通过SQL请求中的条件计算出准确的分区位置信息时,无法准确的强读请求路由到Leader。此时有三种处理策略:
- 按照租户primary zone路由:enable_primary_zone=True,将请求路由到租户的primary zone
- 复用上一次的会话路由:enable_cached_server =true,将请求路由到上一个observer会话
- 随机路由:enable_primary_zone=false 且 enable_cached_server =false,将请求随机路由
示例:
场景一:enable_primary_zone=false && enable_cached_server =true
CREATE TABLE T(C1 INT,C2 INT) PARTITION BY HASH(C1) PARTITIONS 8;
SELECT * FROM T WHERE C1=1; 请求准确路由到server1
SELECT * FROM T WHERE C2=1; 无分区条件,无法计算路由,直接将请求路由到上一个会话server1
SELECT * FROM T WHERE C1=2; 请求准确路由到server2
SELECT * FROM T WHERE C2=2; 无分区条件,无法计算路由,直接将请求路由到上一个会话server2
场景一:enable_primary_zone=true && enable_cached_server =true && leader在server1
SELECT * FROM T WHERE C1=1; 请求准确路由到server1
SELECT * FROM T WHERE C2=1; 无分区条件,无法计算路由,直接将请求路由到server1
SELECT * FROM T WHERE C1=2; 请求准确路由到server1
SELECT * FROM T WHERE C2=2; 无分区条件,无法计算路由,直接将请求路由到server1
生产和测试环境,一般情况下,建议enable_cached_server设置为false
如果需要分析 OBProxy 的路由策略,可以使用 EXPLAIN ROUTE executable sql 查看 OBProxy路由选取过程。
事务路由
事务路由分两种场景:
- 分布式事务路由(OceanBase4.1开始支持),事务内的SQL请求准确路由到Leader节点。
配置enable_ob_protocol_v2=true 且 enable_transaction_INTernal_routing = true,示例:
ALTER PROXYCONFIG SET enable_ob_protocol_v2 = true;
ALTER PROXYCONFIG SET enable_transaction_INTernal_routing = true;
CREATE TABLE T1(C1 INT,C2 INT) PARTITION BY HASH(C1) PARTITIONS 8;
CREATE TABLE T2(C1 INT,C2 INT) PARTITION BY HASH(C1) PARTITIONS 8;
BEGIN;
INSERT INTO T1 VALUES(1,1);路由到server1
INSERT INTO T2 VALUES(11,11);路由到server2
SELECT * FROM T1 WHERE C1=1;路由到server1
SELECT * FROM T2 WHERE C1=11;路由到server2
COMMIT;
事务内的请求都能够准确路由到对应的Leader
- 非分布式事务路由,事务内SQL请求强制路由至事务开启 OBServer 节点
ALTER PROXYCONFIG SET enable_ob_protocol_v2 = false;
ALTER PROXYCONFIG SET enable_transaction_INTernal_routing = false;
CREATE TABLE T1(C1 INT,C2 INT) PARTITION BY HASH(C1) PARTITIONS 8;
CREATE TABLE T2(C1 INT,C2 INT) PARTITION BY HASH(C1) PARTITIONS 8;
BEGIN;
INSERT INTO T1 VALUES(1,1);路由到server1
INSERT INTO T2 VALUES(11,11);路由到server1
SELECT * FROM T1 WHERE C1=1;路由到server1
SELECT * FROM T2 WHERE C1=11;路由到server1
COMMIT;
事务内的请求都路由到第一条INSERT的路由节点server1
弱读路由
OBProxy对弱读请求,有两种路由策略:
- LDC路由,给 OceanBase 集群的每个 Zone 设置地区(Region)属性和机房(IDC)属性,并给 OBProxy 指定机房(IDC)配置项,OBProxy 将 弱读请求按“同机房>同地区>异地”的优先级顺序进行 OBServer 的选取。 通过配置项 proxy_idc_name 控制。 示例:
alter system modify zone "z1" set region = "region1";
alter system modify zone "z1" set idc = "idc1";
alter system modify zone "z2" set region = "region1";
alter system modify zone "z2" set idc = "idc2";
alter proxyconfig set proxy_idc_name='idc1';
CREATE TABLE T(C1 INT,C2 INT) PARTITION BY HASH(C1) PARTITIONS 8;
SELECT /*+READ_CONSISTENCY(WEAK) */ * FROM T;
OBProxy会将弱读请求路由到同idc的z1
- 随机路由,OBProxy将弱读请求随机路由到Leader或者Follower副本,副本优先级由proxy_route_policy控制。对应路由策略:FOLLOWER_FIRST、 FOLLOWER_ONLY、 UNMERGE_FOLLOWER_FIRST。示例:
CREATE TABLE T(C1 INT,C2 INT) PARTITION BY HASH(C1) PARTITIONS 8;
#T表的leader在z1,follower在z2、z3
场景一:alter proxyconfig set proxy_route_policy='';
SELECT /*+READ_CONSISTENCY(WEAK) */ * FROM T;
OBProxy在z1、z2、z3 三个副本随机选择副本转发弱读请求
场景二:alter proxyconfig set proxy_route_policy='FOLLOWER_FIRST';
SELECT /*+READ_CONSISTENCY(WEAK) */ * FROM T;
OBProxy优先选择z2、z3 转发弱读请求,如果z2、z3都不可用,则转发到z1
场景三:alter proxyconfig set proxy_route_policy='FOLLOWER_ONLY';
SELECT /*+READ_CONSISTENCY(WEAK) */ * FROM T;
OBProxy只选择z2、z3 转发弱读请求,如果z2、z3都不可用,则请求报错
场景四:alter proxyconfig set proxy_route_policy='UNMERGE_FOLLOWER_FIRST';
SELECT /*+READ_CONSISTENCY(WEAK) */ * FROM T;
OBProxy优先选择没在做合并的z2、z3 转发弱读请求
LDC路由的优先级高于随机路由,OBProxy在选择副本的时候,先检查LDC路由,再走随机路由策略。
弱读的路由策略 LDC路由和随机路由,同样适用于计算分区失败的强读路由请求
典型场景
在不同的业务场景,需要综合考虑路由策略配置及优先级,合理配置,来实现指定的路由目标。下面以两个典型路由场景为例,介绍路由功能的应用实践。
读写分离
- 路由场景
OLTP与OLAP业务混合负载场景下,希望将交易类请求发送到TP副本,将分析型请求发送到AP副本,TP、AP类业务请求需要部署独立的OBProxy,接收AP请求的OBProxy 需要支持将业务的强读请求转换为弱读,并只发送到AP副本。部署架构如图:
- 路由配置实践
接收AP请求的OBProxy:
设置弱读:alter proxyconfig set obproxy_read_consistency='1';
设置路由目标副本:alter proxyconfig set proxy_primary_zone_name='zone_4';
注意:
确保没有设置过指定ip路由的配置,show proxyconfig like 'target_db_server';
接受TP请求的OBProxy:
ALTER PROXYCONFIG SET enable_cached_server = false;
ALTER PROXYCONFIG SET enable_primary_zone = true;
对交易类请求,需要准确路由到分区Leader,如果无法准确计算,则尽力路由到租户的primary zone,减少远程路由
OBProxy将交易类请求只发往ZONE_1、ZONE_2、ZONE_3的对应Leader副本
注意:
确保没有设置过指定ip路由及指定zone路由
show proxyconfig like 'target_db_server';
show proxyconfig like 'proxy_primary_zone_name';
只读副本
- 路由场景
OceanBase支持的副本类型,除了全功能型副本,还有只读型副本,简称R副本,R副本只提供读能力,只能作为日志流的 Follower 副本,实际业务中,可以将实时性要求不高的分析类读请求发送到R副本,减轻Leader 副本的压力。
- 路由配置实践
设置弱读:alter proxyconfig set obproxy_read_consistency='1';
设置LDC策略:只读副本同IDC的OBProxy和OBServer设置为相同IDC
设置路由策略:alter proxyconfig set proxy_route_policy='FOLLOWER_ONLY';