OB君:好消息!我们将推出分布式数据库OceanBase产品模块原理简介系列内容,其中包含了OceanBase最核心的SQL引擎、存储引擎、内存管理、分布式并行计算引擎等重要的技术原理,很多内容还是第一次对外发布哦~
欢迎关注OceanBase公众号,我们将在接下来的一个多月的时间里陆续为大家推送该系列的完整13篇内容,帮助数据库从业者建立更系统完善的数据库知识体系。
第四期我们为大家带来分布式数据库OceanBase的总控服务RootService的介绍,更多内容敬请期待!


OceanBase是由阿里巴巴和蚂蚁金服完全自主研发的分布式关系型数据库,有着极致的在线伸缩和负载均衡、高可用和强一致能力。在使用OceanBase时,除了关注SQL功能和性能之外,理解OceanBase核心能力的关键就是OceanBase的总控服务。
RootService服务是OceanBase集群内部租户(sys)里的一个服务,依托于表__all_core_table。RootService服务主要是做一些集群级别的管理和任务调度等。虽然有点中心的特点,由于表__all_core_table是至少三副本的,并且选举模块会保证这个表的高可用,所以RootService也是有高可用的。此外RootService的工作通常都很少,因此也不会成为集群性能的瓶颈。

功能总览
集群自举(初始化)。在搭建OceanBase集群里有一步很关键就是bootstrap操作。指定三个节点选举出一个leader后就初始化相关内部表,然后RootService服务就开始提供服务,OceanBase集群也就搭建成功了。
集群架构管理。如集群布局Zone的创建、类型管理。
OBServer节点生命周期管理。如节点心跳检测、节点上线和下线、新增和删除等。
集群级别参数变更。指将参数(parameter)的变更发往各个节点上SQL引擎执行。
集群资源管理。如定义资源单元(unit)的规格,分配资源单元Unit、创建资源池、创建租户。以及相应的变更操作(修改或删除)。
集群分区负载均衡。计算各个资源单元的负载和节点负载,发起分区迁移任务和分区leader切换任务。
指导分区leader选举。分区的选举由选举模块负责,RootService只是根据一些规则(如primary_zone或locality)影响分区的leader选举。
合并转储冻结管理。OceanBase的增量单独存放在内存memtable里,这部份内存使用率超过阈值后需要冻结、转储到磁盘或者跟基线数据做合并落盘。
数据库对象变更任务管理(DDL)。主要是所有租户的建表、视图、存储过程等DDL语句的任务管理。
其他。随着版本的递进,一些适合RootService集中做的事情会陆续加入。
cd/home/admin/node1/oceanbase&&/home/admin/node1/oceanbase/bin/observer-ibond0-P2882-p2881-zzone1-d/home/admin/node1/oceanbase/store/obdemo-r'11.***.84.78:2882:2881;11.***.84.79:2882:2881;11.***.84.83:2882:2881'-c20190423-nobdemo-o"system_memory=10G,memory_limit=51200M,datafile_size=100G,config_additional_dir=/data/data/1/obdemo/etc3;/data/log/log1/obdemo/etc2"
其中-r参数就是指定了rootservice_list地址。第一次搭建的时候,需要用命令初始化该服务。
mysql -h11.***.84.78 -uroot -P2881 -palter system bootstrap ZONE 'zone1' SERVER '11.***.84.78:2882', ZONE 'zone2' SERVER '11.***.84.79:2882', ZONE 'zone3' SERVER '11.***.84.83:2882';
上面指定的RootService是固定的地址,如果指定的节点多数派都不可用则可能导致本节点启动失败。所以常用的指定方法是通过参数obconfig_url指定。
下面是启动示例:
cd home/admin/node1/oceanbase && bin/observer -i bond0 -P 2882 -p 2881 -z zone4 -dhome/admin/oceanbase/store/obdemo -c 20190423 -n obdemo -o "memory_limit=120G,datafile_size=250G,config_additional_dir=/data/1/obdemo/etc3;/data/log1/obdemo/etc2,obconfig_url=http://11.***.84.83:8088/services?Action=ObRootServiceInfo&ObRegion=obdemo"
$curl -Ls "http://11.***.84.83:8088/services?Action=ObRootServiceInfo&ObRegion=obdemo"{"Code":200,"Cost":1,"Data":{"ObRegion":"obdemo","ObRegionId":20190423,"RsList":[{"address":"11.***.84.79:2882","role":"LEADER","sql_port":2881},{"address":"11.***.84.78:2882","role":"FOLLOWER","sql_port":2881},{"address":"11.***.84.84:2882","role":"FOLLOWER","sql_port":2881}],"ReadonlyRsList":[]},"Message":"successful","Success":true}
OBServer节点生命周期管理
bootstrap操作只需要做一次,一个集群只有一个RootService服务。其他节点在启动时指定rootservice_list后,在集群sys租户内用一个命令将新节点注册到集群中。
mysql -h11.***.84.78 -uroot@sys -P2881 -prootpwd -c -A oceanbasealter system add server '11.***.84.78:3882' zone 'zone1';alter system add server '11.***.84.79:3882' zone 'zone2';alter system add server '11.***.84.83:3882' zone 'zone3';
节点加进集群后,自动上线为active状态。

节点生命周期如上图,相应操作SQL语法如下:
alter_system_server_stmt:ALTER SYSTEM server_action SERVER ip_port_list [zone];server_action:ADD| DELETE| CANCEL DELETE| START| STOP| FORCE STOPip_port_list:ip_port [, ip_port ...]
如果要下线服务器,稳妥的做法是先stop server,然后delete server。delete server需要逐个的删除节点上的分区副本,会触发分区迁移逻辑。这个会需要一段时间,这期间还可以发起cancel操作。

alter_system_zone_stmt:ADD ZONE zone_name[zone_option_list]| {ALTER | CHANGE | MODIFY} ZONE zone_name[SET] zone_option_list| {DELETE | START | STOP | FORCE STOP} ZONE zone_namezone_option_list:zone_option [, zone_option ...]zone_option:region| idc| ZONE_TYPE {READONLY | READWRITE}idc:STR_VALUE
alter_system_replica_stmt:ALTER SYSTEM replica_action;replica_action:SWITCH REPLICA{LEADER | FOLLOWER}{replica server | server [tenant_name] | zone [tenant_name]}| DROP REPLICAreplica server [create_timestamp] [zone] [FORCE]| {MOVE | COPY} REPLICAreplica source destination| REPORT REPLICA{zone | server}| RECYCLE REPLICA{zone | server}| {ALTER | CHANGE | MODIFY} REPLICAreplica server [set] REPLICA_TYPE = replica_typesource:SOURCE [=] 'ip:port'destination:DESTINATION [=] 'ip:port'partition_idx | partition_count | table_id | task_id:INT_VALUEcreate_timestamp:CREATE_TIMESTAMP [=] INT_VALUEtenant_name_list:tenant_name [, tenant_name ...]replica_type:{FULL | F}| {READONLY | R}| {LOGONLY | L}
常用场景:
手动或自动打散分区副本分布。使用movereplica命令。这也是分区迁移的命令。OB负载均衡就是靠分区自动迁移实现。
删除/复制/回收副本。
修改副本类型。从全功能副本改为日志副本、或者只读副本。多用于数据库跨机房在线搬迁。
leader选举(切换)。可以使用switch replica强制将某个副本角色变更为leader。
MySQL [oceanbase]> select tenant_name,primary_zone,locality,info from __all_tenant;+-------------+-------------------+---------------------------------------------+---------------+| tenant_name | primary_zone | locality | info |+-------------+-------------------+---------------------------------------------+---------------+| sys | zone1;zone2,zone3 | FULL{1}@zone1, FULL{1}@zone2, FULL{1}@zone3 | system tenant || t_obdemo | RANDOM | FULL{1}@zone1, FULL{1}@zone2, FULL{1}@zone3 | |+-------------+-------------------+---------------------------------------------+---------------+2 rows in set (0.00 sec)
同时OceanBase还提供表分组(tablegroup)用于将有业务强联系的不同分区在空间分配时约束在一个节点的资源单元(Unit)内部。

MySQL [sysbenchtest]> show create table sbtest1\G*************************** 1. row ***************************Table: sbtest1Create Table: CREATE TABLE `sbtest1` (`id` int(11) NOT NULL AUTO_INCREMENT,`k` int(11) NOT NULL DEFAULT '0',`c` char(120) NOT NULL DEFAULT '',`pad` char(60) NOT NULL DEFAULT '',PRIMARY KEY (`id`, `k`)) AUTO_INCREMENT = 12000001 DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.0' REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 10partition by hash(k) partitions 51 row in set (0.15 sec)MySQL [sysbenchtest]> create tablegroup tg_sbtest partition by hash partitions 5;Query OK, 0 rows affected (0.01 sec)MySQL [sysbenchtest]> alter tablegroup tg_sbtest add sbtest1,sbtest2,sbtest3,sbtest4,sbtest5,sbtest6,sbtest7,sbtest8;Query OK, 0 rows affected (0.04 sec)MySQL [sysbenchtest]> show tablegroups;+-----------------+------------+---------------+| Tablegroup_name | Table_name | Database_name |+-----------------+------------+---------------+| oceanbase | NULL | NULL || tg_sbtest | sbtest1 | sysbenchtest || tg_sbtest | sbtest2 | sysbenchtest || tg_sbtest | sbtest3 | sysbenchtest || tg_sbtest | sbtest4 | sysbenchtest || tg_sbtest | sbtest5 | sysbenchtest || tg_sbtest | sbtest6 | sysbenchtest || tg_sbtest | sbtest7 | sysbenchtest || tg_sbtest | sbtest8 | sysbenchtest |+-----------------+------------+---------------+9 rows in set (0.05 sec)

select t3.tenant_name,t4.database_name, t5.tablegroup_name, t1.table_name,t2.partition_id, t2.svr_ip, t2.svr_portfrom __all_table t1 join gv$partition t2 on (t1.tenant_id=t2.tenant_id and t1.table_id=t2.table_id)join __all_tenant t3 on (t1.tenant_id=t3.tenant_id)join __all_database t4 on (t1.tenant_id=t4.tenant_id and t1.database_id=t4.database_id)left join __all_tablegroup t5 on (t1.tablegroup_id=t5.tablegroup_id)where t3.tenant_id=1001 and t2.role=1order by t4.database_name, t5.tablegroup_name, t1.table_name,t2.partition_id, t2.svr_ip, t2.svr_port;

冻结/转储/合并逻辑

alter system set freeze_trigger_percentage=30;
alter system set minor_freeze_times=100;br
alter system minor freeze;
上面冻结会自动触发转储,转储次数用尽时会触发合并。合并也可以手动触发,命令是major freeze,此时不会转储。合并指的是内存中的增量数据跟对应的基线数据在内存里合并,然后以SSTable的格式写入到磁盘数据文件中。注意合并的时候只有原SSTable有变化的部分才会写回磁盘。所以OceanBase的数据模型虽然是LSM架构,但是没有写放大困扰。
alter system major freeze;
select * from __all_rootservice_event_Historyorder by gmt_create desc limit 50;

select module,event,count(*) from __all_rootservice_event_Historygroup by module,event order by module;

alter system set obconfig_url='http://10.***.167.20:8082/services?Action=ObRootServiceInfo&User_ID=alibaba&UID=admin&ObRegion=oms_2x'server = '11.***.84.78:2882';
OCP API模拟
注:下面的***是出于安全考虑估计屏蔽显示的。1. 写一个 rs.json文件模拟api的结果$cat home/admin/test/rs.json{"Code":200,"Cost":3,"Data":{"ObRegionId":2100006,"RsList":[{"sql_port":2881,"address":"11.***.84.83:2882","role":"LEADER"},{"sql_port":2881,"address":"11.***.84.78:2882","role":"FOLLOWER"},{"sql_port":2881,"address":"11.***.84.84:2882","role":"FOLLOWER"}],"ReadonlyRsList":[],"ObRegion":"oms_2x"},"Message":"successful","Success":true,"Trace":"9.9.9.9:10.***.167.20:1556446480671"}2. 本地用python起一个httpserver[admin@h07d17162.sqa.eu95 /home/admin/test]$python -m SimpleHTTPServer 8080Serving HTTP on 0.0.0.0 port 8080 ...3. 验证api[admin@h07d17162.sqa.eu95 /home/admin/oceanbase]$curl -L 'http://127.0.0.1:8080/rs.json'{"Code":200,"Cost":3,"Data":{"ObRegionId":2100006,"RsList":[{"sql_port":2881,"address":"11.***.84.83:2882","role":"LEADER"},{"sql_port":2881,"address":"11.***.84.78:2882","role":"FOLLOWER"},{"sql_port":2881,"address":"11.***.84.84:2882","role":"FOLLOWER"}],"ReadonlyRsList":[],"ObRegion":"oms_2x"},"Message":"successful","Success":true,"Trace":"9.9.9.9:10.***.167.20:1556446480671"}4. 以新的参数启动OBServer[admin@h07d17162.sqa.eu95 /home/admin/oceanbase]$bin/observer -o "obconfig_url='http://11.***.84.78:8080/rs.json'"bin/observer -o obconfig_url='http://11.***.84.78:8080/rs.json'optstr: obconfig_url='http://11.***.84.78:8080/rs.json'[2019-05-09 17:27:18.094254] ERROR [LIB] pidfile_test (utility.cpp:1152)[71476][0][Y0-0000000000000000] [lt=0] fid file doesn't exist(pidfile="run/observer.pid")BACKTRACE:0x7bfc359 0x7b400ab 0x6f4419 0x7c00a96 0x413266 0x7f7a35604445 0x43c025
综上所述,OceanBase的总控服务会负责集群资源的分配、调整(伸缩)、分区高可用切换、负载均衡等相关任务的调度等。OceanBase服务自身也具备高可用能力,服务地址还可以通过外部API获取。
<完>
— 想了解更多OceanBase背后的技术秘密?
— 想与蚂蚁金服OceanBase的技术专家深入交流?
— 有钉钉的小伙伴也可以加入OceanBase钉钉互动群:搜索群号21949783


● 最系统!一篇文章读懂OceanBase数据库的产品家族体系
● OceanBase SQL 引擎的模块介绍和调优实践分享
▼内容这么棒,还不赶紧扫码关注一下!▼





