引言
数据库构架设计中主要有 Shared Everthting、Shared Nothing 和 Shared Disk:
我们常说的 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 主要包括下面组件:
在 composite sharding 下,数据首先根据 list 或者 range,分成若干个shardspace。然后再根据一致性 hash 进行分片。
注:每个 shardspace 包含一个或者多个复制 shard for HA/DR。
我们可以按照服务级别来划分 shardspace,如硬件好的,作为 shardspace_gold,硬件差一些的,划做 shardspace_silver:
Oracle Sharding 方法
Oracle Sharding 支持3种方法 shard / 分片方法:
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 ( 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_113 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 cascade11 ) 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 cascade11 ) partition by reference (fk_items_parent); |
---|
方法2:同关键字 PARENT 来显式的说明父子关系。这种关系只有父子一层关系,不能级联。
SQL> CREATE SHARDED TABLE Customers2 ( CustNo NUMBER NOT NULL3 , Name VARCHAR2(50)4 , Address VARCHAR2(250)5 , region VARCHAR2(20)6 , class VARCHAR2(3)7 , signup DATE8 )9 PARTITION BY CONSISTENT HASH (CustNo)10 TABLESPACE SET ts111 PARTITIONS AUTO12 ; |
---|
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 LineItems2 ( LineNo NUMBER3 , OrderNo NUMBER4 , CustNo NUMBER5 , StockNo NUMBER6 , Quantity NUMBER7 )8 PARENT Customers9 PARTITION BY CONSISTENT HASH (CustNo)10 TABLESPACE SET ts111 PARTITIONS AUTO12 ; |
---|
上面创建在表,都是 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 的条件:
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 技术的优点和缺点
在 Oracle12.2 Sharding 中都无需担心,Oracle 作为一个商业数据库,已通过底层开发规避了这些问题。
单点故障问题可以通过 RAC+Sharding,ADG+Sharding 来规避,但成本也会增加。
Oracle Sharding 技术提供线性扩展和失败隔离的优点