写点什么

OceanBase 源码解读(十四):集群位置信息的存储与汇报

  • 2022 年 6 月 02 日
  • 本文字数:4122 字

    阅读完需:约 14 分钟

在前文源码解读第 13 篇《一号表》中我们为大家介绍了 __all_core_table 的定义以及其对应的内容,本文我们将聚焦在《集群位置信息的存储与汇报》上,为大家解读 OceanBase 集群 location 发现过程、__all_core_table 的位置以及 location 汇报机制。


1 OceanBase 集群的 location 发现过程

思考这样一个问题:在单机数据库中,数据库中的表都存储在本地,但在 OceanBase 这样的分布式数据库中,一张实体表可能存在多个分区,每个分区又有多个副本,分散在集群中的多个 server 上。那么当用户想去查询一张实体表时,数据库内部如何在众多 server 上定位这张表呢?


OceanBase 依靠内部的一套系统表来实现实体表的位置发现过程,这套系统表我们一般统称为 meta table。



涉及 location 的 meta table 主要包括 __all_core_table、__all_root_table、__all_tenant_meta_table 三张内部表。OceanBase 集群中所有实体表的 location(位置信息),以分区副本为粒度,记录在该层级关系中。


从下往上看:

1)用户表的 partition 的 replica 位置信息记录在该租户的内部表 __all_tenant_meta_table 中;

2)每个租户的 __all_tenant_meta_table 的位置信息、系统表(包括用户租户和系统租户的)位置信息记录在 __all_root_table 中;

3)__all_root_table 的位置信息记录在 __all_core_table 中;

4)__all_core_table 的位置信息存储在 RS 所在机器的内存中。

之所以设计成层级结构,一是易于维护,二是可以存储更多的实体表信息。当集群启动、实体表的分区副本变更时,都会将 location 信息主动汇报到 meta table 中。通过维护并查询这个层级结构,数据库内部就能够确定每一个实体表的位置所在。


2 meta table 的更新



meta table 的更新与查询都是通过 ObPartitionTableOperator 实现。ObPartitionTableOperator 会根据实体表的 table_id,调用不同的 ObPartitionTable 进行处理,然后再交给 ObPartitionTableProxy 执行更新/查询的具体操作。


2.1 __all_core_table 的位置

__all_core_table 作为 1 号表,是 OceanBase 集群自举与服务发现的关键。

__all_core_table leade r 的位置在集群启动时就已经确定了。

RS 的 bootstrap 过程中,需要输入 rs_list,该 rs_list 中会包括每个 zone 的一个 server 地址(IP:port)。例如:

ZONE='ZONE1' SERVER='10.232.144.13:2209', ZONE='zone2' SERVER='10.244.4.14:2203',ZONE='zone3' SERVER='10.244.4.15:2203' 
复制代码

prepare_bootstrap 过程中,会在 rs_list 中的 server 上创建 __all_core_table 的 partition,并选择一个合适的 server 作为 __all_core_table 的 leader。(所谓合适的 leader,通过 primary zone 的形式指定偏好位置,但底层可能由于异常原因通过无主选举返回另一 leader,因此 prepare_bootstrap 中会 create_partition 后会通过循环监测 replica 的 to_leader_time 的形式,等待选举完成,确定真实 leader)最后会发送 RPC 到该 leader 上 execute_bootstrap,启动 RS。


其他 server 如何寻找 __all_core_table 的 leader?

每个 OceanBase server 会有一个 RsMgr ,在内存中维持 master rs 的位置信息。而 __all_core_table 的副本位置信息都存放在 rs 的内存中。其他 server 通过 rpc 的方式,到 master_rs_中拿取 partition_info。若拿取失败,则代表当前内存状态落后,会触发一套多层的刷新寻址过程:

(核心函数:int ObRpcPartitionTable::fetch_root_partition_v2(ObPartitionInfo &partition_info))

  1. 调用 RsMgr 的接口,通过 ObInnerConfigRootAddr 从本地配置项中获取 rootservice_list,并在其中遍历寻找 master_rs。(遍历优化为 rpc 询问各个 server,通过其 partition service 查询 partition leader;rs_list 变化通过心跳刷新并持久化到本地)

  2. 通过 partition service 获取 leader 和 memberlist(leader 无效则在 memberlist 中找一遍)(observer 上有 replica 就能拿到 memberlist )

  3. 在 config 中的 all_server_list 中查找

除以上方式外,RS 还会通过心跳机制,检查 observer 的状态,若 10s 以上无心跳,则认为该 server 的租期超时,向其主动广播自己的位置(broadcast_rs_list)。


2.2 location 汇报机制

汇报是各 observer 向 meta 表更新本机的 replica 相关信息的过程,各 partition 的 location 信息就包含其中。


2.2.1 什么时候汇报?


  1. ObService 启动时,server 主动向 RS 汇报自身所有 partition 信息

  2. 创建 partition

  3. partition 的 leader 发生变化时,通过回调函数的形式触发汇报

  4. RS 主动让 server 汇报

  5. meta table 迁移

  6. 其他...

2.2.2 汇报什么?


以 __all_root_table 为例,系统表需要向其全量汇报的内容包括该表的所有列,其中包含的 svr_ip、svr_port(sql_port)就是核心 location 信息:

+-----------+---------------+--------------+----------------+----------+----------+---------+---------------+-------+------+---------------------------------------+-----------+-----------+--------------+---------------+--------------+-----------------+--------------------+--------------------+-------------+---------+--------------+---------------+-----------------------+------------+--------------------+--------+-----------+--------------------+------------------+------------------+| tenant_id | table_id      | partition_id | svr_ip         | svr_port | sql_port | unit_id | partition_cnt | zone  | role | member_list                           | row_count | data_size | data_version | data_checksum | row_checksum | column_checksum | is_original_leader | is_previous_leader | create_time | rebuild | replica_type | required_size | status                | is_restore | partition_checksum | quorum | fail_list | recovery_timestamp | memstore_percent | data_file_id     |+-----------+---------------+--------------+----------------+----------+----------+---------+---------------+-------+------+---------------------------------------+-----------+-----------+--------------+---------------+--------------+-----------------+--------------------+--------------------+-------------+---------+--------------+---------------+-----------------------+------------+--------------------+--------+-----------+--------------------+------------------+------------------+|         1 | 1099511627779 |            0 | 100.81.215.214 |    21100 |    21101 |       1 |             0 | zone1 |    1 | 100.81.215.214:21100:1625130315574320 |         0 |         0 |            1 |             0 |            0 |                 |                  0 |   1625130317425721 |           0 |       0 |            0 |             0 | REPLICA_STATUS_NORMAL |          0 |                  0 |      1 |           |                  0 |              100 | 1625130308620639 ||         1 | 1099511627779 |            1 | 100.81.215.214 |    21100 |    21101 |       1 |             0 | zone1 |    1 | 100.81.215.214:21100:1625130315575073 |         0 |         0 |            1 |             0 |            0 |                 |                  0 |   1625130317425986 |           0 |       0 |            0 |             0 | REPLICA_STATUS_NORMAL |          0 |                  0 |      1 |           |                  0 |              100 | 1625130308620639 ||         1 | 1099511627779 |            2 | 100.81.215.214 |    21100 |    21101 |       1 |             0 | zone1 |    1 | 100.81.215.214:21100:1625130315575862 |         0 |         0 |            1 |             0 |            0 |                 |                  0 |   1625130317426233 |           0 |       0 |            0 |             0 | REPLICA_STATUS_NORMAL |          0 |                  0 |      1 |           |                  0 |              100 | 1625130308620639 |+-----------+---------------+--------------+----------------+----------+----------+---------+---------------+-------+------+---------------------------------------+-----------+-----------+--------------+---------------+--------------+-----------------+--------------------+--------------------+-------------+---------+--------------+---------------+-----------------------+------------+--------------------+--------+-----------+--------------------+------------------+------------------+
复制代码

系统表的汇报过程均为全量汇报。

但是百万分区情况下,用户表需要汇报的副本数量巨大,针对 leader 切换、无主选举等场景,只向上汇报 leader 信息可有效提高感知 leader 的速度。因此针对用户表,将全量汇报优化为 role 汇报和非 role 汇报两部分。role 汇报只让 leader 更新 role 和 to_leader_time(is_previous_leader)两列信息。


2.2.3 汇报的实现



通过任务队列的方式,异步汇报副本信息,其中通过队列分类区分任务处理的优先级,并且进行批量处理的优化。例如 core_table_queue 中存放需要 __all_core_table 和 __all_root_table 的汇报任务,优先单独处理每个 task。user_table_queue 中存放用户表的汇报任务,进行批量处理优化。



role 汇报时,leader 不仅汇报自身 role 和 to_leader_time ,还会将其他副本的 role 全部更新为 follower ,因此只需要 leader 进行汇报,follower 副本不向 meta table 汇报。

全量汇报时,leader 开启事务修改 meta table ,为保证 leader 的正确性和唯一性,会比较 to_leader_time,并将其他副本的 role 更改为 follower。若此时 follower 汇报,会产生锁冲突。若发生汇报冲突,汇报任务失败后重新放入任务队列进行重试。

用户头像

企业级原生分布式数据库 2020.05.06 加入

github:https://github.com/oceanbase/oceanbase 欢迎大家

评论

发布
暂无评论
OceanBase 源码解读(十四):集群位置信息的存储与汇报_数据库_OceanBase 数据库_InfoQ写作社区