ShardingSphere介紹


Apache ShardingSphere 是一套開源的分布式數據庫中間件解決方案組成的生態圈,它由 JDBC、Proxy 和 Sidecar(規划中)這 3 款相互獨立,卻又能夠混合部署配合使用的產品組成。 它們均提供標准化的數據分片、分布式事務和數據庫治理功能,可適用於如 Java 同構、異構語言、雲原生等各種多樣化的應用場景。

一、背景

傳統的將數據集中存儲至單一數據節點的解決方案,在性能、可用性和運維成本這三方面已經難於滿足互聯網的海量數據場景。

從性能方面來說,由於關系型數據庫大多采用B+樹類型的索引,在數據量超過閾值的情況下,索引深度的增加也將使得磁盤訪問的IO次數增加,進而導致查詢性能的下降;同時,高並發訪問請求也使得集中式數據庫成為系統的最大瓶頸。

從可用性的方面來講,服務化的無狀態型,能夠達到較小成本的隨意擴容,這必然導致系統的最終壓力都落在數據庫之上。而單一的數據節點,或者簡單的主從架構,已經越來越難以承擔。數據庫的可用性,已成為整個系統的關鍵。

從運維成本方面考慮,當一個數據庫實例中的數據達到閾值以上,對於DBA的運維壓力就會增大。數據備份和恢復的時間成本都將隨着數據量的大小而愈發不可控。一般來講,單一數據庫實例的數據的閾值在1TB之內,是比較合理的范圍。

在傳統的關系型數據庫無法滿足互聯網場景需要的情況下,將數據存儲至原生支持分布式的NoSQL的嘗試越來越多。 但NoSQL對SQL的不兼容性以及生態圈的不完善,使得它們在與關系型數據庫的博弈中始終無法完成致命一擊,而關系型數據庫的地位卻依然不可撼動。

數據分片指按照某個維度將存放在單一數據庫中的數據分散地存放至多個數據庫或表中以達到提升性能瓶頸以及可用性的效果。 數據分片的有效手段是對關系型數據庫進行分庫和分表。分庫和分表均可以有效的避免由數據量超過可承受閾值而產生的查詢瓶頸。 除此之外,分庫還能夠用於有效的分散對數據庫單點的訪問量;分表雖然無法緩解數據庫壓力,但卻能夠提供盡量將分布式事務轉化為本地事務的可能,一旦涉及到跨庫的更新操作,分布式事務往往會使問題變得復雜。 使用多主多從的分片方式,可以有效的避免數據單點,從而提升數據架構的可用性。

通過分庫和分表進行數據的拆分來使得各個表的數據量保持在閾值以下,以及對流量進行疏導應對高訪問量,是應對高並發和海量數據系統的有效手段。 數據分片的拆分方式又分為垂直分片和水平分片。

垂直分片

按照業務拆分的方式稱為垂直分片,又稱為縱向拆分,它的核心理念是專庫專用。 在拆分之前,一個數據庫由多個數據表構成,每個表對應着不同的業務。而拆分之后,則是按照業務將表進行歸類,分布到不同的數據庫中,從而將壓力分散至不同的數據庫。 下圖展示了根據業務需要,將用戶表和訂單表垂直分片到不同的數據庫的方案。

垂直拆分可以緩解數據量和訪問量帶來的問題,但無法根治。如果垂直拆分之后,表中的數據量依然超過單節點所能承載的閾值,則需要水平分片來進一步處理。

水平分片

水平分片又稱為橫向拆分。 相對於垂直分片,它不再將數據根據業務邏輯分類,而是通過某個字段(或某幾個字段),根據某種規則將數據分散至多個庫或表中,每個分片僅包含數據的一部分。 例如:根據主鍵分片,偶數主鍵的記錄放入0庫(或表),奇數主鍵的記錄放入1庫(或表),如下圖所示。

水平分片從理論上突破了單機數據量處理的瓶頸,並且擴展相對自由,是分庫分表的標准解決方案。

二、概念&功能

數據分片
SQL

① 邏輯表

水平拆分的數據庫(表)的相同邏輯和數據結構表的總稱。例:訂單數據根據主鍵尾數拆分為10張表,分別是t_order_0t_order_9,他們的邏輯表名為t_order

② 真實表

在分片的數據庫中真實存在的物理表。即上個示例中的t_order_0t_order_9

③ 數據節點

數據分片的最小單元。由數據源名稱和數據表組成,例:ds_0.t_order_0

④ 綁定表

指分片規則一致的主表和子表。例如:t_order表和t_order_item表,均按照order_id分片,則此兩張表互為綁定表關系。綁定表之間的多表關聯查詢不會出現笛卡爾積關聯,關聯查詢效率將大大提升。

⑤ 廣播表

指所有的分片數據源中都存在的表,表結構和表中的數據在每個數據庫中均完全一致。適用於數據量不大且需要與海量數據的表進行關聯查詢的場景,例如:字典表。

分片

① 分片鍵

用於分片的數據庫字段,是將數據庫(表)水平拆分的關鍵字段。例:將訂單表中的訂單主鍵的尾數取模分片,則訂單主鍵為分片字段。 SQL中如果無分片字段,將執行全路由,性能較差。 除了對單分片字段的支持,ShardingSphere也支持根據多個字段進行分片。

② 分片算法

通過分片算法將數據分片,支持通過=>=<=><BETWEENIN分片。分片算法需要應用方開發者自行實現,可實現的靈活度非常高。

目前提供4種分片算法。由於分片算法和業務實現緊密相關,因此並未提供內置分片算法,而是通過分片策略將各種場景提煉出來,提供更高層級的抽象,並提供接口讓應用開發者自行實現分片算法。

  • 精確分片算法:對應PreciseShardingAlgorithm,用於處理使用單一鍵作為分片鍵的=與IN進行分片的場景。需要配合StandardShardingStrategy使用。
  • 范圍分片算法:對應RangeShardingAlgorithm,用於處理使用單一鍵作為分片鍵的BETWEEN AND、>、<、>=、<=進行分片的場景。需要配合StandardShardingStrategy使用。
  • 復合分片算法:對應ComplexKeysShardingAlgorithm,用於處理使用多鍵作為分片鍵進行分片的場景,包含多個分片鍵的邏輯較復雜,需要應用開發者自行處理其中的復雜度。需要配合ComplexShardingStrategy使用。
  • Hint分片算法:對應HintShardingAlgorithm,用於處理使用Hint行分片的場景。需要配合HintShardingStrategy使用。

③ 分片策略

包含分片鍵和分片算法,由於分片算法的獨立性,將其獨立抽離。真正可用於分片操作的是分片鍵 + 分片算法,也就是分片策略。目前提供5種分片策略。

  • 標准分片策略:對應StandardShardingStrategy。提供對SQL語句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持單分片鍵,提供PreciseShardingAlgorithm和RangeShardingAlgorithm兩個分片算法。PreciseShardingAlgorithm是必選的,用於處理=和IN的分片。RangeShardingAlgorithm是可選的,用於處理BETWEEN AND, >, <, >=, <=分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND將按照全庫路由處理。
  • 復合分片策略:對應ComplexShardingStrategy。復合分片策略。提供對SQL語句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片鍵,由於多分片鍵之間的關系復雜,因此並未進行過多的封裝,而是直接將分片鍵值組合以及分片操作符透傳至分片算法,完全由應用開發者實現,提供最大的靈活度。
  • 行表達式分片策略:對應InlineShardingStrategy。使用Groovy的表達式,提供對SQL語句中的=和IN的分片操作支持,只支持單分片鍵。對於簡單的分片算法,可以通過簡單的配置使用,從而避免繁瑣的Java代碼開發,如: t_user_$->{u_id % 8} 表示t_user表根據u_id模8,而分成8張表,表名稱為t_user_0t_user_7
  • Hint分片策略:對應HintShardingStrategy。通過Hint指定分片值而非從SQL中提取分片值的方式進行分片的策略。
  • 不分片策略:對應NoneShardingStrategy。不分片的策略。

 ④ SQL Hint

對於分片字段非SQL決定,而由其他外置條件決定的場景,可使用SQL Hint靈活的注入分片字段。例:內部系統,按照員工登錄主鍵分庫,而數據庫中並無此字段。SQL Hint支持通過Java API和SQL注釋(待實現)兩種方式使用。

配置

① 分片規則

分片規則配置的總入口。包含數據源配置、表配置、綁定表配置以及讀寫分離配置等。

② 數據源配置

真實數據源列表。

③ 表配置

邏輯表名稱、數據節點與分表規則的配置。

④ 數據節點配置

用於配置邏輯表與真實表的映射關系。可分為均勻分布和自定義分布兩種形式。

  • 均勻分布:用於配置邏輯表與真實表的映射關系。可分為均勻分布和自定義分布兩種形式。如:db0.t_order0, db0.t_order1, db1.t_order0, db1.t_order1
  • 自定義分布:db0.t_order0, db0.t_order1, db1.t_order2, db1.t_order3, db1.t_order4

⑤ 分片策略配置

對於分片策略存有數據源分片策略和表分片策略兩種維度。兩種策略的API完全相同。

  • 數據源分片策略:對應於DatabaseShardingStrategy。用於配置數據被分配的目標數據源。
  • 表分片策略:對應於TableShardingStrategy。用於配置數據被分配的目標表,該目標表存在與該數據的目標數據源內。故表分片策略是依賴與數據源分片策略的結果的。

⑥ 自增主鍵生成策略

通過在客戶端生成自增主鍵替換以數據庫原生自增主鍵的方式,做到分布式主鍵無重復。

行表達式

行表達式的使用非常直觀,只需要在配置中使用${ expression }或$->{ expression }標識行表達式即可。 目前支持數據節點和分片算法這兩個部分的配置。行表達式的內容使用的是Groovy的語法,Groovy能夠支持的所有操作,行表達式均能夠支持。例如:

${begin..end}表示范圍區間

${[unit1, unit2, unit_x]}表示枚舉值

行表達式中如果出現連續多個${ expression }或$->{ expression }表達式,整個表達式最終的結果將會根據每個子表達式的結果進行笛卡爾組合。

例如,以下行表達式:

${['online', 'offline']}_table${1..3}

最終會解析為:

online_table1, online_table2, online_table3, offline_table1, offline_table2, offline_table3

■ 配置數據節點

對於均勻分布的數據節點,如果數據結構如下:

db0
  ├── t_order0 
  └── t_order1 
db1
  ├── t_order0 
  └── t_order1

用行表達式可以簡化為:

db${0..1}.t_order${0..1}

或者

db$->{0..1}.t_order$->{0..1}

對於自定義的數據節點,如果數據結構如下:

db0
  ├── t_order0 
  └── t_order1 
db1
  ├── t_order2
  ├── t_order3
  └── t_order4

用行表達式可以簡化為:

db0.t_order${0..1},db1.t_order${2..4}

或者

db0.t_order$->{0..1},db1.t_order$->{2..4}

對於有前綴的數據節點,也可以通過行表達式靈活配置,如果數據結構如下:

db0
  ├── t_order_00
  ├── t_order_01
  ├── t_order_02
  ├── t_order_03
  ├── t_order_04
  ├── t_order_05
  ├── t_order_06
  ├── t_order_07
  ├── t_order_08
  ├── t_order_09
  ├── t_order_10
  ├── t_order_11
  ├── t_order_12
  ├── t_order_13
  ├── t_order_14
  ├── t_order_15
  ├── t_order_16
  ├── t_order_17
  ├── t_order_18
  ├── t_order_19
  └── t_order_20
db1
  ├── t_order_00
  ├── t_order_01
  ├── t_order_02
  ├── t_order_03
  ├── t_order_04
  ├── t_order_05
  ├── t_order_06
  ├── t_order_07
  ├── t_order_08
  ├── t_order_09
  ├── t_order_10
  ├── t_order_11
  ├── t_order_12
  ├── t_order_13
  ├── t_order_14
  ├── t_order_15
  ├── t_order_16
  ├── t_order_17
  ├── t_order_18
  ├── t_order_19
  └── t_order_20

可以使用分開配置的方式,先配置包含前綴的數據節點,再配置不含前綴的數據節點,再利用行表達式笛卡爾積的特性,自動組合即可。 上面的示例,用行表達式可以簡化為:

db${0..1}.t_order_0${0..9}, db${0..1}.t_order_${10..20}

或者

db->${0..1}.t_order_0$->{0..9}, db$->{0..1}.t_order_$->{10..20}

■ 配置分片算法

對於只有一個分片鍵的使用=IN進行分片的SQL,可以使用行表達式代替編碼方式配置。 

行表達式內部的表達式本質上是一段Groovy代碼,可以根據分片鍵進行計算的方式,返回相應的真實數據源或真實表名稱。

例如:分為10個庫,尾數為0的路由到后綴為0的數據源, 尾數為1的路由到后綴為1的數據源,以此類推。用於表示分片算法的行表達式為:

ds${id % 10}

或者

ds$->{id % 10}
分布式主鍵

在傳統企業軟件開發中,主鍵自動生成技術是基本需求,各個數據庫對於該自增主鍵的需求提供了相應的支持,如MySQL的自增鍵。對於MySQL而言,分庫分表之后,不同庫、不同表生成全局唯一的主鍵是非常麻煩的事情。因為同一個邏輯表內的不同物理表之間的自增主鍵是無法互相感知的,這樣會生成重復的主鍵。

目前有許多第三方解決方案可以完美解決這個問題,比如UUID等依靠特定算法自生成不重復鍵,或者通過引入主鍵生成服務(Redis或者ZooKeeper)等。

Sharding-JDBC提供了抽象接口ShardingKeyGenerator,各個實現類通過實現generateKey()方法即可對外提供生成主鍵的功能。

目前內置了UUID和SNOWFLAKE(雪花算法)兩種主鍵生成策略。在分片規則配置模塊可配置每個表的主鍵生成策略,默認使用雪花算法(snowflake)生成64bit的長整型數據。

UUID:UUIDShardingKeyGenerator

SNOWFLAKE:SnowflakeShardingKeyGenerator

讀寫分離

主庫:添加、更新以及刪除數據操作所使用的數據庫,目前僅支持單主庫。

從庫:查詢數據操作所使用的數據庫,可支持多從庫。

主從同步:將主庫的數據異步的同步到從庫的操作。由於主從同步的異步性,從庫與主庫的數據會短時間內不一致。

負載均衡策略:通過負載均衡策略將查詢請求疏導至不同從庫。 

分布式事務

① 兩階段事務-XA:采用的是X/OPEN組織所定義的DTP模型,通過抽象出來的AP, TM, RM的概念可以保證事務的強一致性。

② SAGA柔性事務:一個Saga事務是一個有多個短時事務組成的長時的事務。 在分布式事務場景下,我們把一個Saga分布式事務看做是一個由多個本地事務組成的事務,每個本地事務都有一個與之對應的補償事務。在Saga事務的執行過程中,如果某一步執行出現異常,Saga事務會被終止,同時會調用對應的補償事務完成相關的恢復操作,這樣保證Saga相關的本地事務要么都是執行成功,要么通過補償恢復成為事務執行之前的狀態。

③ SEATA柔性事務:Seata是阿里集團和螞蟻金服聯合打造的分布式事務框架,截止到0.5.x版本包含了AT事務和TCC事務。其中AT事務的目標是在微服務架構下,提供增量的事務ACID語意,讓用戶像使用本地事務一樣,使用分布式事務,核心理念同ShardingSphere一脈相承。

彈性伸縮

① 彈性伸縮作業:指一次將數據由舊分片規則伸縮至新分片規則的完整流程。

② 數據節點:同數據分片中的數據節點

③ 存量數據:在彈性伸縮作業開始前,數據分片中已有的數據。

④ 增量數據:在彈性伸縮作業執行過程中,業務系統所產生的新數據。

官網:http://shardingsphere.apache.org/index_zh.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM