本文由恩墨大讲堂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 其实需要解决三个问题:
数据的路由
数据路由是数据库告诉应用程序,你让我查的数据目前在哪个分片上,这条路怎么走过去。
数据的分片
数据分片就是实际数据的存放地点,往往每个分片就是一台单独的服务器(含存储)。
分片的元数据信息保存
由于分片的数据实际是被切割放在不同的机器上,那么需要有个集中的地点存放数据分片的信息,即分片元数据的信息。
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。如下:
shardspace shardspace 的概念伴随着综合性分片的分片方法(compositesharding method)出现的;如果是系统管理分片方法(system-managed shardingmethod),只有一个默认的 shardspace。所以只有在 compositesharding 下,才有可能出现多个 shardspace。
在 composite sharding 下,数据首先根据 list 或者 range,分成若干个shardspace。然后再根据一致性 hash 进行分片。
注:每个 shardspace 包含一个或者多个复制 shard for HA/DR。
我们可以按照服务级别来划分 shardspace,如硬件好的,作为 shardspace_gold,硬件差一些的,划做 shardspace_silver:
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 ) 分区。
可以通过如下两种方式建立 table family:
通过CONSTRAINT [FK_name] FOREIGN KEY(FK_column) REFERENCES [R_table_name]([R_table_column]) —这种关系可以有级联关系。
sql> CREATE SHARDED TABLE Customers 2( 3CustId VARCHAR2(60) NOT NULL, 4FirstName VARCHAR2(60), 5LastName VARCHAR2(60), 6Class VARCHAR2(10), 7Geo VARCHAR2(8), 8CustProfile VARCHAR2(4000), 9Passwd RAW(60), 10CONSTRAINT pk_customers PRIMARY KEY (CustId), 11CONSTRAINT json_customers CHECK (CustProfile IS JSON) 12) TABLESPACE SET TSP_SET_1 13PARTITION 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(
3OrderId INTEGER NOT NULL,
4CustId VARCHAR2(60) NOT NULL,
5OrderDate TIMESTAMP NOT NULL,
6SumTotal NUMBER(19,4),
7Status CHAR(4),
8constraint pk_orders primary key (CustId,OrderId),
9constraint fk_orders_parent foreign key (CustId)
10references Customers on delete cascade
11) partition by reference (fk_orders_parent);
再下一级表是 LineItems 表,主键是 CustId+OrderId+ProductId,外键是 CustId+OrderId,即上一层表达主键,partition 是参考外键
sql> CREATE SHARDED TABLE LineItems 2( 3OrderId INTEGER NOT NULL, 5ProductId INTEGER NOT NULL, 6Price NUMBER(19, 7Qty NUMBER, 8constraint pk_items primary key (CustId,OrderId,ProductId), 9constraint fk_items_parent foreign key (CustId,OrderId) 10references 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)
9PARTITION 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)
6PARENT Customers
7PARTITION BY CONSISTENT HASH (CustNo)
8TABLESPACE SET ts1
9PARTITIONS AUTO
10 ;
sql> CREATE SHARDED TABLE LineItems
2( LineNo NUMBER
3,OrderNo NUMBER
4,CustNo NUMBER
5,StockNo NUMBER
6,Quantity NUMBER
7)
8PARENT Customers
9PARTITION 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 的同步:以物化视图的方式同步。
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。
注:chunk 的数量在 CREATESHARDCATALOG 的指定,如果不指定,默认值是每个shard 120个chunk
chunk move
chunk move 的条件:
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。
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 来处理 sharding 的逻辑。
Sharding 本身带来的复杂性
sharding 软件需要照顾分区,数据平衡, 访问协调,数据完整性
单点故障
一个 shard 损坏可能导致整张表不可访问。失效接管服务器也更复杂。因为负责失效接管的服务器必须拥有任何可能损坏的 shard 上的数据。
备份也更复杂
多个 shard 可能都需要同时备份。
维护也更复杂
在 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
资源下载
‘2017DTC’,2017 DTC 大会 PPT
‘DBALIFE’,“DBA 的一天”海报
‘DBA04’,DBA 手记4 经典篇章电子书
‘RACV1’,RAC 系列课程视频及 PPT
‘122ARCH’,Oracle 12.2 体系结构图
‘2017OOW’,Oracle OpenWorld 资料
‘PRELECTION’,大讲堂讲师课程资料