循序漸進:Oracle 12c新特性Sharding技術解讀
引言
資料庫構架設計中主要有 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 ( 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 的同步:以物化檢視的方式同步。
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 的複雜性
因為開發人員必須要寫更復雜的 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