1 Star 0 Fork 0

OceanBase / tutorials-doc

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
3.7-2-obproxy-sql-routing-principles.md 30.82 KB
一键复制 编辑 原始数据 按行查看 历史
obdev 提交于 2023-08-07 12:38 . PullRequest: 39 常用词扫描

7.2 ODP SQL 路由原理

ODP 的主要功能是提供 SQL 路由。所以要先了解数据的位置,再了解 SQL 路由策略。

查看租户资源单元位置

租户的资源通常分布在每个 Zone 的机器上。租户的数据就在租户资源所在的机器上。集群规模很大的时候,每个租户可能只是在部分机器上。ODP 首先需要知道租户的位置(LOCATION CACHE)。

如下有 2 种方法可以确认租户的位置:

  • sys 租户直接查询

    select t1.name resource_pool_name, t2.`name` unit_config_name, t2.max_cpu, t2.min_cpu, round(t2.max_memory/1024/1024/1024) max_mem_gb, round(t2.min_memory/1024/1024/1024) min_mem_gb, t3.unit_id, t3.zone, concat(t3.svr_ip,':',t3.`svr_port`) observer,t4.tenant_id, t4.tenant_name
    from __all_resource_pool t1 join __all_unit_config t2 on (t1.unit_config_id=t2.unit_config_id)
        join __all_unit t3 on (t1.`resource_pool_id` = t3.`resource_pool_id`)
        left join __all_tenant t4 on (t1.tenant_id=t4.tenant_id)
    order by t1.`resource_pool_id`, t2.`unit_config_id`, t3.unit_id
    ;

    输出:

    +--------------------+------------------+---------+---------+------------+------------+---------+-------+--------------------+-----------+-------------+
    | resource_pool_name | unit_config_name | max_cpu | min_cpu | max_mem_gb | min_mem_gb | unit_id | zone  | observer           | tenant_id | tenant_name |
    +--------------------+------------------+---------+---------+------------+------------+---------+-------+--------------------+-----------+-------------+
    | sys_pool           | sys_unit_config  |       5 |       5 |          2 |          2 |       1 | zone1 | 172.20.249.52:2882 |         1 | sys         |
    | sys_pool           | sys_unit_config  |       5 |       5 |          2 |          2 |       2 | zone2 | 172.20.249.49:2882 |         1 | sys         |
    | sys_pool           | sys_unit_config  |       5 |       5 |          2 |          2 |       3 | zone3 | 172.20.249.51:2882 |         1 | sys         |
    | my_pool_zone1      | unit1            |       9 |       9 |         19 |         19 |    1001 | zone1 | 172.20.249.52:2882 |      1002 | obmysql     |
    | my_pool_zone2      | unit1            |       9 |       9 |         19 |         19 |    1002 | zone2 | 172.20.249.49:2882 |      1002 | obmysql     |
    | my_pool_zone3      | unit1            |       9 |       9 |         19 |         19 |    1003 | zone3 | 172.20.249.51:2882 |      1002 | obmysql     |
    +--------------------+------------------+---------+---------+------------+------------+---------+-------+--------------------+-----------+-------------+
    6 rows in set (0.008 sec)
  • 业务租户直接查询

    select tenant_name, unit_id, unit_config_name, resource_pool_name, zone, svr_ip ,max_cpu,min_cpu,round(max_memory/1024/1024/1024) max_mem_gb,round(min_memory/1024/1024/1024) min_mem_gb
    from gv$unit 
    WHERE tenant_id=1002;

    输出:

    +-------------+---------+------------------+--------------------+-------+---------------+---------+---------+------------+------------+
    | tenant_name | unit_id | unit_config_name | resource_pool_name | zone  | svr_ip        | max_cpu | min_cpu | max_mem_gb | min_mem_gb |
    +-------------+---------+------------------+--------------------+-------+---------------+---------+---------+------------+------------+
    | obmysql     |    1001 | unit1            | my_pool_zone1      | zone1 | 172.20.249.52 |       9 |       9 |         19 |         19 |
    | obmysql     |    1002 | unit1            | my_pool_zone2      | zone2 | 172.20.249.49 |       9 |       9 |         19 |         19 |
    | obmysql     |    1003 | unit1            | my_pool_zone3      | zone3 | 172.20.249.51 |       9 |       9 |         19 |         19 |
    +-------------+---------+------------------+--------------------+-------+---------------+---------+---------+------------+------------+
    3 rows in set (0.031 sec)

    在业务租户里,条件 tenant_id=1002 也可以不用,因为每个业务租户只能查看自己的租户资源单元信息。

说明

直连 OBServer 节点时,如果该 OBServer 节点上没有这个租户的资源单元,连接会报错。

查看分区副本位置

每个租户的分区都是从租户的资源单元中分配的。以下 SQL 可以在 sys 租户里查看租户中所有数据库的主副本位置。

SELECT  a.tenant_name, t.table_name, d.database_name,  tg.tablegroup_name , t.part_num , t2.partition_id, t2.ZONE, t2.svr_ip , round(t2.data_size/1024/1024/1024) data_size_gb
 , IF(t.primary_zone = '' OR t.primary_zone IS NULL, a.primary_zone, t.primary_zone) primary_zone
FROM oceanbase.__all_tenant AS a  
 JOIN oceanbase.__all_virtual_database AS d ON ( a.tenant_id = d.tenant_id  ) 
 JOIN oceanbase.__all_virtual_table AS t  ON (t.tenant_id = d.tenant_id AND t.database_id = d.database_id) 
 JOIN oceanbase.__all_virtual_meta_table t2 ON (t.tenant_id = t2.tenant_id AND (t.table_id=t2.table_id OR t.tablegroup_id=t2.table_id)  AND t2.ROLE IN (1) )
 LEFT JOIN oceanbase.__all_virtual_tablegroup AS tg ON (t.tenant_id = tg.tenant_id and  t.tablegroup_id = tg.tablegroup_id) 
WHERE a.tenant_id IN (1002 ) AND  t.table_type IN (3)  
 AND d.database_name IN ( 'tpccdb')
ORDER BY t.tenant_id, tg.tablegroup_name, d.database_name, t.table_name, t2.partition_id
;

输出:

+-------------+------------------+---------------+-----------------+----------+--------------+-------+---------------+--------------+-------------------+
| tenant_name | table_name       | database_name | tablegroup_name | part_num | partition_id | ZONE  | svr_ip        | data_size_gb | primary_zone      |
+-------------+------------------+---------------+-----------------+----------+--------------+-------+---------------+--------------+-------------------+
| obmysql     | bmsql_config     | tpccdb        | NULL            |        1 |            0 | zone2 | 172.20.249.49 |            0 | zone2;zone1,zone3 |
| obmysql     | bmsql_item       | tpccdb        | NULL            |        1 |            0 | zone1 | 172.20.249.52 |            0 | zone1;zone2,zone3 |
| obmysql     | bmsql_customer   | tpccdb        | tpcc_group      |        3 |            0 | zone2 | 172.20.249.49 |            0 | RANDOM            |
| obmysql     | bmsql_customer   | tpccdb        | tpcc_group      |        3 |            1 | zone1 | 172.20.249.52 |            0 | RANDOM            |
| obmysql     | bmsql_customer   | tpccdb        | tpcc_group      |        3 |            2 | zone3 | 172.20.249.51 |            0 | RANDOM            |
| obmysql     | bmsql_district   | tpccdb        | tpcc_group      |        3 |            0 | zone2 | 172.20.249.49 |            0 | RANDOM            |
| obmysql     | bmsql_district   | tpccdb        | tpcc_group      |        3 |            1 | zone1 | 172.20.249.52 |            0 | RANDOM            |
| obmysql     | bmsql_district   | tpccdb        | tpcc_group      |        3 |            2 | zone3 | 172.20.249.51 |            0 | RANDOM            |
| obmysql     | bmsql_history    | tpccdb        | tpcc_group      |        3 |            0 | zone2 | 172.20.249.49 |            0 | RANDOM            |
| obmysql     | bmsql_history    | tpccdb        | tpcc_group      |        3 |            1 | zone1 | 172.20.249.52 |            0 | RANDOM            |
| obmysql     | bmsql_history    | tpccdb        | tpcc_group      |        3 |            2 | zone3 | 172.20.249.51 |            0 | RANDOM            |
| obmysql     | bmsql_new_order  | tpccdb        | tpcc_group      |        3 |            0 | zone2 | 172.20.249.49 |            0 | RANDOM            |
| obmysql     | bmsql_new_order  | tpccdb        | tpcc_group      |        3 |            1 | zone1 | 172.20.249.52 |            0 | RANDOM            |
| obmysql     | bmsql_new_order  | tpccdb        | tpcc_group      |        3 |            2 | zone3 | 172.20.249.51 |            0 | RANDOM            |
| obmysql     | bmsql_oorder     | tpccdb        | tpcc_group      |        3 |            0 | zone2 | 172.20.249.49 |            0 | RANDOM            |
| obmysql     | bmsql_oorder     | tpccdb        | tpcc_group      |        3 |            1 | zone1 | 172.20.249.52 |            0 | RANDOM            |
| obmysql     | bmsql_oorder     | tpccdb        | tpcc_group      |        3 |            2 | zone3 | 172.20.249.51 |            0 | RANDOM            |
| obmysql     | bmsql_order_line | tpccdb        | tpcc_group      |        3 |            0 | zone2 | 172.20.249.49 |            0 | RANDOM            |
| obmysql     | bmsql_order_line | tpccdb        | tpcc_group      |        3 |            1 | zone1 | 172.20.249.52 |            0 | RANDOM            |
| obmysql     | bmsql_order_line | tpccdb        | tpcc_group      |        3 |            2 | zone3 | 172.20.249.51 |            0 | RANDOM            |
| obmysql     | bmsql_stock      | tpccdb        | tpcc_group      |        3 |            0 | zone2 | 172.20.249.49 |            0 | RANDOM            |
| obmysql     | bmsql_stock      | tpccdb        | tpcc_group      |        3 |            1 | zone1 | 172.20.249.52 |            0 | RANDOM            |
| obmysql     | bmsql_stock      | tpccdb        | tpcc_group      |        3 |            2 | zone3 | 172.20.249.51 |            0 | RANDOM            |
| obmysql     | bmsql_warehouse  | tpccdb        | tpcc_group      |        3 |            0 | zone2 | 172.20.249.49 |            0 | RANDOM            |
| obmysql     | bmsql_warehouse  | tpccdb        | tpcc_group      |        3 |            1 | zone1 | 172.20.249.52 |            0 | RANDOM            |
| obmysql     | bmsql_warehouse  | tpccdb        | tpcc_group      |        3 |            2 | zone3 | 172.20.249.51 |            0 | RANDOM            |
+-------------+------------------+---------------+-----------------+----------+--------------+-------+---------------+--------------+-------------------+
26 rows in set (0.095 sec)

role 是副本角色。1 表示主副本,2 表示备副本。

下面 SQL 是 ODP 查看一个具体的分区副本位置。视图 __all_virtual_proxy_schema 的访问要求非常严格,必须提供下面 4 个条件。通常不建议运维人员自己查询这个视图。

select table_name,partition_id, part_num, svr_ip,role, replica_num, table_type
from __all_virtual_proxy_schema
where tenant_name = 'obmysql' and database_name = 'tpccdb' and table_name = 'bmsql_oorder' and partition_id = 1 ;

输出:

+--------------+--------------+----------+---------------+------+-------------+------------+
| table_name   | partition_id | part_num | svr_ip        | role | replica_num | table_type |
+--------------+--------------+----------+---------------+------+-------------+------------+
| bmsql_oorder |            1 |        3 | 172.20.249.49 |    2 |           3 |          3 |
| bmsql_oorder |            1 |        3 | 172.20.249.51 |    2 |           3 |          3 |
| bmsql_oorder |            1 |        3 | 172.20.249.52 |    1 |           3 |          3 |
+--------------+--------------+----------+---------------+------+-------------+------------+
3 rows in set (0.028 sec)

ODP 获取到每个分区的位置缓存在进程内部。如果后端 OBServer 节点宕机,发生部分分区主备故障切换,ODP 不一定能立即感知到,而是在 SQL 发到老的主副本节点时报错后,ODP 重新获取该分区新的主副本位置,然后更新自己的分区位置缓存。

调整 PRIMARY_ZONE 设置

PRIMARY_ZONE 设置主副本分布策略,通常可以在租户级别设置。MySQL 租户还可以在数据库级别再设置,数据库设置覆盖租户默认设置。此外,也可以在表分组或表级别设置,表分组和表的 PRIMARY_ZONE 设置会覆盖数据库或者租户的默认设置。

当调整主副本分布策略后,OceanBase 会很快发起在线主备切换。

  • 查看租户的 PRIMARY_ZONE 和 LOCALITY 设置。

    select tenant_id,tenant_name,primary_zone,locality from gv$tenant;
    
    # 输出:
    +-----------+-------------+-------------------+---------------------------------------------+
    | tenant_id | tenant_name | primary_zone      | locality                                    |
    +-----------+-------------+-------------------+---------------------------------------------+
    |         1 | sys         | zone1;zone2,zone3 | FULL{1}@zone1, FULL{1}@zone2, FULL{1}@zone3 |
    |      1002 | obmysql     | RANDOM            | FULL{1}@zone1, FULL{1}@zone2, FULL{1}@zone3 |
    +-----------+-------------+-------------------+---------------------------------------------+
    2 rows in set (0.011 sec)

    PRIMARY_ZONE 的取值可以有很多组合:

    • zone1:等同于 zone1; zone2,zone3。即主副本优先分布在 zone1 的节点上。如果 zone1 的节点不可用,会选举 zone2zone3 中的节点。

    • zone1; zone2; zone3:即主副本优先分布在 zone1 的节点上。如果 zone1 的节点不可用,优先考虑 zone2 的节点,其次才是考虑 zone3 的节点。

    • RANDOM:即主副本随机分布。赋值语句: set primary_zone =RANDOM;,不需要单引号。

    • DEFAULT:即清空 PRIMARY_ZONE 设置,遵守默认值,只能设置数据库和表分组、表的 PRIMARY_ZONE 为 DEFAULT

    LOCALITY 设置是描述每个 Zone 里的副本类型,默认为全功能副本(FULL)。其他副本类型还有:日志副本(LOGONLY)、只读副本(READONLY)。

  • 查看数据库的 PRIMARY_ZONE 设置

    可以通过查看数据库的定义获取。

    MySQL [test]> alter database test primary_zone='zone2';
    Query OK, 0 rows affected (0.310 sec)
    
    MySQL [test]> show create database test;
    +----------+-----------------------------------------------------------------------------------------------------------+
    | Database | Create Database                                                                                           |
    +----------+-----------------------------------------------------------------------------------------------------------+
    | test     | CREATE DATABASE `test` DEFAULT CHARACTER SET = utf8mb4 REPLICA_NUM = 3 PRIMARY_ZONE = 'zone2;zone1,zone3' |
    +----------+-----------------------------------------------------------------------------------------------------------+
    1 row in set (0.016 sec)
  • 查看表分组和表的 PRIMARY_ZONE 设置

    MySQL [test]> alter tablegroup tpcc_group primary_zone=RANDOM;
    Query OK, 0 rows affected (0.427 sec)
    
    MySQL [test]> show create tablegroup tpcc_group\G
    *************************** 1. row ***************************
           Tablegroup: tpcc_group
    Create Tablegroup: CREATE TABLEGROUP IF NOT EXISTS `tpcc_group`  PRIMARY_ZONE = RANDOM BINDING = FALSE
      partition by hash partitions 3
    
    1 row in set (0.010 sec)
    
    MySQL [test]> alter table t1 primary_zone='zone3;zone2;zone1';
    Query OK, 0 rows affected (0.405 sec)
    
    MySQL [test]> show create table t1\G
    *************************** 1. row ***************************
           Table: t1
    Create Table: CREATE TABLE `t1` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `c1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
      PRIMARY KEY (`id`)
    ) AUTO_INCREMENT = 1000001 DEFAULT CHARSET = utf8mb4 ROW_FORMAT = COMPACT COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 3 PRIMARY_ZONE = 'zone3;zone2;zone1' BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0
    1 row in set (0.082 sec)
  • 查看分区主备副本切换事件

    调整 PRIMARY_ZONE 可能引起分区副本主备角色切换,这个是在线切换,立即生效,对业务影响非常小。可以通过以下 SQL 查看切换历史:

    select t.table_name, h.partition_idx, h.gmt_create, h.svr_ip, h.event, h.leader, h.info
    from `__all_virtual_election_event_History` h join __all_virtual_table t  on (h.table_id=t.table_id)
    where t.table_id >> 40 = 1002
    order by h.gmt_create desc 
    limit 10;

    输出:

    
    +------------------+---------------+----------------------------+---------------+-----------------+----------------------+--------------------+
    | table_name       | partition_idx | gmt_create                 | svr_ip        | event           | leader               | info               |
    +------------------+---------------+----------------------------+---------------+-----------------+----------------------+--------------------+
    | bmsql_order_line |             1 | 2021-10-03 16:31:05.822946 | 172.20.249.52 | leader takevoer | "172.20.249.52:2882" | change leader succ |
    | bmsql_order_line |             1 | 2021-10-03 16:31:05.822150 | 172.20.249.49 | leader takevoer | "172.20.249.52:2882" | change leader succ |
    | bmsql_order_line |             1 | 2021-10-03 16:31:05.821211 | 172.20.249.51 | leader revoke   | "172.20.249.51:2882" | old leader revoke  |
    | bmsql_order_line |             1 | 2021-10-03 16:31:05.821211 | 172.20.249.51 | leader takevoer | "172.20.249.52:2882" | renew lease succ   |
    | nation           |             0 | 2021-10-03 16:31:05.817790 | 172.20.249.51 | leader takevoer | "172.20.249.51:2882" | change leader succ |
    | sbtest7          |             0 | 2021-10-03 16:31:05.817790 | 172.20.249.51 | leader takevoer | "172.20.249.51:2882" | change leader succ |
    | sbtest1          |             0 | 2021-10-03 16:31:05.817790 | 172.20.249.51 | leader takevoer | "172.20.249.51:2882" | change leader succ |
    | supplier         |             3 | 2021-10-03 16:31:05.817790 | 172.20.249.51 | leader takevoer | "172.20.249.51:2882" | change leader succ |
    | sbtest8          |             0 | 2021-10-03 16:31:05.817790 | 172.20.249.51 | leader takevoer | "172.20.249.51:2882" | change leader succ |
    | customer         |             0 | 2021-10-03 16:31:05.817790 | 172.20.249.51 | leader takevoer | "172.20.249.49:2882" | change leader succ |
    +------------------+---------------+----------------------------+---------------+-----------------+----------------------+--------------------+
    10 rows in set (0.107 sec)

LDC 设置

OceanBase 数据库作为典型的高可用分布式关系型数据库,使用 Paxos 协议进行日志同步,天然支持多地多中心的部署方式以提供高可靠的容灾保证。但当真正多地多中心部署时,任何数据库都会面临异地路由延迟问题。

逻辑数据中心(Logical Data Center,LDC)路由正是为了解决这一问题而设计的。您可以为 OceanBase 集群的每个 Zone 设置 Region 属性和 IDC 属性,并为 ODP 指定 IDC 名称配置项。当 ODP 随机发送时,会优先考虑同一个 IDC 或者同一个 Region 的可用节点。

OceanBase 集群节点添加 Region 和 IDC 属性

ALTER SYSTEM MODIFY zone zone1 SET region = SHANGHAI; 
ALTER SYSTEM MODIFY zone zone1 SET idc = SH_IDC1;

ALTER SYSTEM MODIFY zone zone2 SET region = SHANGHAI; 
ALTER SYSTEM MODIFY zone zone2 SET idc = SH_IDC2;

ALTER SYSTEM MODIFY zone zone3 SET region = HANGZHOU; 
ALTER SYSTEM MODIFY zone zone3 SET idc = SH_IDC3;

一个集群可以有若干 Region,一个 Region 有若干个 Zone,每个 Zone 对应一个 IDC(可以重复,如同机房三副本)。Region 和 IDC 不能随意设置,需要保证租户的 PRIMARY_ZONE 里至少有两个 FULL 副本。

MySQL [oceanbase]> select * from __all_zone where name in ('region','idc');
+----------------------------+----------------------------+-------+--------+-------+---------+
| gmt_create                 | gmt_modified               | zone  | name   | value | info    |
+----------------------------+----------------------------+-------+--------+-------+---------+
| 2021-09-25 08:19:05.067944 | 2021-10-04 14:28:03.262961 | zone1 | idc    |     0 | idc1    |
| 2021-09-25 08:19:05.067944 | 2021-10-04 14:29:17.004134 | zone1 | region |     0 | region1 |
| 2021-09-25 08:19:05.068993 | 2021-10-04 14:28:12.236866 | zone2 | idc    |     0 | idc2    |
| 2021-09-25 08:19:05.068993 | 2021-10-04 14:29:23.306688 | zone2 | region |     0 | region2 |
| 2021-09-25 08:19:05.070055 | 2021-10-04 14:28:19.560596 | zone3 | idc    |     0 | idc3    |
| 2021-09-25 08:19:05.070055 | 2021-10-04 14:29:30.604319 | zone3 | region |     0 | region3 |
+----------------------------+----------------------------+-------+--------+-------+---------+
6 rows in set (0.012 sec)

例如,上述设置就有问题,租户的 PRIMARY_ZONE 设置为任意一个 Zone 都会报错。

MySQL [oceanbase]> alter tenant sys primary_zone='zone1';
ERROR 4179 (HY000): primary zone F type replica not enough in its region not allowed

MySQL [oceanbase]> alter system modify zone zone2 set region = region1;
Query OK, 0 rows affected (0.004 sec)


MySQL [oceanbase]> alter tenant sys primary_zone='zone1';
Query OK, 0 rows affected (0.095 sec)

MySQL [oceanbase]> select tenant_name,primary_zone,locality from __all_tenant;
+-------------+--------------+---------------------------------------------+
| tenant_name | primary_zone | locality                                    |
+-------------+--------------+---------------------------------------------+
| sys         | zone1;zone2  | FULL{1}@zone1, FULL{1}@zone2, FULL{1}@zone3 |
| obmysql     | RANDOM       | FULL{1}@zone1, FULL{1}@zone2, FULL{1}@zone3 |
+-------------+--------------+---------------------------------------------+
2 rows in set (0.003 sec)

将 zone2 的 Region 属性和 zone1 的 Region 属性调整一致后,即可设置 PRIMARY_ZONE 为 zone1zone2。并且 zone3 不再出现在候选里,因为 zone3region3 里只有一个 FULL 副本,不具备设置为 PRIMARY_ZONE 的资格。

开启 LDC 后,PRIMARY_ZONE 设置为 RANDOM 还可能会有限制。

MySQL [oceanbase]> alter tenant obmysql primary_zone=RANDOM;
ERROR 1235 (0A000): tenant primary zone span regions when GTS is on not supported

登录业务租户查看。

MySQL [test]> show global variables like 'ob_timestamp_service';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| ob_timestamp_service | GTS   |
+----------------------+-------+
1 row in set (0.008 sec)

MySQL [test]> set global ob_timestamp_service = LTS;
Query OK, 0 rows affected (0.120 sec)

再次登录 sys 租户修改。

MySQL [oceanbase]> alter tenant obmysql primary_zone=RANDOM;
Query OK, 0 rows affected (0.078 sec)

MySQL [oceanbase]> select tenant_name,primary_zone,locality from __all_tenant;
+-------------+-------------------+---------------------------------------------+
| tenant_name | primary_zone      | locality                                    |
+-------------+-------------------+---------------------------------------------+
| sys         | zone1;zone2,zone3 | FULL{1}@zone1, FULL{1}@zone2, FULL{1}@zone3 |
| obmysql     | RANDOM            | FULL{1}@zone1, FULL{1}@zone2, FULL{1}@zone3 |
+-------------+-------------------+---------------------------------------------+
2 rows in set (0.014 sec)

此时虽然设置成功,不过由于时间服务改用了 LTS,不支持跨节点的一致性读快照,会遇到以下问题。

MySQL [tpccdb]> select /*+ read_consistency(strong) query_timeout(10000000) */ count(*) from bmsql_warehouse;
ERROR 1235 (0A000): strong consistency across distributed node not supported
MySQL [tpccdb]>
MySQL [tpccdb]> select /*+ read_consistency(weak) */ count(*) from bmsql_warehouse;
+----------+
| count(*) |
+----------+
|       10 |
+----------+
1 row in set (0.269 sec)

LTS 服务下不支持跨节点的分布式查询,这个是业务不能接受的。所以反过来,当 OceanBase 集群有多个 Region 的时候,就不能设置 PRIMARY_ZONE 为 RANDOM

ODP 的 IDC 属性

ODP 启动时可以指定参数 proxy_idc_name 为具体的 IDC,也可以启动后修改参数值。

MySQL [(none)]> show proxyconfig like 'proxy_idc_name';
+----------------+-------+-----------------------------------------------------------------------------------------------------------------------------------+-------------+---------------+
| name           | value | info                                                                                                                              | need_reboot | visible_level |
+----------------+-------+-----------------------------------------------------------------------------------------------------------------------------------+-------------+---------------+
| proxy_idc_name |       | idc name for proxy ldc route. If is empty or invalid, treat as do not use ldc. User session vars 'proxy_session_ldc' can cover it | false       | SYS           |
+----------------+-------+-----------------------------------------------------------------------------------------------------------------------------------+-------------+---------------+
1 row in set (0.008 sec)

MySQL [(none)]> alter proxyconfig set proxy_idc_name = 'idc1';
Query OK, 0 rows affected (0.044 sec)

MySQL [(none)]> show proxyconfig like 'proxy_idc_name';
+----------------+-------+-----------------------------------------------------------------------------------------------------------------------------------+-------------+---------------+
| name           | value | info                                                                                                                              | need_reboot | visible_level |
+----------------+-------+-----------------------------------------------------------------------------------------------------------------------------------+-------------+---------------+
| proxy_idc_name | idc1  | idc name for proxy ldc route. If is empty or invalid, treat as do not use ldc. User session vars 'proxy_session_ldc' can cover it | false       | SYS           |
+----------------+-------+-----------------------------------------------------------------------------------------------------------------------------------+-------------+---------------+
1 row in set (0.051 sec)

MySQL [(none)]> show proxyinfo idc;
+-----------------+--------------+----------------+----------------+--------------+--------------------------+--------------+
| global_idc_name | cluster_name | match_type     | regions_name   | same_idc     | same_region              | other_region |
+-----------------+--------------+----------------+----------------+--------------+--------------------------+--------------+
| idc1            | obce-3zones  | MATCHED_BY_IDC | [[0]"region1"] | [[0]"zone1"] | [[0]"zone2", [1]"zone3"] | []           |
+-----------------+--------------+----------------+----------------+--------------+--------------------------+--------------+
1 row in set (0.010 sec)

ODP 路由策略简介

说明

ODP 的路由策略非常丰富,本节只做大概的介绍。您仅需了解每条 ODP 的路由策略即可。

弱一致性读路由策略

OceanBase 数据库默认是强一致性读,即写后读立即可见(READ AFTER WRITER)。使用强一致性读策略时,ODP 会优先路由到访问表的分区的主副本节点上。

和强一致性读对立的就是弱一致性读,弱一致性读不要求写后读立即可见。弱一致性读也可以路由到分区的主副本和备副本节点,通常有三副本所在节点可以选。

但是开启弱一致性读后,如果 OceanBase 数据库和 ODP 都开启了 LDC 特性,那么弱一致性读语句的路由策略会改变,弱一致性读语句将按下述顺序进行路由:

  1. 同一个机房或者同一个 Region 状态不是合并中(merging)的节点。

  2. 合并中的节点。

  3. 其他 Region 的不在合并的或在合并的节点。

即 ODP 会尽力避开合并中的节点。不过若 OceanBase 集群关闭了轮转合并(参数 enable_merge_by_turn 设置为 false ),合并(major freeze)则是所有节点都开始合并,那么 ODP 也就无法避开合并中的节点。

还有一些 SQL 不是访问数据,而是查看或者设置变量值等。如:

set @@autocommit=off
show variables like 'autocommit';

这类 SQL 的路由策略则是随机路由。在随机路由策略中,如果 OceanBase 数据库和 ODP 开启了 LDC 设置,也会按照上文的路由顺序进行路由。

弱一致性读通常用在读写分离场景中。不过当租户 PRIMARY_ZONE 为 RANDOM 时,租户的所有分区的主副本也是分散在所有 Zone 下,这时弱一致性读备副本的意义也不是很大。

但是,如果使用了只读副本,只读副本设置为独立的 IDC,然后单独的 ODP 设置为同一个 IDC,则这个 ODP 可以用于只读副本的路由。

强一致性读路由策略

路由策略很多,这里针对部分路由策略由简单到复杂进行列举。

  • 强一致性读路由策略将 SQL 路由到访问表的分区的主副本所在节点。这一条理解起来比较简单,但实际 SQL 情形很复杂。

  • 如果 SQL 访问了两个表,会依据第一个表及其条件判断出该分区主副本节点。如果无法判断,就随机发。所以 SQL 里多表连接时,表的前后顺序对路由策略是有影响的,间接对性能有影响。

    注意

    如果要判断的表是分区表,会判断条件是否是分区键等值条件。如果不是,则不能确定是哪个分区,就随机发到该表的所有分区所在的节点任意一个。

  • 如果开启事务了,则事务里开启事务的 SQL 的路由节点会作为事务后面其他 SQL 路由的目标节点,直到事务结束(提交或者回滚)为止。

  • 当 SQL 被 ODP 路由分配到一个节点上时

    • 如果要访问的数据分区的主副本恰好在那个节点上,SQL 就在该节点执行,这个 SQL 的执行类型是本地 SQL(plan_type1)。

    • 如果要访问的数据分区的主副本不在这个节点上,SQL 会被 OBServer 节点再次转发。这个 SQL 的执行类型是远程 SQL(plan_type2)。

    • 如果 SQL 执行计划要访问的数据分区是跨越多个节点,则这个 SQL 的执行类型是分布式 SQL(plan_type3)。

  • 如果事务中有复制表的读 SQL,只要 SQL 被路由到的节点上有该复制表的备副本,则该 SQL 可以读取本地备副本,因为复制表的所有备副本跟主副本是强一致的。这个 SQL 的执行类型是本地 SQL。

实际 SQL 类型很复杂,ODP 的路由策略也变得很复杂,有时候会出现路由不准的情形。如果不符合设计预期就会产生 BUG,但很可能也是设计如此(BY DESIGN)。毕竟当前版本的 ODP 只能做简单的 SQL 解析,不像 OceanBase 数据库那样做完整的执行计划解析。

当业务 SQL 很多很复杂时,远程 SQL 和分布式 SQL 将会无法避免,这时需主要观察远程 SQL 和分布式 SQL 比例。如果比例很高,整体上业务 SQL 性能都不会很好。此时应尽可能地减少远程 SQL 和分布式 SQL。比如,通过表分组、复制表和 PRIMARY_ZONE 设置等。

1
https://gitee.com/oceanbase/tutorials-doc.git
git@gitee.com:oceanbase/tutorials-doc.git
oceanbase
tutorials-doc
tutorials-doc
V1.0.0

搜索帮助