为了数据安全和提供高可用的数据服务,每个分区数据在物理上存储多份,每一份叫做分区的一个副本。每个副本,包括存储在磁盘上的静态数据(SSTable)、存储在内存的增量数据(MemTable)、以及记录事务的日志三类主要的数据。根据存储数据种类的不同,副本有几种不同的类型,以支持不同业务在在数据安全、性能伸缩性、可用性、成本等之间的选择。
- 全能型副本
也就是目前支持的普通副本,拥有事务日志、MemTable 和 SSTable 等全部完整的数据和功能。它可以随时快速切换为 leader 对外提供服务。
- 日志型副本
只包含日志的副本,没有 MemTable 和 SSTable。它参与日志投票并对外提供日志服务,可以参与其他副本的恢复,但自己不能变为主提供数据库服务。
- 只读型副本
包含完整的日志、MemTable 和 SSTable等,但是它的日志比较特殊。它不作为paxos成员参与日志的投票,而是作为一个观察者实时追赶 paxos 成员的日志,并在本地回放。这种副本可以在业务对读取数据的一致性要求不高的时候提供只读服务。因其不加入 paxos 成员组,又不会造成投票成员增加导致事务提交延时的增加。
三种副本的具体差异如下表所示。
类型 | LOG | MemTable | SSTable | 数据安全 | 恢复为 leader 时间 | 资源成本 | 服务 | 名称(简写) |
全能型 | 有,参与投票(SYNC_CLOG) | 有(WITH_MEMSTORE) | 有(WITH_SSSTORE) | 高 | 快 | 高 | leader 提供读写,follower 可非一致性读 | FULL(F) |
日志型 | 有,参与投票(SYNC_CLOG) | 无(WITHOUT_MEMSTORE) | 无(WITHOUT_SSSTORE) | 低 | 不支持 | 低 | 不可读写 | LOGONLY(L) |
只读型 | 有,异步日志,但不属于 paxos 组,只是 listener (ASYNC_CLOG) | 有(WITH_MEMSTORE) | 有(WITH_SSSTORE) | 中 | 不支持 | 高 | 可非一致性读 | READONLY(R) |
租户内创建的分区都是存储在资源单元中,分区副本的个数和分布方式是由租户的资源单元决定的。
OceanBase 数据库集群内部 Zone 是副本复制的边界,通常情况每个 Zone 会存储一份所有数据的副本,一个分区在每个 Zone 内有且只有一个副本。当租户的资源单元是分布在一个 Region 的三个 Zone 内时,租户创建的分区会有三个副本,在每个 Zone 内有一个副本。当租户的资源单元是分布在三个 Region 的五个 Zone 时,租户创建的分区表会有五个副本。
一个分区的在多个副本中有一个副本会被选举成主副本,主副本负责数据库服务,提供读写能力,数据的修改以 Redo 日志的形式通过 Paxos 一致性协议在多个副本间同步,其他备副本通过回放同步到 Redo 日志,保持与主副本的一致。
分区主副本的选择策略由租户的 primary_zone 属性决定,在创建租户的命令中可以指定 primary_zone 属性,也可以用 alter 语句来修改。
示例:创建租户并指定 primary_zone
下面的语句创建了一个 primary_zone 在 zone1 的租户。primary_zone=’zone1’ 表示租户 local_warehouse 创建的分区中所有的主都选在 zone1 上,只有当 zone1 出现故障时,分区的主才会选到其他的 Zone 上。
create tenant tt1 replica_num = 1, primary_zone='zone1', resource_pool_list=('pool_large1');
primay_zone 还可以指定多个 Zone,而且可以指定优先级。
比如:
- primary_zone=’zone1,zone2’,表示主在 zone1、zone2 两个 Zone 上均匀分布。
- primary_zone=’zone1;zone2;zone3’,表示主在 zone1 上,如果 zone1 出现故障,那么主选到 zone2 上。
primary_zone 的配置中,逗号表示前后的 Zone 是同等优先级,分号表示前后的 Zone 是先后的优先级。逗号和分号可以混用,primary_zone=’zone1,zone2;zone3,zone4;zone5’ 表示的是主选在 zone1 和 zone2 上均匀分布,如果 zone1 出现故障,那么主会选在 zone2 上,如果 zone1、zone2 出现故障,那么主会选在 zone3、zone4 上均匀分布。