在 OceanBase 数据库中,Leader 承担事务中的读写请求,因此每个分区 Leader 的分布决定了流量在每个节点上的分布。
流量介绍
数据库系统在应用架构中承担了数据存储和查询的功能,应用的读写请求称为数据库流量。数据库流量分为写流量、强一致读流量和弱一致读流量,写流量和强一致读流量由 OceanBase 数据库的 Leader 副本提供服务,弱一致读流量由 Leader 副本和 Follower 副本提供服务。ODP 提供了数据库流量的路由选择能力,ODP 实现了一个简单的 SQL Parser 模块,解析出 SQL 中的库名、表名及 hint,从而根据业务 SQL、路由规则、及 OBServer 节点的状态,选择最合适的一个 OBServer 节点转发请求。
Primary Zone 介绍
流量分布通过 Primary Zone 来描述,Primary Zone 描述了 Leader 副本的偏好位置,而 Leader 副本承载了业务的强一致读写流量,即 Primary Zone 决定了 OceanBase 数据库的流量分布。假设某张表 t1
的 primary_zone="Zone1"
,则 RootService
会尽量将 t1
表的 Leader 调度到 Zone1 上来。
说明
副本描述的对象是数据,而 Primary Zone 描述的对象是承载数据的容器,从而该容器下的数据继承容器的 Primary Zone 属性所描述的 Leader 偏好位置。OceanBase 数据库当前版本仅支持租户级别的 Primary Zone,而 OceanBase 数据库 V3.x 还支持表级、DB级、Table Group 级别配置 Primary Zone。
Primary Zone 实际上是一个 Zone 的列表,列表中包含多个 Zone。该列表用如下方式为 Zone 配置优先级:
当 Primary Zone 列表包含多个 Zone 时,用 ';' 分隔的具有从高到低的优先级;用 ',' 分隔的具有相同优先级,表示流量打散在多个 Zone 上,这几个 Zone 同时提供服务。
例如:'hz1,hz2;sh1,sh2;sz1'
表示 hz1
和 hz2
具有相同的优先级,并且优先级高于 sh1/sh2
和 sz1
;sh1
和 sh2
具有相同优先级,并且优先级高于 sz1
。
OceanBase 数据库当前版本仅支持租户级别的 Primary Zone,不再支持表级、DB 级、Table Group 级配置 Primary Zone。如果创建租户时未指定 primary_zone
,默认填写为 RANDOM
,表示各个 Zone 优先级相同。
租户的 Primary Zone 属性可以通过系统租户下 oceanbase.DBA_OB_TENANTS
视图的 PRIMARY_ZONE
字段查看。示例如下:
obclient> SELECT * FROM oceanbase.DBA_OB_TENANTS limit 10;
+-----------+-------------+-------------+----------------------------+----------------------------+--------------+---------------+-------------------+--------------------+--------+---------------+--------+-------------+-------------------+------------------+---------------------+---------------------+---------------------+---------------------+--------------+----------------------------+
| TENANT_ID | TENANT_NAME | TENANT_TYPE | CREATE_TIME | MODIFY_TIME | PRIMARY_ZONE | LOCALITY | PREVIOUS_LOCALITY | COMPATIBILITY_MODE | STATUS | IN_RECYCLEBIN | LOCKED | TENANT_ROLE | SWITCHOVER_STATUS | SWITCHOVER_EPOCH | SYNC_SCN | REPLAYABLE_SCN | READABLE_SCN | RECOVERY_UNTIL_SCN | LOG_MODE | ARBITRATION_SERVICE_STATUS |
+-----------+-------------+-------------+----------------------------+----------------------------+--------------+---------------+-------------------+--------------------+--------+---------------+--------+-------------+-------------------+------------------+---------------------+---------------------+---------------------+---------------------+--------------+----------------------------+
| 1 | sys | SYS | 2023-05-17 18:10:19.940353 | 2023-05-17 18:10:19.940353 | RANDOM | FULL{1}@zone1 | NULL | MYSQL | NORMAL | NO | NO | PRIMARY | NORMAL | 0 | NULL | NULL | NULL | NULL | NOARCHIVELOG | DISABLED |
| 1001 | META$1002 | META | 2023-05-17 18:15:21.455549 | 2023-05-17 18:15:36.639479 | zone1 | FULL{1}@zone1 | NULL | MYSQL | NORMAL | NO | NO | PRIMARY | NORMAL | 0 | NULL | NULL | NULL | NULL | NOARCHIVELOG | DISABLED |
| 1002 | mysql001 | USER | 2023-05-17 18:15:21.461276 | 2023-05-17 18:15:36.669988 | zone1 | FULL{1}@zone1 | NULL | MYSQL | NORMAL | NO | NO | PRIMARY | NORMAL | 0 | 1684398681521302749 | 1684398681521302749 | 1684398681345969089 | 4611686018427387903 | NOARCHIVELOG | DISABLED |
| 1003 | META$1004 | META | 2023-05-17 18:18:19.927859 | 2023-05-17 18:18:36.443233 | zone1 | FULL{1}@zone1 | NULL | MYSQL | NORMAL | NO | NO | PRIMARY | NORMAL | 0 | NULL | NULL | NULL | NULL | NOARCHIVELOG | DISABLED |
| 1004 | oracle001 | USER | 2023-05-17 18:18:19.928914 | 2023-05-17 18:18:36.471606 | zone1 | FULL{1}@zone1 | NULL | ORACLE | NORMAL | NO | NO | PRIMARY | NORMAL | 0 | 1684398681335427475 | 1684398681335427475 | 1684398681144712832 | 4611686018427387903 | NOARCHIVELOG | DISABLED |
| 1005 | META$1006 | META | 2023-05-18 15:48:57.441320 | 2023-05-18 15:49:12.820051 | zone1 | FULL{1}@zone1 | NULL | MYSQL | NORMAL | NO | NO | PRIMARY | NORMAL | 0 | NULL | NULL | NULL | NULL | NOARCHIVELOG | DISABLED |
| 1006 | mq_t1 | USER | 2023-05-18 15:48:57.447657 | 2023-05-18 15:49:12.857944 | zone1 | FULL{1}@zone1 | NULL | MYSQL | NORMAL | NO | NO | PRIMARY | NORMAL | 0 | 1684398680916392609 | 1684398680916392609 | 1684398680742451346 | 4611686018427387903 | NOARCHIVELOG | DISABLED |
+-----------+-------------+-------------+----------------------------+----------------------------+--------------+---------------+-------------------+--------------------+--------+---------------+--------+-------------+-------------------+------------------+---------------------+---------------------+---------------------+---------------------+--------------+----------------------------+
7 rows in set
Region 属性
在 OceanBase 数据库中,Zone 有一个 Region 属性(DBA_OB_ZONES
视图的 REGION
字段),表示该 Zone 所处的地区,每个 Zone 仅能配置一个 Region,但一个 Region 内可包含多个 Zone。Primary Zone 的设置隐含的包含了 Leader 偏好的 Region 位置。具体指用户设置 Primary Zone 时包含两层语义:
-
被指定的 Primary Zone 为 Leader 的偏好 Zone 的 Region。
-
被指定 Primary Zone 所在的 Region 为 Leader 偏好的 Region。
具体地,Leader 会被优先调度到最高优先级的 Zone 上去,如果最高优先级的 Zone 上的副本不能成为 Leader,会优先选择同一个 Region 内的其他 Zone 作为 Leader 的位置,从而保证业务访问 OceanBase 数据库尽量不跨城。
Primary Zone 改写
用户设置的 Primary Zone 会由 OceanBase 数据库基于各个 Zone 所在的 Region 进行改写,改写规则如下:
-
将用户设置的 Primary Zone 中的所有 Zone 对应的 Region 列出。例如:
primary_zone
为hz1,hz2;sh1,sh2;sz1
对应的primary_region
的列表为hz,hz;sh,sh;sz
。 -
将
primary_region
中重复的 Region 去掉,去掉规则为保留第一个出现的 Region,其他 Region 后续重复的 Region 移除,例如hz1,hz2;sh1,sh2;sz1
,其primary_region
转化为列表hz;sh;sz
。 -
依据
primary_region
中各 Region 的优先级,对primary_zone
进行补充,补充规则如下:将 Primary Zone 中各 Region 对应的 Zone 都取出,重新排列,高优先级 Region 内 Zone 比低优先级 Region 内 Zone 的优先级高,同一 Region 内 Zone 的优先级高低参考原始 Primary Zone 中的优先级。
例如:假设共有 9 个 Zone,sh1
、sh2
、sh3
三个 Zone 在 Region SH
,hz1
、hz2
、hz3
三个 Zone 在 Region HZ
,sz1
、sz2
、sz3
三个 Zone 在 Region SZ
。
-
用户设置的
primary_zone
为'sh1;hz1;hz2;sz1'
;按照改写规则 1 得到 primary_region 为'SH;HZ;HZ;SZ'
。按照改写规则 2 得到primary_region
为'SH;HZ;SZ'
。按规则 3 得到改写后primary_zone
为'sh1;sh2,sh3;hz1;hz2;hz3;sz1;sz2,sz3'
。解释如下:
三个 Region 的优先级为
SH
>HZ
>SZ
。RegionSH
中的 Zone 的优先级高于 RegionHZ
和 RegionSZ
中 Zone 的优先级。RegionHZ
中的 Zone 的优先级高于 RegionSZ
中 Zone 的优先级。各 Region 内每个 Zone 的优先级为:在 RegionSH
中sh1
>sh2
=sh3
,在 RegionHZ
中hz1
>hz2
>hz3
,在 RegionSZ
中sz1
>sz2
=sz3
。因此最终得到新的 Primary Zone 为'sh1;sh2,sh3;hz1;hz2;hz3;sz1;sz2,sz3'
。Leader 会优先分布在sh1
上,当sh1
发生故障时,Leader 会依照上面的 Primary Zone 优先级依次分布在sh2
和sh3
。 -
用户设置的
primary_zone
为'sh1,sh2;hz1;hz2;sz1'
;按照改写规则 1 得到primary_region
为'SH,SH;HZ;HZ;SZ'
。按照改写规则 2 得到primary_region
为'SH;HZ;SZ'
。按规则 3 得到改写后primary_zone
为'sh1,sh2;sh3;hz1;hz2;hz3;sz1;sz2,sz3'
。解释如下:
三个 Region 的优先级为
SH
>HZ
>SZ
。RegionSH
中的 Zone 的优先级高于 RegionHZ
和 RegionSZ
中 Zone 的优先级。RegionHZ
中的 Zone 的优先级高于 RegionSZ
中 Zone 的优先级。各 Region 内每个 Zone的优先级为:在 RegionSH
中sh1
=sh2
>sh3
,在 RegionHZ
中hz1
>hz2
>hz3
,在 RegionSZ
中sz1
>sz2
=sz3
。因此最终得到新的 Primary Zone 为'sh1,sh2;sh3;hz1;hz2;hz3;sz1;sz2,sz3'
。Leader 会优先平均分布在sh1
和sh2
上,当sh1
和sh2
发生故障时,Leader 会依照上面 Primary Zone 优先级依次分布在sh3
。 -
用户设置的
primary_zone
为'sh1,hz1;hz2;sz1'
;按照改写规则 1 得到primary_region
为'SH,HZ;HZ;SZ'
。按照改写规则 2 得到primary_region
为'SH,HZ;SZ'
。按规则 3 得到改写后primary_zone
为'sh1,hz1;hz2;sh2,sh3,hz3;sz1;sz2,sz3'
。解释如下:
三个 Region 的优先级为
SH
=HZ
>SZ
。RegionSH
和 RegionHZ
中的 Zone 的优先级高于 RegionSZ
中 Zone 的优先级。sh1
=hz1
>hz2
>sh2
=sh3
=hz3
>sz1
>sz2
=sz3
。因此最终得到新的 Primary Zone 为'sh1,hz1;hz2;sh2,sh3,hz3;sz1;sz2,sz3'
。Leader 会优先平均分布在sh1
和hz1
上,当sh1
和hz1
发生故障时,Leader 会依照上面 Primary Zone 优先级依次分布在hz2
。
数据分区是基于建表语句创建的逻辑对象,是划分和管理表数据的一种机制。每个租户由若干个 Unit 组成,日志流根据一定的规则分布于这些 Unit 上,从而决定了归属于日志流的数据分区在 Unit 上的分布。本小节介绍数据及其流量的分布规则。
OceanBase 数据库支持普通表和分区表。分区表又分为一级分区表和二级分区表,分区表由一个或多个分区组成。普通表由一个分区组成,可以看做分区表的特例。OceanBase 数据库的基本分区策略包括范围(Range)分区、列表(List)分区、哈希(Hash)分区、Key 分区等。
Unit Group 介绍
OceanBase 数据库 V4.0 开始在租户管理上增加了限制,要求同一个租户所有 Zone 的 Unit 个数相同。系统为每个 Zone 的 Unit 进行了编号,不同 Zone 之间相同编号(UNIT_GROUP_ID
)的 Unit 组成一个 Unit Group。Unit Group 具有以下特性:
-
每个 Unit Group 分配唯一 ID,系统租户通过
oceanbase.DBA_OB_UNITS
视图的UNIT_GROUP_ID
字段可以查看该 ID。 -
一个日志流只属于一个 Unit Group,并且只分布于该 Unit Group 的 Unit 上。因此 Unit Group 内所有 Unit 以日志流为单位,分布了相同的数据分区,从而框定了一组数据。同时,也就要求每个 Zone 的服务能力对等。
-
OceanBase 数据库 V4.0 开始不再支持按 Zone 个性化配置租户的 Unit 个数,只能按照 Unit Group 维度整体调整,比如需要为租户水平扩容资源,调大 Unit 个数,只能所有 Zone 统一扩容;相应的,租户缩容的场景,只能按 Unit Group 整体删除 Unit。通过 Unit Group 机制,保证了不同 Zone 上的数据分布是同构的。
sys
租户下,通过 oceanbase.DBA_OB_UNITS
视图可以查询所有的 Unit,及其所归属的 Unit Group。例如:
obclient> select UNIT_ID,TENANT_ID,UNIT_GROUP_ID,ZONE,SVR_IP,SVR_PORT from DBA_OB_UNITS where TENANT_ID = 1004;
+---------+-----------+---------------+--------------+-------------+----------+
| UNIT_ID | TENANT_ID | UNIT_GROUP_ID | ZONE | SVR_IP | SVR_PORT |
+---------+-----------+---------------+--------------+-------------+----------+
| 1004 | 1004 | 1003 | sa128_obv4_1 | xx.xx.xx.47 | 2882 |
| 1005 | 1004 | 1003 | sa128_obv4_2 | xx.xx.xx.81 | 2882 |
| 1006 | 1004 | 1003 | sa128_obv4_3 | xx.xx.xx.19 | 2882 |
+---------+-----------+---------------+--------------+-------------+----------+
3 rows in set
日志流组介绍
日志流组的概念是为了适配 Primary Zone 打散在多个 Zone 上而引入的。当 Primary Zone 为单个 Zone 时,Unit Group 内只需要创建单个日志流即可。当 Primary Zone 为多个 Zone 时,Unit Group 内需要创建多个日志流来实现服务能力水平扩展。这些日志流具有相同的分布属性,他们共同组成一个日志流组,日志流组内的日志流个数等于 Primary Zone 的 Zone 个数。
因此,一个日志流属于一个日志流组,不可更改;日志流组与 Unit Group 一一对应;日志流组内所有日志流分布在对应的 Unit Group 上,日志流 Leader 打散在 Primary Zone 上。
日志流组内的日志流个数随着租户 Primary Zone 配置的变化而动态变化,日志流组生命期与 Unit Group 绑定。
sys
租户下,通过 oceanbase.CDB_OB_LS
视图可以查看集群所有租户的日志流,及其所归属的日志流组。例如:
obclient> select TENANT_ID,LS_ID,STATUS,PRIMARY_ZONE,UNIT_GROUP_ID,LS_GROUP_ID from oceanbase.CDB_OB_LS where TENANT_ID=1004;
+-----------+-------+--------+----------------------------------------+---------------+-------------+
| TENANT_ID | LS_ID | STATUS | PRIMARY_ZONE | UNIT_GROUP_ID | LS_GROUP_ID |
+-----------+-------+--------+----------------------------------------+---------------+-------------+
| 1004 | 1 | NORMAL | sa128_obv4_1;sa128_obv4_2,sa128_obv4_3 | 0 | 0 |
| 1004 | 1001 | NORMAL | sa128_obv4_1;sa128_obv4_2,sa128_obv4_3 | 1003 | 1001 |
+-----------+-------+--------+----------------------------------------+---------------+-------------+
2 rows in set
总结
综上所述,对本节介绍的众多细粒度概念做一总结:
-
Unit 是物理资源的抽象,每个 Unit 占据节点上一定的物理资源,包括 CPU、内存、存储空间等资源项。Unit 是资源调度的基本单位,可以调整 Unit 在同一个 Zone 内不同节点的分布,从而达到节点负载均衡和节点容灾的目的。
-
每个租户由若干 Unit 组成,通过设置租户的 Unit Number 和 Primary Zone,定义了一组承载业务流量的 Unit 集合。每个 Unit 放置于一个节点上,从而可以方便的实现租户容量的水平扩展。
-
日志流框定了一组数据,包括若干数据分区和有序的 RedoLog 日志流。通过 Paxos 协议实现了多副本日志同步,保证副本间数据的一致性,从而实现了数据的高可用。日志流也是事务的提交单位,事务修改在单个日志流内完成时可以采用一阶段原子提交;事务修改跨多个日志流时,采用 OceanBase 数据库优化的两阶段提交协议完成原子提交,日志流是分布式事务的参与者。日志流具有位置属性和角色属性,日志流内所有数据分区继承其属性。
-
系统为每个 Zone 的 Unit 进行编号,相同编号的 Unit 组成一个 Unit Group。Unit Group 框定了一组日志流,这些日志流只分布于该 Unit Group 的 Unit 上。
-
日志流组与 Unit Group 一一对应,在每个日志流组中,日志流的个数由 Primary Zone 的 Zone 个数决定。从而 Primary Zone 的 Zone 列表中的每个 Zone 都可以分布着日志流组中一个日志流的 Leader。
假设租户配置为
unit_num =2
,primary_zone ='Z1,Z2,Z3'
,则该租户定义了 2 个 Unit Group、2 个 日志流组和 6 个日志流。如下图所示。
OceanBase 数据库从多个层面将数据和流量灵活分布于多个节点上,Unit 可以在 Zone 内节点之间迁移以实现节点负载均衡和节点容灾。