本篇為InfoQ中文站供稿

原文鏈接:infoq.cn/article/NHSAAm*MfpLiTiTTEu5?from=timeline&isappinstalled=0

ShardingSphere 是什麼?

ShardingSphere 是一套開源的分散式資料庫中間件解決方案組成的生態圈,它由 Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar(規劃中)這 3 款相互獨立的產品組成。他們均提供標準化的數據分片、分散式事務和資料庫治理功能,可適用於如 Java 同構、異構語言、容器、雲原生等各種多樣化的應用場景。ShardingShpere 在剛剛過去的雙十一之前通過了 Apache 基金會的投票,正式進入孵化器,成為 Apache 的首個分散式資料庫中間件。

ShardingSphere 可以採用混合使用 Sharding-JDBC 和 Sharding-Proxy 的部署方式滿足在線 + 管理的能力,也可以獨立使用 Sharding-JDBC 或 Sharding-Proxy。ShardingSphere 希望可以通過多元化的接入端架構去滿足不同需求。

Vitess 是什麼?

Vitess源起於 Youtube,現已屬於 PlanetScale 的開源產品。它致力於部署、擴展和管理大型 MySQL 實例集羣的資料庫解決方案。它結合了許多重要的 MySQL 功能和 NoSQL 資料庫的可擴展性,提供數據分片、分散式事務以及管理大量 MySQL 實例等功能。

Vitess 由負責元數據存儲的 Topology、負責應用接入和 SQL 路由的 vtgate、負責重寫和執行 SQL 的 vttablet 以及兩類管理工具 vtctl(用於命令行) 和 vtctld(用於圖形界面) 等服務組件共同構成。用戶可以通過支持 MySQL 協議的客戶端,或使用 Vitess 的客戶端 API 使用 Vitess。

應用功能對比

面對這兩個同樣優秀的產品,用戶該在何種場景下選用哪款產品,想必有所糾結。本文接下來將使用 Vitess v2.2 和 ShardingSphere 3.0.0,從應用功能和管理功能的角度,以官方文檔為基礎,進行測試對比,儘可能展示出兩者在已有功能和實現思路側重點上的不同。

接入方式

Vitess 通過組件 vtgate 作為中心化的接入代理,用戶可以通過 Vitess 的 gRPC 連接器或各類 MySQL 原生驅動進行連接。Vitess 的 gRPC 連接器目前僅支持 Java 和 Go 兩種語言,若使用原生驅動則沒有語言限制,目前 Vitess 支持 MySQL 和 MariaDB 兩種資料庫。

ShardingSphere 提供 Proxy 和 JDBC 兩種接入方式,其中 Sharding-Proxy 和 vtgate 類似,提供了中心化的接入代理,用戶可以通過 MySQL 原生驅動進行連接,理論上支持所有開發語言,目前同樣支持 MySQL 和 MariaDB 資料庫;Sharding-JDBC 可理解為增強版的 JDBC 驅動,提供無中心化的輕量級運行方式,讓客戶端直連資料庫,無網路二次轉發的消耗。由於是 JDBC 的增強,因此沒有資料庫類型的限制,可以支持 MySQL、Oracle、SQLServer 和 PostgreSQL 等。

通過表格,可以更直觀的比較雙方的接入方式區別:

分片模式

Vitess 在分片上採用了每個資料庫實例均創建一個分庫,並且不進行分表的方式,即多實例單庫單表。由於 Vitess 的分片模式相對固定,因此在配置分片時通過 JSON 指定分片表、分片欄位和分片演算法,分片之後的庫名由 Vitess 自動管理,表名不變。

ShardingSphere 支持單獨分庫、單獨分表和同時分庫分表的分片方式,並且提供四種不同的分片策略以及能夠讓用戶自行實現分片演算法,使得用戶能夠更加自由地控制數據分片。

單純描述有些抽象,接下來分別創建一個分片的例子進行測試.

首先模仿 Vitess 官方文檔的測試用例,創建了一個名為 test_keyspace 的鍵空間(keyspaces),為其設置了 2 個分片。同時指定了 t_order 和 t_order_item 兩張分表,分別使用 user_id 和 order_id 進行 Hash 分片。

在建表完畢後,通過 DataGrip 客戶端分別連接 vtgate 和實際 MySQL 實例進行查看。

vtgate 執行 show databases 和 show tables。

MySQL 實例中的拓撲結構如下圖。

從 MySQL 實例的拓撲看出,Vitess 在每一個分片資料庫實例中,都創建了一個 vt_${keyspace_name}的庫,並且將建表語句廣播到所有資料庫執行。

同樣模仿 ShardingSphere 的官方樣例,在 Sharding-Proxy 中配置 test_keyspace 分庫及 t_order,t_order_item 兩張分表。為了區別 ShardingSphere 和 Vitess 的分片能力,這裡選用同時分庫分表的方式進行分片,通過 user_id 取餘進行分庫、order_id 取餘進行分表。

在進行配置的時候,可以利用 InlineShardingStrategy 直接使用 Groovy 表達式簡化配置,如本例中可簡化配置為:

test_keyspace_${user_id % 2}
t_order_${order_id % 2}
t_order_item_${order_id % 2}

在建表完畢後,通過 DataGrip 客戶端分別連接 Sharding-Proxy 和實際 MySQL 實例進行查看。

Sharding-Proxy 執行 show databases 和 show tables:

MySQL 實例中的拓撲結構:

同樣通過表格,直觀的展示兩者分片上的區別:

由此可見,ShardingSphere 和 Vitess 在分片模式上有著很大的區別,ShardingSphere 具有更豐富更自由的分片方式,能夠應付更多的應用場景。

SQL 支持

由於 SQL 語法靈活複雜,分散式資料庫和單機資料庫的查詢場景又不完全相同,難免有和單機資料庫不兼容的 SQL 出現。針對該問題,Vitess 和 ShardingSphere 都在官方文檔中進行了說明。

在 ShardingSphere 中,對於已支持和未支持的 SQL 種類作出了明確的標註,對於常用的分頁、排序、分組、聚合都進行了支持,並支持部分關聯查詢,具體內容可以通過官方文檔 使用規範 > SQL 中進行查閱。

而 Vitess 暫時沒有明確的文檔標明已支持和未支持的 SQL 種類,只在 FAQ 中的test-case標註了當前已經出現的未支持的 SQL 的情況。

為了更直觀地展示兩者 SQL 支持情況,這裡選取了一部分常用的 SQL 類型,根據文檔說明並結合

實際測試結果,列出參考列表:

從測試結果看來,對於常用的 SQL 類型,無論是 Vitess 還是 ShardingSphere 都可以比較好的支持。但是 Vitess 無法支持排序,因此也無法支持分頁對於部分應用來說可能是比較嚴重的問題。相比 Vitess,ShardingSphere 除 DISTINCT 關鍵字以外,其他類型的 SQL 支持程度均持平或略有優勢。通過 SharingSphere 的官方 issue 列表中可知,DISTINCT 的支持目前正在進行中,相信不久之後就會支持。

分片路由

分散式資料庫將數據進行分片的主要目的之一就是希望執行的操作能分散在一個或其中數個分片中,而不是在所有分片中,因此如何觸發分片路由,縮小分片範圍也是需要重點關注的功能。

Vitess 在 VSchema Guide 文檔說明 Select、Update、Delete 通過 Where 條件中的等值條件進行路由,等值條件僅包括了 = 及 IN;Insert 則根據插入欄位是否包含分片鍵來進行分片路由。

ShardingSphere 除了支持 Where 條件中的 = 及 IN 進行分片路由之外,還可以通過 BETWEEN 進行分片路由 (需要使用 RangeShardingAlgorithm 或 ComplexShardingStrategy),Insert 時同樣根據插入欄位來進行分片路由。

為了驗證分片路由的執行條件,首先要開啟 MySQL 資料庫的 GENERAL_LOG 參數。

SET GLOBAL GENERAL_LOG = 1;
SHOW VARIABLES LIKE %general_log%;

開啟該參數之後,MySQL 資料庫將會記錄所有執行過的 SQL,通過查看分片庫中實際執行的 SQL,來判斷是分片路由還是廣播。

之後在 Vitess 中執行數個測試 SQL:

SELECT * FROM t_order WHERE user_id = 7;
SELECT * FROM t_order WHERE user_id in (7, 9);
SELECT * FROM t_order WHERE user_id=7 or user_id=11;
SELECT * FROM t_order WHERE user_id BETWEEN 7 AND 11;

從 Vitess 分片 1 的 general_log,找到 Mysql 實際執行了如下 SQL:

select * from t_order where user_id in (9)
select * from t_order where (user_id = 7 or user_id = 11)
select * from t_order where user_id between 7 and 11

從 Vitess 分片 2 的 general_log,找到 Mysql 實際執行了如下 SQL:

select * from t_order where user_id = 7
select * from t_order where user_id in (7)
select * from t_order where (user_id = 7 or user_id = 11)
select * from t_order where user_id between 7 and 11

由於 user_id=7 屬於分片 2,所以 SQL1 不會分發到分片 1 中,而 SQL2 也被實際改寫,只將 user_id=9 分發到了分片 1,說明對於 = 以及 IN,Vitess 的確能夠正確進行路由分片; 因為 user_id 7 和 11 均屬於分片 2,所以對於等值 OR 查詢 Vitess 並沒有解析到條件內部,而是直接執行了廣播。

然後在 ShardingSphere 中執行測試 SQL:

SELECT * FROM t_order WHERE order_id = 1007 AND user_id=7;
SELECT * FROM t_order WHERE order_id = 1007;
SELECT * FROM t_order WHERE order_id in (1007, 1008);
SELECT * FROM t_order WHERE order_id in (1007, 1009);
SELECT * FROM t_order WHERE order_id=1007 or order_id=1011;

從 ShardingSphere 分片 1 的 general_log,發現 Mysql 實際執行了如下 SQL:

SELECT * FROM t_order_1 WHERE order_id = 1007
SELECT * FROM t_order_0 WHERE order_id in (1007, 1008)
SELECT * FROM t_order_1 WHERE order_id in (1007, 1008)
SELECT * FROM t_order_1 WHERE order_id in (1007, 1009)
SELECT * FROM t_order_1 WHERE order_id=1007 or order_id=1011
SELECT * FROM t_order_1 WHERE order_id=1007 or order_id=1010
SELECT * FROM t_order_0 WHERE order_id=1007 or order_id=1010

從 ShardingSphere 分片 2 的 general_log,發現 Mysql 實際執行了如下 SQL:

SELECT * FROM t_order_1 WHERE order_id = 1007 AND user_id=7
SELECT * FROM t_order_1 WHERE order_id = 1007
SELECT * FROM t_order_0 WHERE order_id in (1007, 1008)
SELECT * FROM t_order_1 WHERE order_id in (1007, 1008)
SELECT * FROM t_order_1 WHERE order_id in (1007, 1009)
SELECT * FROM t_order_1 WHERE order_id=1007 or order_id=1011
SELECT * FROM t_order_1 WHERE order_id=1007 or order_id=1010
SELECT * FROM t_order_0 WHERE order_id=1007 or order_id=1010

ShardingSphere 的等值查詢和 Vitess 一樣,能準確的確定對應分片表進行查詢,當 SQL 中存在庫級分片鍵 user_id 時(SQL1),ShardingSphere 只將 SQL 定位在了分片 2 的 t_order_1 分表;而查詢不帶有庫級分片時(SQL2),ShardingSphere 進行了庫級的廣播,但仍然能夠將 SQL 定位在 t_order_1 表;而對於 IN 方式,雖然能夠準確的定位到分片表,但是不會對 IN 的條件進行重寫(分片 1 的 SQL2-4);對於 OR 的等值查詢,ShardingSphere 能夠定位到具體的分片,比 Vitess 優秀;最後由於測試用例使用的是 InlineShardingStrategy,因此無法對 BETWEEN AND 的 SQL 進行測試。

經過測試,Vitess 和 ShardingSphere 都可以對等值條件進行準確的分片路由;ShardingSphere 相比於 Vitess 多支持了 OR 等值的分片路由,並且在實現了特定演算法或特定策略時,還能夠支持 BETWEEN AND 的分片路由。

另外,對於強制分片路由,Vitess 在 FAQ 中回答需要用戶直接連接到對應分片的 vttablet 進行操作,而 ShardingSphere 支持 Hint 方式進行強制分片路由,依舊使得分片對應用透明。由此看來,ShardingSphere 在分片路由上的功能,也要略強於 Vitess。

結果歸併

當分片路由將 SQL 路由到多個分片,或無法使用分片路由而進行廣播時,如何將多個分片的結果合併為一個正確的結果,就涉及到結果歸併。

Vitess 在文檔中沒有對結果歸併詳細的說明,從在之前的 SQL 測試中能夠發現,Vitess 對於一般的結果僅是簡單的將各個分片的結果集按照分片順序連接起來;對於部分聚合的結果歸併,如 count 和 sum,Vitess 能夠正確的進行合併;但是對於一些複雜的歸併類型,比如 avg 或 order by 的結果歸併,就無法支持;在測試過程中,還發現 Vitess 會對 Limit 的分頁 SQL 進行改寫,比如分頁 SQL

SELECT * FROM t_order LIMIT 10,10;

就會改寫成

SELECT * FROM t_order LIMIT 20;

然後將 2 個分片的結果集合併之後再獲取 10~20 的結果。

ShardingSphere 在文檔 歸併引擎 一節中對結果歸併有非常詳細的描述,將歸併分類為遍歷、排序、分組、分頁和聚合 5 種類型。不僅和 Vitess 一樣能夠將分片的結果集普通地連接起來,而且還支持了 avg 和 order by 的結果歸併。同時對於 Limit 分頁 SQL,也進行了改寫。

正是由於 ShardingSphere 對結果歸併有著更好的支持,所以 ShardingSphere 在 SQL 支持上能夠比 Vitess 表現的更好。

分散式事務

事務是資料庫中一個重要且常用的功能,對於分散式資料庫而言同樣不可或缺。因此 Vitess 和 ShardingSphere 都提供了一些可選的分散式事務功能。

Vitess 提供了 3 個級別的分散式事務,單庫事務、多庫事務、兩階段提交事務,用戶可選擇其中一種作為 Vitess 的分散式事務實現:

  • 單庫事務指的是僅允許單個資料庫事務。嘗試超出單個資料庫的任何事務都將失敗。
  • 多庫事務允許事務跨越多個資料庫,但每個資料庫均為單獨提交,即弱 XA,可能會出現部分提交導致數據不一致,且無法回滾。
  • 兩階段提交類似於多庫事務,但能保持多資料庫間的原子性,即其中一個資料庫提交失敗時,其他資料庫的提交將會回滾以保持數據一致。

ShardingSphere 同樣提供了 3 種類型的分散式事務,本地事務、XA 事務及柔性事務(開發中,預計 3.1.0 發布):

  • 本地事務類似於 Vitess 的多庫事務,各個資料庫獨立提交,即弱 XA。
  • XA 事務即兩階段提交事務,默認採用 Atomikos 事務管理器。
  • 柔性事務採用 SAGA 模型進行事務控制,以保證數據的最終一致性。其中 ShardingSphere 在 3.x 之前的版本也使用過最大努力送達型事務,但由於無回滾能力,因此已經廢棄,轉而使用能力更加強大的 SAGA。

Vitess 和 ShardingSphere 當前版本的分散式事務功能相當,但是 Vitess 的官方文檔和 roadmap 計劃中,似乎沒有實現柔性事務的計劃,因此一旦 ShardingSphere 3.1.0 中支持柔性事務,在分散式事務功能上將能支持更多的應用場景。

讀寫分離

Vitess 的不提供默認的讀寫分離功能,但是提供在 SQL 中通過 @指定的方式進行從庫的查詢,例如在 SQL 中通過 ks@master 將查詢指向主庫,而使用 ks@replica 或 ks@rdonly 將查詢指向從庫或備庫。

ShardingSphere 的讀寫分離功能只需要在配置中指定主庫和從庫,ShardingSphere 能自動地將 DML 路由至主庫,DQL 路由至從庫;同時 ShardingSphere 允許多個從庫並配置負載均衡策略將請求疏導到不同的從庫;另外 ShardingSphere 還可以通過 Hint 進行強制主庫路由。

ShardingSphere 的讀寫分離功能,無論從對 SQL 的入侵程度,還是從功能的實現程度,都略強於 Vitess 的讀寫分離。

分散式主鍵

Vitess 的分散式主鍵,用戶可通過設定全局非分片的外部查詢表來實現。如 Vitess 在官方文檔中的用例,將 user_id(主分片鍵)列配上全局序列表 user_seq,組成自增分散式主鍵;

ShardingSphere 提供靈活的配置分散式主鍵生成策略方式。 在分片規則配置中可配置每個表的主鍵生成策略,默認使用雪花演算法(snowflake)生成 64bit 的長整型數據。ShardingSphere 的雪花演算法的時間紀元從 2016 年 11 月 1 日零點開始,可以使用到 2156 年,相信能滿足絕大部分系統的要求。

管理功能對比

配置管理

Vitess 將資料庫信息、分片信息等元數據信息,存儲在 zookeeper 或 Etcd 註冊中心中,並配以 GUI 系統 vtctld 和命令行系統 vtctl 對 Vitess 的功能進行管理和控制。同時 Vitess 提供 workflows,將一些常用操作流程,變成可控制的工作流,使運維人員能夠自動快速地執行諸如主從切換、數據遷移、平衡分片等操作。

ShradingSphere 同樣可以將分片信息,配置信息等元數據,存儲在 zookeeper 或 Etcd 註冊中心中,但暫時沒有提供 GUI 或命令控制檯功能,對配置和 ShardingSphere 程序進行控制和管理,用戶需要在 zookeeper 或 Etcd 的 API 或自帶的控制檯中,修改其中的信息。

監控

Vitess 在 vtagate 和 vttablet 中提供了簡易的 GUI,用戶通過 GUI 頁面不僅能夠查看 Vitess 本身部分組件的健康狀況,QPS 等信息,還能獲取一部分底層資料庫的監控信息。

ShardingSphere 自身並不提供監控,但是可以通過一些 APM 系統進行應用監控。目前 ShardingSphere 提供兩種方式對接應用性能監控系統:

  • 使用 OpenTracing API 發送性能追蹤數據。面向 OpenTracing 協議的 APM 產品都可以和 ShardingSphere 自動對接,比如 SkyWalking,Zipkin 和 Jaeger。
  • 使用 SkyWalking 的自動探針。

資料庫管理

Vitess 提供了備份資料庫數據的功能,能將資料庫的數據、配置,連同 vttablet 一同備份到 NFS、雲存儲或本地文件系統中,在備份的過程中,還能進行自動壓縮以提高備份效率,並且 Vitess 可以從備份中快速創建出 vttable 並加入集羣中。Vitess 還提供了主從切換和重設主從關係的功能,該功能不僅可以由 DBA 有計劃的使用 workflow 執行,還可以在資料庫節點失效或有問題時自動執行。Vitess 也提供了重分片 (Resharding) 的數據遷移方式,使得用戶能夠在修改分片規則後平滑地將舊分片的數據遷移到新分片上,Vitess 會在新分片上複製,驗證和保持數據最新,而現有分片繼續提供實時讀寫流量。當 Vitess 準備切換時,只需幾秒鐘的只讀停機時間即可進行遷移。在切換執行期間,可以讀取現有數據,但無法寫入新數據。

ShardingSphere 目前僅提供了熔斷實例和禁用從庫的功能,在 roadmap 中還規劃實現多數據副本和彈性伸縮的功能。

總結

Vitess 和 ShardingSphere 作為當下優秀的資料庫中間件和分散式資料庫解決方案,在數據分片、分散式事務和資料庫治理等功能上均有所建樹,但是雙方在功能側重上有部分差異。

關於數據分片、分散式事務等 OTLP 應用功能方面,ShardingSphere 比 Vitess 提供了更豐富和自由的分片方式、提供了更多的 SQL 支持和更容易觸發的分片路由、提供了侵入性更低的讀寫分離並即將提供更多種的分散式事務類型。因此 ShardingSphere 在應用功能方面要強於 Vitess。

而關於管理方面的功能,Vitess 相比 ShardingSphere 增加了 GUI 的控制方式、提供了資料庫的備份和主從切換功能、並提供部分自身和資料庫的監控。因此 Vitess 在管理方面的功能要優於 ShardingSphere。

ShardingSphere 還在快速發展中,未來也會對資料庫治理及彈性數據遷移做大量工作。如果目前想找一個完美的在線功能 + 管理功能的解決方案,可以混合部署,在線查詢更新用 ShardingSphere,然後使用 Vitess 進行數據的管理和監控,並可以自行開發插件,同步 Vitess 和 ShardingSphere 的註冊中心配置,使其動態生效。

最後,通過一個簡單的表格,總結一下 Vitess 和 ShardingSphere 的對比結論:


ShardingSphere近期相關計劃安排是什麼呢?歡迎大家來github圍觀、留言!

github.com/sharding-sph

ShardingSphere自2016開源以來,不斷精進、不斷發展,被越來越多的企業和個人認可:在Github上收穫5000+的star,2000+forks,60+公司企業的成功案例。此外,越來越多的企業和個人也加入到ShardingSphere的開源項目中,為它的成長和發展貢獻了巨大力量。

我們從未停息過腳步,聆聽社區夥伴的需求和建議,不斷開發新的、強大的功能,不斷使其健壯可靠!

開源不易, 我們卻願向著最終的目標,步履不停!

那麼,正在閱讀的你,是否可以助我們一臂之力呢?分享、轉發、使用、交流,以及加入我們,都是對我們最大的鼓勵!

關注我們

weixin.qq.com/r/1SmwqBX (二維碼自動識別)

掃碼進羣

u.wechat.com/MPcTObaiCh (二維碼自動識別)


推薦閱讀:
查看原文 >>
相關文章