作者简介

循序渐进:Oracle 12c新特性Sharding技术解读_大数据

邝志辉

4年 ORACLE SSC(方案解决中心)高级工程师工作经验,6年 ORACLE Exadata 一体机产品维护经验;8年大型数据库运维经验,曾负责华为、工商银行、广东移动、中国信托、富邦证券等大客户的核心系统数据库维护;现任云和恩墨技术专家,在数据库疑难故障诊断、数据库架构设计、数据迁移、升级、核心系统运维方面有丰富经验。

本文由恩墨大讲堂151期线上分享整理而成。课程回看可点击文末“阅读原文”。 

引言

数据库构架设计中主要有 Shared Everthting、Shared Nothing 和 Shared Disk:

  • Shared Everthting:一般是针对单个主机,完全透明共享 CPU/MEMORY/IO,并行处理能力是最差的,例如 Oracle 的单机模式。
  • Shared Disk:各个处理单元使用自己的私有 CPU和 Memory,共享磁盘系统。典型的代表 Oracle RAC, 它是数据共享,可通过增加节点来提高并行处理的能力,扩展能力较好。其类似于 SMP(对称多处理)模式,但是当存储器接口达到饱和的时候,增加节点并不能获得更高的性能 。
  • Shared Nothing:各个处理单元都有自己私有的 CPU / 内存 / 硬盘等,不存在共享资源,类似于 MPP(大规模并行处理)模式,各处理单元之间通过协议通信,并行处理和扩展能力更好。 各节点相互独立,各自处理自己的数据,处理后的结果可能向上层汇总或在节点间流转。

我们常说的 Sharding 其实就是 Share Nothing 架构,它是把某个表从物理存储上被水平分割,并分配给多台服务器(或多个实例),每台服务器可以独立工作,具备共同的 schema,只需增加服务器数就可以增加处理能力和容量。

Oracle Sharding 简介

Oracle Sharding 是 Oracle 12.2 版本推出的新功能,也称为数据分片,适用于 online transaction processing (OLTP)。Oracle Sharding 基于表分区技术,是一种在数据层将数据水平分区存储到不同的数据库的技术。Sharding 可以实现将一个分区表的不同分区存储在不同的数据库中,每个数据库位于不同的服务器,每一个数据库都称为shard,这些 shard 组成一个逻辑数据库,称为 sharded database (SDB)。这个 table 也称为 sharded table,每个 shard 数据库中保存该表的不同数据集(按照 sharding key 分区),但是他们有相同的列 (columns)。

Shard 是一种 shared-nothing 技术,每个 shard 数据库使用独立的服务器硬件 (CPU、内存等)。Shard 可以运行在单机数据库或者 DATAGUARD / ADG 数据库。

Sharding 其实需要解决三个问题:

  1. 数据的路由
    数据路由是数据库告诉应用程序,你让我查的数据目前在哪个分片上,这条路怎么走过去。
  2. 数据的分片
    数据分片就是实际数据的存放地点,往往每个分片就是一台单独的服务器(含存储)。
  3. 分片的元数据信息保存
    由于分片的数据实际是被切割放在不同的机器上,那么需要有个集中的地点存放数据分片的信息,即分片元数据的信息。

循序渐进:Oracle 12c新特性Sharding技术解读_数据库_02

Oracle Sharding 组成

Oracle Sharding 主要包括下面组件:

  • Sharded database (SDB):逻辑上 SDB 是一个数据库,但是物理上SDB包括多个物理独立的数据库,SDB 类似一个数据库池 (pool),数据库池 (pool) 中包括多个数据库 (Shard)。目前版本最大支持1000个 shard。
  • Shards:SDB 包括多个物理独立的数据库,每一个数据库都称为shard,每个 shard 数据库位于不同的服务器,他们不共享 CPU、内存、存储等资源。每个shard 数据库中保存表的不同数据集, 但是每个 shard 中都有相同的列(columns)。Shard 数据库可以是 Dataguard / ADG,提供高可用性,Shard 数据库(单机或者 ADG)可以通过 GSM deploy 来自动创建,也可以将一个已经通过 dbca 创建好的数据库 add 到 SDB。
  • Shard catalog:是一个 Oracle 数据库,用于集中存储管理 SDB 配置信息,是 SDB 的核心。SDB 配置变化,比如添加/删除 shard,Globalservice 等等,都记录在 Shard catalog。如果应用查询多个 shard 中的数据,那么由 Shard catalog统一协调分配。我们推荐将 Shard catalog 配置为 dataguard 环境,这样可以提供 HA 高可用。如果 Shard catalog 无法访问,那么只会影响一些维护操作和跨shard访问,而不会影响单独的 shard 操作(通过 sharding key 的查询 /DML)。
  • Shard directors:Global Data Service (GDS) 实现对 Sharding 的集中部署和管理。GSM 是 GDS 的核心组件。GSM 作为 Shard director。GSM 类似于监听器,将客户端对 SDB 的请求路由到对应的 shard,负载均衡客户端的访问。
  • Shardgroup:在逻辑上,将一组相同复制属性的 shard 称作 shard group。如有8台主机,其中4台是 shard node 的 primary,另外4台是 shard node 的 standby。那么,我们可以把4台 primary 定义成一个shardgroup,叫 primary_shardgroup,另外4台 standby 定义成另外一个shardgroup,叫 standby_shardgroup。
    注:一个 shardgroup 通常是在一个 datacenter 内。
    Dataguard 可以级联,那么我们可以把 primary 做为一个 shardgroup1,第一级的 dataguard 叫 shardgroup2,第二级的 dataguard 叫 shardgroup2。如下:

循序渐进:Oracle 12c新特性Sharding技术解读_java_03

  • shardspace shardspace 的概念伴随着综合性分片的分片方法(compositesharding method)出现的;如果是系统管理分片方法(system-managed shardingmethod),只有一个默认的 shardspace。所以只有在 compositesharding 下,才有可能出现多个 shardspace。

在 composite sharding 下,数据首先根据 list 或者 range,分成若干个shardspace。然后再根据一致性 hash 进行分片。

注:每个 shardspace 包含一个或者多个复制 shard for HA/DR。

循序渐进:Oracle 12c新特性Sharding技术解读_分布式_04

我们可以按照服务级别来划分 shardspace,如硬件好的,作为 shardspace_gold,硬件差一些的,划做 shardspace_silver:

循序渐进:Oracle 12c新特性Sharding技术解读_java_05

Oracle Sharding 方法

Oracle Sharding 支持3种方法 shard / 分片方法:

  • System-Managed Sharding:这种方法用户不用指定数据存放在哪个 shard 中。Sharding 通过一致性哈希 (CONSISTENT HASH) 方法将数据分区 (partitioning),并自动分布在不同的 Shard。System-managed sharding 只能有一个shardspace。
  • Composite Sharding:这种方法用户创建多个 shardspaces ,每个 shardspaces 中存放一定范围 (range) 或者列表 (list) 的数据。一般情况下,Shardspace 按照区域来划分,比如美国区域的 shard 属于 shardspace cust_america,欧洲的 shard 属于 shardspace cust_europe。
  • Subpartitions with Sharding:Sharding 基于表分区,因此子分区 (Subpartitions) 技术同样适用于 Sharding

Oracle Sharding 对象

被 Shard/分片的表我们成为 shardedtable,这些 sharded table 的集合称为表家族(TableFamily)。

所谓表家族(Table Family)就是指 sharded table 之间是父-子关系,一个表家族(Table Family)中没有任何父表的表叫做根表(root table),每个表家族中只能有一个根表。

在12.2,在一个 SDB 中只支持一个表家族。

在表家族(Table Family)中的所有 sharded table 都按照相同的 sharding key (主键)来分片,主要是由 root table 的 shardingkey 决定的。表家族(Table Family)中有相同 shardingkey 的数据存储在同一个 Chunk 中,这样方便以后的数据移动。

比如: 用户表 – 订单表 – 订单明细表 就是一个表家族,其中用户表是 root table,订单表和订单明细表分别是子表,他们都按照 sharding key (CustNo ) 分区。

循序渐进:Oracle 12c新特性Sharding技术解读_大数据_06

可以通过如下两种方式建立 table family:

通过CONSTRAINT [FK_name] FOREIGN KEY(FK_column) REFERENCES [R_table_name]([R_table_column]) —这种关系可以有级联关系。

SQL> CREATE  SHARDED TABLE Customers

  2  (

  3  CustId  VARCHAR2(60) NOT NULL,

  4  FirstName  VARCHAR2(60),

  5  LastName  VARCHAR2(60),

  6  Class  VARCHAR2(10),

  7  Geo  VARCHAR2(8),

  8  CustProfile  VARCHAR2(4000),

  9  Passwd  RAW(60),

10  CONSTRAINT  pk_customers PRIMARY KEY (CustId),

11  CONSTRAINT  json_customers CHECK (CustProfile IS JSON)

12  )  TABLESPACE SET TSP_SET_1

13  PARTITION  BY CONSISTENT HASH (CustId) PARTITIONS AUTO;

可以看到上面根表(root table)是 customer 表,主键是 CustId,partition 是根据 CONSISTENT HASH,对 CustId 进行分区;

下一级的表是 order 表,主键是 CustId+OrderId,外键是 CustId 且 references Customers 表,partition 是参考外键;

SQL> CREATE  SHARDED TABLE Orders

  2  (

  3  OrderId  INTEGER NOT NULL,

  4  CustId  VARCHAR2(60) NOT NULL,

  5  OrderDate  TIMESTAMP NOT NULL,

  6  SumTotal  NUMBER(19,4),

  7  Status  CHAR(4),

  8  constraint  pk_orders primary key (CustId, OrderId),

  9  constraint  fk_orders_parent foreign key (CustId)

10  references  Customers on delete cascade

11  ) partition  by reference (fk_orders_parent);

再下一级表是 LineItems 表,主键是 CustId+OrderId+ProductId,外键是 CustId+OrderId,即上一层表达主键,partition 是参考外键

SQL> CREATE  SHARDED TABLE LineItems

  2  (

  3  OrderId  INTEGER NOT NULL,

  4  CustId  VARCHAR2(60) NOT NULL,

  5  ProductId  INTEGER NOT NULL,

  6  Price  NUMBER(19,4),

  7  Qty  NUMBER,

  8  constraint  pk_items primary key (CustId, OrderId, ProductId),

  9  constraint  fk_items_parent foreign key (CustId, OrderId)

10  references  Orders on delete cascade

11  )  partition by reference (fk_items_parent);

方法2:同关键字 PARENT 来显式的说明父子关系。这种关系只有父子一层关系,不能级联。

SQL>  CREATE  SHARDED TABLE Customers

2  (  CustNo NUMBER NOT NULL

3  , Name  VARCHAR2(50)

4  ,  Address VARCHAR2(250)

5  ,  region VARCHAR2(20)

6  , class  VARCHAR2(3)

7  ,  signup DATE

8  )

9  PARTITION  BY CONSISTENT HASH (CustNo)

10 TABLESPACE SET  ts1

11 PARTITIONS AUTO

12 ;

SQL> CREATE  SHARDED TABLE  Orders          

2  (  OrderNo  NUMBER                      

3  ,  CustNo  NUMBER                      

4  ,  OrderDate  DATE                      

5  )                                    

6  PARENT  Customers                      

7  PARTITION  BY CONSISTENT HASH (CustNo)

8  TABLESPACE  SET  ts1                    

9  PARTITIONS  AUTO                      

10 ; 

SQL> CREATE  SHARDED TABLE LineItems

2  (  LineNo NUMBER

3  ,  OrderNo NUMBER

4  ,  CustNo NUMBER

5  ,  StockNo NUMBER

6  ,  Quantity NUMBER

7  )

8  PARENT  Customers

9  PARTITION  BY CONSISTENT HASH (CustNo)

10 TABLESPACE SET  ts1

11 PARTITIONS AUTO

12 ;

  • 注意上面的 order 表和 LineItems 表,都是属于同一个父表,即 customers 表。
  • 另外,也注意上面的 CustNo 字段,在每个表中都是有的。而上面说的第一种的级联关系的 tablefamily,可以不在每个表中都存在 CustNo 字段。

上面创建在表,都是 sharded table,即表的各个分区,可以分布在不同的 shard node 上。各个 shard node 上的分区,是不同的。即整个表的内容,是被切割成片,分配在不同的机器上的。

而 duplicatedtable,是整个表达同样内容,在各个机器上是一样的。duplicate table 在各个 shard node上,是以 read only mv 的方式呈现:在 shardcat 中,存在 mast table;在各个shard中,存在 read only mv。duplicated table 的同步:以物化视图的方式同步。

循序渐进:Oracle 12c新特性Sharding技术解读_数据库_07

chunk

chunk 的概念和 table family 密不可分。因为 family 之间的各个表都是有关系的,我们把某个 table family 的一组分区称作一个 chunk。

如 customers 表中的1号~100万号客户信息在一个分区中;在 order 表中,也有1号~100万号的客户的 order 信息,也在一个分区中;另外 LineItems 表中的1号~100万号客户的明细信息,也在一个分区中,我们希望这些相关的分区,都是在一个 shard node 中,避免 cross shard join。所以,我们把这些在同一个 table family 内,相关的分区叫做 chunk。在进行 re-sharding 的时候,是以 chunk 为单位进行移动。因此可以避免 cross shard join。

循序渐进:Oracle 12c新特性Sharding技术解读_数据库_08

注:chunk 的数量在 CREATESHARDCATALOG 的指定,如果不指定,默认值是每个shard 120个chunk

chunk move

chunk move 的条件:

  1. re-sharding 发生,即当 shard 的数量发生改变的时候,会发生 chunk move。
    注:re-sharding 之后,chunk 的数虽然平均,但并不连续。
    如:原来是2个 shard,1~6号 chunk在 shard 1,7~12号 chunk 在 shard2。加多一个 shard 后,1~4号 chunk 在 shard 1,7~10号 chunk 在 shard 2,那么5~6,11~12号 chunk 在 shard 3 上。即:总是挪已经存在的 shard node 上的后面部分 chunk。
  2. DBA 手工发起:move chunk-chunk 7 -source sh2 -target sh1。将 chunk 7 从 shard node sh2 上,挪到 shard node sh1 上。

chunk move 的过程:

在 chunk migration 的时候,chunk 大部分时间是 online 的,但是期间会有几秒钟的时间 chunk 中的 data 处于 read-only 状态。

chunk migration 的过程就是综合利用 rman 增量备份和 TTS 的过程:
level 0 备份源 chunk 相关的 TS,还原到新 shard->开始 FAN(等待几秒)->将源 chunk 相关的 TS 置于 read-only->level 1 备份还原->chunk up(更新 routing table 连新 shard)->chunk down(更新 routing table 断开源 shard)->结束 FAN(等待几秒)->删除原 shard 上的老 chunk

Oracle Sharding 路由选择(Routing)

--直接路由
应用程序初始化时,在应用层/中间件层建立连接池,连接池获取所有 shard 节点的sharding key 范围,并且保存在连接池中,形成 shard topologycache(拓扑缓存),Cache 提供了一个快速的方法直接将请求路由到具体的 shard。

客户端请求时指定 shard key,直接从连接池获取连接,这种情况下不经过 shard  director / catalog 数据库,直接连接到对应的 shard。

--代理路由
如果客户端执行 select 或者DML 时不指定 shard key 或者执行聚合操作(比如groupby),那么请求发送到 Catalog 数据库,根据 matadata 信息,SQL 编译器决定访问哪些 shards。

为了实现 sharding,Oracle 在连接池和驱动方面都做了增强,提供了新的 API(UCP, JDBC, OCI 等等)在连接创建时来传递 sharding keys。

Sharding 技术的优点和缺点

  • 增加了 SQL 的复杂性
    因为开发人员必须要写更复杂的 SQL 来处理 sharding 的逻辑。
  • Sharding 本身带来的复杂性
    sharding 软件需要照顾分区,数据平衡, 访问协调,数据完整性
  • 单点故障
    一个 shard 损坏可能导致整张表不可访问。失效接管服务器也更复杂。因为负责失效接管的服务器必须拥有任何可能损坏的 shard 上的数据。
  • 备份也更复杂
    多个 shard 可能都需要同时备份。
  • 维护也更复杂
    比如增加删除索引,增减删除字段,修改表定义等等,都变得更困难
  • 商业 sharding 技术随着节点数的增加,Licensing 费用也会大规模增加

在 Oracle12.2 Sharding 中都无需担心,Oracle 作为一个商业数据库,已通过底层开发规避了这些问题。

单点故障问题可以通过 RAC+Sharding,ADG+Sharding 来规避,但成本也会增加。

Oracle Sharding 技术提供线性扩展和失败隔离的优点

  • 线性扩展
    因为每个 shard 是一个独立的数据库,通过增加新的 Shard 节点,来线性扩展性能。自动 rebalance 数据。
  • 失败隔离
    由于 Shard 是一种 shared-nothing 技术,每个 shard 使用独立的硬件,因此一个 shard 节点出现故障,只会影响到这个 shard 存放的数据,而不会影响到其他shard。
  • 按照地理位置分布数据
    可以选择根据地理位置不同,将数据存储在不同的 shard。
  • 滚动升级
    选择不同时间升级不同的 shard。比如同一时间只升级一个或一部分 shard,那么只有这些升级的 shard 中存储的数据受到影响,其他的 shard 不受到影响,可以继续提供服务。
  • 云部署
    Shard 非常适合部署在 cloud