作者:郑增权,爱可生 DBA 团队成员,OceanBase 和 MySQL 数据库技术爱好者。
爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
本文约 4200 字,预计阅读需要 15 分钟。
对于分布式数据库来说,当多个数据副本间发生半数异常时(一半副本故障或与另一半网络隔离),可以通过集群之外的仲裁服务来参与变更决策(选主/成员组变更),进而恢复服务。OceanBase 数据库 V4.1.0 版本开始支持 仲裁服务(Arbitratrion Service)[1]。
某客户基于节约成本的想法,欲使用 OceanBase 仲裁服务功能,架构副本类型如下:
存在的疑虑:
本文基于如上 2 个问题展开实验,记录相关过程和结果,为类似需求评估提供参考。
OceanBase 数据库仲裁服务(Arbitratrion Service)是一种基于 Paxos 多副本容灾方案提出的新型高可用方案。
仲裁服务独立于 OceanBase 集群部署,是一个以特殊模式启动的轻量级 observer 进程,它承载着日志流级别的仲裁成员。
仲裁成员具备如下特征:
当半数全功能副本故障导致日志同步失败并且达到日志流降级控制时间时,仲裁服务会自动执行日志流降级流程,将故障副本从成员列表中剔除,从而恢复服务,且能做到 RPO = 0。待故障的全功能副本恢复时,仲裁服务又会执行日志流升级流程,将被降级的副本重新加入成员列表,提供更高的可用性保证。
OceanBase 数据库参考传统数据库分区表的概念,把一张表格的数据划分成不同的分区(Partition)。在 V4.0.0 版本,分区是用户创建的逻辑对象,是划分和管理表数据的一种机制。
每个分区都有其对应的数据存储对象,称之为分片(Tablet),它具备存储数据的能力,支持在机器之间迁移(transfer),是数据均衡的最小单位。
日志流是由 OceanBase 数据库自动创建和管理的实体,它代表了一批数据的集合,包括若干 Tablet 和有序的 Redo 日志流。它通过 Paxos 协议实现了多副本日志同步,保证副本间数据的一致性,实现了数据的高可用。
日志流 Leader 上运行的仲裁服务发现一些副本在 arbitration_timeout
(默认值为 5s)内没有向 Leader 回复日志确认消息,仲裁服务将执行进一步检查,准备对日志不同步的副本进行日志流降级操作。
仲裁服务通过周期性探测,检查日志不同步的副本是否存在降级策略中所列的异常,如果存在异常,则执行日志流降级操作。
注意:仅当故障副本(包括已降级的副本)总数等于全功能副本总数的一半时,仲裁服务才会执行日志流降级操作。例如,4F1A 部署场景下:
mysql_ob
租户日志流,可以看到有 3 个日志流。select tenant_id,ls_id from oceanbase.CDB_OB_TABLET_TO_LS where tenant_id = 1002 group by LS_ID;
SELECT * FROM oceanbase.DBA_OB_SERVERS;
mysql_ob
的 leader/follower
角色信息。select b.tenant_name,a.tenant_id,a.ls_id,a.zone,a.svr_ip,a.role from cdb_ob_table_locations a join __all_tenant b on a.tenant_id = b.tenant_id where a.tenant_id = 1002 group by role;
select * from DBA_OB_ARBITRATION_SERVICE;
mysql_ob
为 2F1A 架构(2F:10.186.64.161/163 , 1A:10.186.64.164)。SELECT * FROM oceanbase.GV$OB_ARBITRATION_SERVICE_STATUS;
select TENANT_ID,TENANT_NAME,PRIMARY_ZONE,STATUS,TENANT_ROLE,SWITCHOVER_STATUS,ARBITRATION_SERVICE_STATUS from DBA_OB_TENANTS;
show parameters like 'server_permanent_offline_time';
ALTER SYSTEM SET server_permanent_offline_time='60s';
show parameters like 'server_permanent_offline_time';
evan.time_table
表写入数据。select evan.time_table
表的最新数据。模拟故障:kill 掉第 1 个全能型副本
业务租户 leader 节点执行。
ps -ef | grep observer | grep -v "grep"
date && kill -9 $(ps aux | grep "observer" | grep -v "grep" | awk '{print $2}') && ps -ef | grep observer | grep -v grep && date
当故障副本(包括已降级的副本)总数等于全功能副本总数的一半时,仲裁服务才会执行日志流降级操作。
SELECT * FROM oceanbase.DBA_OB_SERVER_EVENT_HISTORY WHERE EVENT LIKE "%DEGRADE%" AND VALUE1 = 1002 AND TIMESTAMP >= '2024-05-06 15:53%' ORDER BY 1 ;
SELECT * FROM oceanbase.DBA_OB_SERVERS;
无法与 161 节点联通。
SELECT * FROM oceanbase.GV$OB_ARBITRATION_SERVICE_STATUS;
select * from __all_rootservice_event_history where event='permanent_offline' and gmt_create like '2024-05-06%' \G
time_table
实际是否有数据插入失败。select * from evan.time_table where time >= '2024-05-06 15:53:37' order by time limit 20;
故障模拟:kill 掉第 2 个全能型副本。
ps -ef | grep observer | grep -v "grep"
date && kill -9 $(ps aux | grep "observer" | grep -v "grep" | awk '{print $2}') && ps -ef | grep observer | grep -v grep && date
处于异常状态。
处于异常状态。
无主状态,执行 SQL 超时。
select b.tenant_name,a.tenant_id,a.ls_id,a.zone,a.svr_ip,a.role from cdb_ob_table_locations a join __all_tenant b on a.tenant_id = b.tenant_id where a.tenant_id = 1002 group by role;
SELECT * FROM oceanbase.DBA_OB_SERVER_EVENT_HISTORY WHERE EVENT LIKE "%DEGRADE%" AND VALUE1 = 1002 AND TIMESTAMP >= '2024-05-06 16%' ORDER BY 1 ;
SELECT * FROM oceanbase.DBA_OB_SERVERS;
161 和 163 节点均无法联通。
161 和 163 节点均被标记永久下线。
select * from __all_rootservice_event_history where event='permanent_offline' and gmt_create like '2024-05-06%' \G
time_table
实际是否有数据插入失败。租户故障期间无法查询,恢复正常后补图。
select * from evan.time_table where time >= '2024-05-06 16:04:25' order by time limit 20;
161 和 163 节点均存在租约过期记录。
SELECT * FROM __all_rootservice_event_history WHERE module = 'server' AND event = 'lease_expire' AND gmt_create > usec_to_time(time_to_usec(now())-3600*1000000) ORDER BY gmt_create;
cd /home/admin/oceanbase/log && grep "ret=-4038" observer.log
由于此时租户已经不满足多数派,处于故障状态,我们应该先启动故障时间较晚的 OBServer 节点,再启动故障时间较早的 OBServer 节点。(通过 observer.log
最后写入的时间点做判断)
tail -1 /home/admin/oceanbase/log/observer.log
根据上一步骤判断 163 节点 observer.log
较新。
su - admin
cd /home/admin/oceanbase
date && ./bin/observer
ps -ef | grep observer | grep -v "grep"
16:24:56 写入数据成功。
16:24:55 读取数据成功(脚本打印时间每隔1秒打印一次,存在细微误差属正常情况)。
SELECT * FROM oceanbase.DBA_OB_SERVERS;
根据之前的步骤判断 161 节点 observer.log
较旧,后启动。
su - admin
cd /home/admin/oceanbase
date && ./bin/observer
ps -ef | grep observer | grep -v "grep"
确认 161 节点 OBServer 状态变成 ACTIVE。
SELECT * FROM oceanbase.DBA_OB_SERVERS;
正常写入。
正常读取。
oceanbase.DBA_OB_UNIT_JOBS
视图查看数据补全进度。如果查询结果为空,则表示 Unit 迁移完成,数据补全成功。
SELECT * FROM oceanbase.DBA_OB_UNIT_JOBS WHERE JOB_TYPE = 'MIGRATE_UNIT';
time_table
的 tenant_id
和 ls_id
(日志流 ID)。SELECT TENANT_ID, LS_ID FROM oceanbase.CDB_OB_TABLET_TO_LS WHERE TABLET_ID = (SELECT DATA_OBJECT_ID FROM oceanbase.CDB_OBJECTS WHERE OBJECT_NAME ='time_table' AND OBJECT_TYPE='TABLE');
time_table
对应日志流的选举记录。lease_time:当 Root Service 累计超过 lease_time 时间没有收到过某节点的任意心跳数据包时,Root Service 认为该 observer 进程短暂断线,Root Service 会标记该节点的心跳状为 lease_expired。
SELECT * FROM DBA_OB_SERVER_EVENT_HISTORY WHERE MODULE LIKE '%ELECTION%' and TIMESTAMP >= '2024-05-06 15:53:37' AND NAME1 = 'TENANT_ID' AND VALUE1 = '1002' AND NAME2 = 'LS_ID' AND VALUE2 =1001 ORDER BY TIMESTAMP;
ALTER SYSTEM SET server_permanent_offline_time='3600s';
show parameters like 'server_permanent_offline_time';
server_permanent_offline_time
调成 60sserver_permanent_offline_time
调回3600s结论:租户切主期间短暂读写异常,后续恢复正常读写。
结论:可恢复正常。
仲裁服务两个典型的应用场景在于 “自动选主提升同城自动容灾能力” 和 “降低跨城带宽提升两地三中心稳定性”,感兴趣的读者可查看《OceanBase 助力企业应对数据库转型深水区挑战》[2] 中关于仲裁服务章节的内容。
[1]
OceanBae 仲裁服务: https://www.oceanbase.com/knowledge-base/oceanbase-database-1000000000261688?back=kb
[2]
OceanBase 助力企业应对数据库转型深水区挑战: https://open.oceanbase.com/blog/7742925344
本文关键字:#OceanBase# #高可用# #仲裁服务# #分布式#