5.2 如何管理 OceanBase 租户
OceanBase 租户原理
生产环境中 OceanBase 集群通常是三副本架构,有三个 Zone,每个 Zone 至少需要一台主机,集群架构是 N-N-N(N>=1)。
OceanBase 集群将所有节点的资源(主要是 CPU 、内存和磁盘空间)聚合成大的资源池之后,再二次分配给租户。
租户就是逻辑实例,每个租户对应一部分资源(主要是 CPU、内存)。租户的资源也被称为资源池,由每个 Zone 中一个小的资源池组成,通常三个 Zone 的资源池大小规格是一样的(可以不一样)。资源单元规格 * 资源单元数就是租户的可以利用的最大资源。
说明
每个 Zone 中的资源池至少需包含一个资源单元。创建租户资源池时,每个资源单元只能从一个节点上分配资源。
如上图:
集群的架构是 3-3-3。每个节点总资源是 30C 200G 内存,集群总资源是 270C 1800G 内存。
默认租户 sys 的架构是 1-1-1,每个 Zone 里的资源单元大小是 5C 20G。
业务租户 t_trade 的架构是 1-1-1,每个 Zone 里的资源单元大小是 20C 40G。
业务租户 t_pay 的架构是 2-2-2,每个 Zone 里的资源单元大小是 20C 100G,每个 Zone 有两个资源单元,分布在 2 个节点上。
每个租户的数据都从租户资源池对应的资源单元中分配。租户每个 Zone 的资源单元数组成租户的架构:n-n-n(1<=n<=N)。
租户的数据管理单位是分区,分区是表的子集。普通表就是一个分区,分区表有多个分区。每个分区有三个副本,分布在三个 Zone 里,具体就在租户的某三个资源单元中。
说明:
表
t1是普通表,只有一个分区,标识为t1(p0),有三个副本,分别在资源单元 UNIT7、UNIT8、UNIT9 上。表
t3是分区表,有三个分区,标识为t3(p0)、t3(p1)和t3(p2),每个分区有三个副本,每个分区的三副本分别在三个资源单元上。单看一个 Zone,表
t3的三个分区分散在两个节点上。如t3(p1)一个节点,t3(p0)和t3(p2)是一个节点。
一个表有多个分区,这个技术类似存储的条带技术(Striping),每个分区有三个副本,类似存储的镜像技术(Mirroring)。
如何修改 OceanBase 租户变量/参数
集群的参数中有部分参数的生效范围是租户,这部分参数也称为租户的参数,会影响租户的行为。
常用租户参数如下:
| 参数名 | 参数值 | 参数含义 |
|---|---|---|
| writing_throttling_maximum_duration | 1h | 增量内存写入限速剩余时间目标上限。 |
| writing_throttling_trigger_percentage | 100 | 增量内存写入限速触发阈值。建议设置为 90。 |
| max_stale_time_for_weak_consistency | 5s | 弱一致性读能容忍最大延时。 |
除了参数,租户更常用变量(variable)来定制租户的行为。变量跟参数其实是同一类概念,参数的定位和风格取自 Oracle 数据库,变量的定位和风格取自 MySQL 数据库。
集群 sys 租户同样可以设置变量值(sys 租户变量通常不易调整,必须很谨慎),不同租户的变量设置彼此独立,互不影响。
大部分变量的设置是立即生效,生效范围根据设置方法不同可分为实例全局层面生效和会话层面生效。极少数变量(类似 MySQL 的初始化变量)不能在租户里后期修改,只能在 sys 租户里新建业务租户的时候设置。当然也可以后期在 sys 租户后期修改,只是在修改时必须充分评估影响。
变量的值、描述都可以通过以下命令查看。
show global | [session] variables [ like '%变量名特征%' ] ;
# 或
show global | [session] variables where variable_name in ('参数1' [, '参数2']) ;
# 您可通过以下命令修改变量的值
set global | [session] 变量名 = 变量值 ; # 如果是字符串,用两个单引号引起来其中,global 指全局生效,对新建会话生效,当前会话不生效。session 或者没有限定符,都表示对当前会话生效。会话断开重连后,又会取全局层面的默认值。
常用的租户变量如下:
| 变量名 | 变量默认值(OceanBase) | 变量含义 |
|---|---|---|
| autocommit | ON | 是否自动提交。 ON: 表示每个 DML 后会自动添加 commit 语句; OFF:表示不会自动 commit,需要用户主动 commit 或 rollback 事务。 |
| max_allowed_packet | 4194304 | 需要调大,否则 SQL 文本或数据量很大的时候可能报错。 |
| sql_mode | STRICT_ALL_TABLES | 用于设置 SQL 模式。 |
| transaction_isolation | READ-COMMITTED | 用于设置事务的隔离级别。 |
| tx_isolation | READ-COMMITTED | 用于设置事务隔离级别。 |
| lower_case_table_names | 1 | 1(ON)表示自动将表名转小写。 |
| ob_tcp_invited_nodes | % | % 表示允许所有 IP 访问。 |
| foreign_key_checks | ON | ON:检查外键约束; OFF:不检查外键约束。 |
| ob_query_timeout | 10000000 | 语句超时时间,单位是微秒(us)。 |
| ob_trx_idle_timeout | 120000000 | 事务空闲超时时间,单位是微秒(us)。 |
| ob_trx_timeout | 100000000 | 事务超时时间,单位是微秒(us)。 |
| ob_trx_lock_timeout | -1 | 锁等待超时时间,默认是 -1,不超时。单位是微秒(us)。 |
| ob_sql_work_area_percentage | 3 | 租户里 SQL 可用内存占租户内存比例。 |
部分变量还可以通过 SQL HINT 设置语句级别的变量,影响范围是所修饰的语句。语句级的变量名会去掉前面的 ob_ 部分。
下面是常用的几个语句级别的变量命名映射关系。
| 全局/会话变量名 | 语句级变量名 | 描述 |
|---|---|---|
| ob_query_timeout | query_timeout | 指定语句执行超时的阈值 |
| ob_read_consistency | read_consistency | 指定读一致性级别,默认是强一致性读,可以修改为弱一致性读 |
新建租户常用租户变量修改。可修改语句超时时间,避免复杂的语句查询时超时报错。
示例:语句超时报错
MySQL [test]> select sleep(11); ERROR 4012 (HY000): Timeout
示例:租户变量初始化
set global ob_query_timeout = 100000000; set global ob_trx_idle_timeout = 1200000000; set global ob_trx_timeout = 1000000000; set global ob_trx_lock_timeout = 1000000; set global ob_sql_work_area_percentage = 50;
注意
以上修改完成后均需要会话断开重连,重连后才会生效。
如何对租户资源扩容/缩容
租户扩容或缩容主要是指资源扩容或缩容,具体就是调整租户的 CPU 和内存规格。对租户资源扩容的前提是集群中有节点可以分配出租户需要的资源。
通常会首先考虑租户所在节点是否有可用资源满足租户资源扩容需求;如果不满足,就考虑集群中其他节点是否有资源。后者会触发集群中租户的资源负载均衡,会伴随着数据迁移逻辑。这个数据迁移完全是 OceanBase 内部逻辑,具备高可用能力,不怕异常宕机,不需要 DBA 介入。
租户资源池分裂
在三副本集群里,租户资源池通常也是由三个 Zone 中三个节点的资源单元(resource unit)组成。在前面创建租户的过程中,每个资源单元使用了统一的资源单元规格,创建了一个包含三个资源单元(同一个资源单元规格)的资源池。这是一种最简单的创建和使用形态。
您可通过下面 SQL 查看资源池细节。
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 | unit1 | 9 | 9 | 11 | 11 | 1001 | zone1 | 172.20.249.52:2882 | 1002 | obmysql | | my_pool | unit1 | 9 | 9 | 11 | 11 | 1002 | zone2 | 172.20.249.49:2882 | 1002 | obmysql | | my_pool | unit1 | 9 | 9 | 11 | 11 | 1003 | zone3 | 172.20.249.51:2882 | 1002 | obmysql | +--------------------+------------------+---------+---------+------------+------------+---------+-------+--------------------+-----------+-------------+ 6 rows in set (0.132 sec)
说明:
sys 租户有一个资源池
sys_pool,规格是sys_unit_config。业务租户
obmysql有一个资源池my_pool,规格是unit1。
下面示例是将业务租户的资源池分裂为三个资源池。
ALTER RESOURCE POOL `my_pool` SPLIT INTO ('my_pool_zone1','my_pool_zone2','my_pool_zone3') ON ('zone1','zone2','zone3');
# 再次确认资源池细节,输出:
+--------------------+------------------+---------+---------+------------+------------+---------+-------+--------------------+-----------+-------------+
| 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 | 11 | 11 | 1001 | zone1 | 172.20.249.52:2882 | 1002 | obmysql |
| my_pool_zone2 | unit1 | 9 | 9 | 11 | 11 | 1002 | zone2 | 172.20.249.49:2882 | 1002 | obmysql |
| my_pool_zone3 | unit1 | 9 | 9 | 11 | 11 | 1003 | zone3 | 172.20.249.51:2882 | 1002 | obmysql |
+--------------------+------------------+---------+---------+------------+------------+---------+-------+--------------------+-----------+-------------+
6 rows in set (0.010 sec)将原本一个资源池打散为三个资源池,主要是为了便于调整单独 Zone 里的资源单元规格。该步骤为可选步骤,只是为了便于更细粒度的扩容或缩容租户资源。
租户资源扩容
租户资源扩容有三种方法:
调整租户单元使用的资源规格的大小
示例:
alter resource unit sys_unit_config min_cpu=5,min_memory='2G'; alter resource unit unit1 max_cpu=5, min_cpu=5, max_memory='8G', min_memory='8G' ; +--------------------+------------------+---------+---------+------------+------------+---------+-------+--------------------+-----------+-------------+ | 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 | 5 | 5 | 8 | 8 | 1001 | zone1 | 172.20.249.52:2882 | 1002 | obmysql | | my_pool_zone2 | unit1 | 5 | 5 | 8 | 8 | 1002 | zone2 | 172.20.249.49:2882 | 1002 | obmysql | | my_pool_zone3 | unit1 | 5 | 5 | 8 | 8 | 1003 | zone3 | 172.20.249.51:2882 | 1002 | obmysql | +--------------------+------------------+---------+---------+------------+------------+---------+-------+--------------------+-----------+-------------+ 6 rows in set (0.026 sec)
更换资源单元规格
示例:
CREATE resource unit unit2 max_cpu=8, min_cpu=8, max_memory='10G', min_memory='10G', max_iops=10000, min_iops=1000, max_session_num=1000000, max_disk_size='1024G'; alter resource pool my_pool_zone1 unit = 'unit2'; # 查看资源池分布细节输出: +--------------------+------------------+---------+---------+------------+------------+---------+-------+--------------------+-----------+-------------+ | 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 | unit2 | 8 | 8 | 10 | 10 | 1001 | zone1 | 172.20.249.52:2882 | 1002 | obmysql | | my_pool_zone2 | unit1 | 5 | 5 | 8 | 8 | 1002 | zone2 | 172.20.249.49:2882 | 1002 | obmysql | | my_pool_zone3 | unit1 | 5 | 5 | 8 | 8 | 1003 | zone3 | 172.20.249.51:2882 | 1002 | obmysql | +--------------------+------------------+---------+---------+------------+------------+---------+-------+--------------------+-----------+-------------+ 6 rows in set (0.047 sec)
保留资源单元规格不变,增加每个 Zone 里的资源单元数量。
注意 此方法需要每个 Zone 中至少有 2 个节点。
具体语法如下:
alter resource pool my_pool_zone1 unit_num = 2;
默认情况下,租户在每个 Zone 里的资源单元数量是 1,这种租户架构也是 1-1-1,这种租户也叫小租户。在执行扩容命令时,租户会从集群其他节点里找到可用资源分配该规格的资源单元。
租户资源扩容的时候,很容易遇到资源不足的报错,信息如下:
MySQL [oceanbase]> alter resource pool my_pool_zone1 unit_num = 2; ERROR 4624 (HY000): machine resource 'zone1' is not enough to hold a new unit MySQL [oceanbase]>
为了避免遇到资源不足的错误,需要对集群可用资源进行准确统计,这就是前面常用的 SQL。为了确保可用资源统计准确,要求所有租户资源的
min_cpu和max_cpu值保持一致、min_memory和max_memory值保持一致。默认 sys 租户的规格
sys_unit_config的最小值和最大值经常不一样,需要手动调整。alter resource unit sys_unit_config min_cpu=5,min_memory='2G'; select a.zone,concat(a.svr_ip,':',a.svr_port) observer, cpu_total, (cpu_total-cpu_assigned) cpu_free, round(mem_total/1024/1024/1024) mem_total_gb, round((mem_total-mem_assigned)/1024/1024/1024) mem_free_gb, usec_to_time(b.last_offline_time) last_offline_time, usec_to_time(b.start_service_time) start_service_time, b.status, usec_to_time(b.stop_time) stop_time from __all_virtual_server_stat a join __all_server b on (a.svr_ip=b.svr_ip and a.svr_port=b.svr_port) order by a.zone, a.svr_ip ;
输出:
+-------+--------------------+-----------+----------+--------------+-------------+----------------------------+----------------------------+--------+----------------------------+ | zone | observer | cpu_total | cpu_free | mem_total_gb | mem_free_gb | last_offline_time | start_service_time | status | stop_time | +-------+--------------------+-----------+----------+--------------+-------------+----------------------------+----------------------------+--------+----------------------------+ | zone1 | 172.20.249.52:2882 | 14 | 1 | 13 | 1 | 1970-01-01 08:00:00.000000 | 2021-09-25 08:19:06.622351 | active | 1970-01-01 08:00:00.000000 | | zone2 | 172.20.249.49:2882 | 14 | 4 | 13 | 3 | 1970-01-01 08:00:00.000000 | 2021-09-25 08:19:07.392669 | active | 1970-01-01 08:00:00.000000 | | zone3 | 172.20.249.51:2882 | 14 | 4 | 13 | 3 | 1970-01-01 08:00:00.000000 | 2021-09-26 14:05:58.641570 | active | 1970-01-01 08:00:00.000000 | +-------+--------------------+-----------+----------+--------------+-------------+----------------------------+----------------------------+--------+----------------------------+ 3 rows in set (0.010 sec)
租户资源缩容
租户资源缩容就是调小租户的资源,具体方法和扩容时相同。一种方法是调小资源规格,另外一种方法就是调小资源池对应的资源单元数量(unit_num),详细示例请参考租户资源扩容。
租户资源缩容需要考虑一种场景,当租户有大量增量数据在增量内存 MemStore 中时,如果缩小租户资源的内存规格,可能会导致 MemStore 内存水位变高触发转储或限流。
为了避免这种情形,建议租户资源缩容之前,先对集群发起合并,降低 MemStore 里已使用的资源。此外,租户资源内存缩容可以分多步缩容。
当租户资源池对资源单元数量缩容时,会面临一个选择,即该释放那个资源单元。此时如果不指定 UNIT ID,将会由 OceanBase 自动选择。租户缩容结束后,可能会出现集群资源的负载均衡。为了避免这种不必要的负载均衡,可以指定删除的资源单元(UNIT ID)。
示例 SQL,unit_num 从 5 变为 4:
ALTER RESOURCE POOL pool_total_zone1 unit_num = 4 DELETE unit = (1013 );
租户缩容资源,很可能会触发租户资源负载均衡操作和数据迁移逻辑。建议关注数据迁移的进度和影响,可以通过查看集群事件日志视图,观察信息。
SELECT DATE_FORMAT(gmt_create, '%b%d %H:%i:%s') gmt_create_ , module, event, name1, value1, name2, value2, rs_svr_ip FROM __all_rootservice_event_history WHERE 1 = 1 AND gmt_create > SUBDATE(now(),interval 1 hour) ORDER BY gmt_create DESC LIMIT 20;




