ShardingSphere
在中小企業須要分庫分表的時候用的會比較多,由於它維護成本低,不須要額外增派人手;並且目前社區也還一直在開發和維護,還算是比較活躍。java
可是中大型公司通常會選擇選用 Mycat 這類 proxy 層方案,由於可能大公司系統和項目很是多,團隊很大,人員充足,那麼最好是專門弄我的來研究和維護 Mycat,mysql
而後大量項目直接透明使用便可。git
ShardingSphere是一套開源的分佈式數據庫中間件解決方案組成的生態圈,它由Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar這3款相互獨立的產品組成。github
他們均提供標準化的數據分片
、分佈式事務
和 數據庫治理功能
,可適用於如Java同構、異構語言、雲原生等各類多樣化的應用場景。sql
如圖數據庫
數據分片
apache
- 分庫 & 分表 - 讀寫分離 - 分片策略定製化 - 無中心化分佈式主鍵
分佈式事務
數組
- 標準化事務接口 - XA強一致事務 - 柔性事務
數據庫治理
分佈式
- 配置動態化 - 編排 & 治理 - 數據脫敏 - 可視化鏈路追蹤 - 彈性伸縮(規劃中)
概念
將從各個數據節點獲取的多數據結果集,組合成爲一個結果集並正確的返回至請求客戶端,稱爲結果歸併。ide
咱們在實現分庫分表以後,遍歷
、排序
、分組
、分頁
和 聚合
操做變成不在一張表上進行SQL,而是多張表執行的結果進行歸併。
因此咱們來看下ShardingSphere實現這些操做的原理。
它是最爲簡單的歸併方式。 只需將多個數據結果集合併爲一個單向鏈表
便可。在遍歷完成鏈表中當前數據結果集以後,將鏈表元素後移一位,繼續遍歷下一個數據結果集便可。
因爲在SQL中存在ORDER BY
語句,每一個數據結果集自身是有序的,因此咱們要作的就是對多個有序的數組進行排序
ShardingSphere在對排序的查詢進行歸併時,將每一個結果集的當前數據值進行比較(經過實現Java的Comparable接口完成),並將其放入優先級隊列
。
每次獲取下一條數據時,只需將隊列頂端結果集的遊標下移,並根據新遊標從新進入優先級排序隊列找到本身的位置便可。
舉例
下圖是一個經過分數進行排序的示例圖。 圖中展現了3張表返回的數據結果集,每一個數據結果集已經根據分數排序完畢,可是3個數據結果集之間是無序的。
將3個數據結果集的當前遊標指向的數據值進行排序,並放入優先級隊列
,t_score_0的第一個數據值最大,t_score_2的第一個數據值次之,t_score_1的第一個數據值最小,
所以優先級隊列根據t_score_0,t_score_2和t_score_1的方式排序隊列。
如圖
下圖則展示了進行next調用的時候,排序歸併是如何進行的。 經過圖中咱們能夠看到,當進行第一次next調用時,排在隊列首位的t_score_0將會被彈出隊列,而且將當前
遊標指向的數據值(也就是100)返回至查詢客戶端,而且將遊標下移一位(90)以後,從新放入優先級隊列。根據當前數值,t_score_0排列在隊列的最後一位。 以前隊列中
排名第二的t_score_2的數據結果集則自動排在了隊列首位。
在進行第二次next時,只須要將目前排列在隊列首位的t_score_2彈出隊列,而且將其數據結果集遊標指向的值返回至客戶端,並下移遊標,繼續加入隊列排隊,以此類推。
當一個結果集中已經沒有數據了,則無需再次加入隊列。
能夠看到,ShardingSphere的排序歸併,是在維護數據結果集的縱軸和橫軸這兩個維度的有序性。
縱軸
是指每一個數據結果集自己,它是自然有序的,它經過包含ORDER BY
的SQL所獲取。
橫軸
是指每一個數據結果集當前遊標所指向的值,它須要經過優先級隊列
來維護其正確順序。 每一次數據結果集當前遊標的下移都須要將該數據結果集從新放入優先級隊列排序,
而只有排列在隊列首位的數據結果集纔可能發生遊標下移的操做。
分組歸併的狀況最爲複雜,它分爲流式分組歸併
和內存分組歸併
。 流式分組歸併要求SQL的排序項與分組項的字段以及排序類型(ASC或DESC)必須保持一致,不然只能
經過內存歸併才能保證其數據的正確性。
舉例
假設根據科目分片,表結構中包含考生的姓名(爲了簡單起見,不考慮重名的狀況)和分數。經過SQL獲取每位考生的總分,可經過以下SQL:
SELECT name, SUM(score) FROM t_score GROUP BY name ORDER BY name;
在分組項與排序項徹底一致的狀況下,取得的數據是連續的,分組所需的數據全數存在於各個數據結果集的當前遊標所指向的數據值,所以能夠採用流式歸併。以下圖所示。
進行歸併時,邏輯與排序歸併相似。 下圖展示了進行next調用的時候,流式分組歸併是如何進行的。
經過圖中咱們能夠看到,當進行第一次next調用時,排在隊列首位的t_score_java將會被彈出隊列,而且將分組值同爲「Jetty」的其餘結果集中的數據一同彈出隊列。 在獲取了
全部的姓名爲「Jetty」的同窗的分數以後,進行累加操做,那麼,在第一次next調用結束後,取出的結果集是「Jetty」的分數總和。 與此同時,全部的數據結果集中的遊標都將
下移至數據值「Jetty」的下一個不一樣的數據值,而且根據數據結果集當前遊標指向的值進行重排序。 所以,包含名字順着第二位的「John」的相關數據結果集則排在的隊列的前列。
流式分組歸併與排序歸併的區別僅僅在於兩點:
- 它會一次性的將多個數據結果集中的分組項相同的數據全數取出。 - 它須要根據聚合函數的類型進行聚合計算。
不管是流式分組歸併仍是內存分組歸併,對聚合函數的處理都是一致的。 除了分組的SQL以外,不進行分組的SQL也可使用聚合函數。 所以,聚合歸併是在以前介紹的歸併類
的之上追加的歸併能力,即裝飾者模式
。聚合函數能夠歸類爲比較、累加和求平均值這3種類型。
比較類型的聚合函數是指MAX
和MIN
。它們須要對每個同組的結果集數據進行比較,而且直接返回其最大或最小值便可。
累加類型的聚合函數是指SUM
和COUNT
。它們須要將每個同組的結果集數據進行累加。
求平均值的聚合函數只有AVG
。它必須經過SQL改寫的SUM
和COUNT
進行計算,相關內容已在SQL改寫的內容中涵蓋,再也不贅述。
上文所述的全部歸併類型均可能進行分頁。 分頁也是追加在其餘歸併類型之上的裝飾器,ShardingSphere經過裝飾者模式
來增長對數據結果集進行分頁的能力。 分頁歸併負責
將無需獲取的數據過濾掉。
ShardingSphere的分頁功能比較容易讓使用者誤解,用戶一般認爲分頁歸併會佔用大量內存。 在分佈式的場景中,將LIMIT 10000000, 10
改寫爲LIMIT 0, 10000010
,
才能保證其數據的正確性。 用戶很是容易產生ShardingSphere會將大量無心義的數據加載至內存中,形成內存溢出風險的錯覺。 其實,經過流式歸併的原理可知,會將
數據所有加載到內存中的只有內存分組歸併這一種狀況。 而一般來講,進行OLAP的分組SQL,不會產生大量的結果數據,它更多的用於大量的計算,以及少許結果產出的場景。
除了內存分組歸併這種狀況以外,其餘狀況都經過流式歸併獲取數據結果集,所以ShardingSphere會經過結果集的next方法將無需取出的數據所有跳過,並不會將其存入內存。
但同時須要注意的是,因爲排序的須要,大量的數據仍然須要傳輸到ShardingSphere的內存空間。 所以,採用LIMIT這種方式分頁,並不是最佳實踐
。 因爲LIMIT並不能經過索引
查詢數據,所以若是能夠保證ID的連續性,經過ID進行分頁是比較好的解決方案
,例如:
SELECT * FROM t_order WHERE id > 100000 AND id <= 100010 ORDER BY id;
或經過記錄上次查詢結果的最後一條記錄的ID進行下一頁的查詢,例如:
SELECT * FROM t_order WHERE id > 10000000 LIMIT 10;
六、總結
用最後一張圖來總結歸併引擎的總體結構劃分
補充
有關ShardingSphere其它的知識概述這裏就不在講了,這篇文章也是徹底根據官方文檔加上我的理解寫的,因此想一想要更加詳細的瞭解能夠去看官網。
我相信,不管從此的道路多麼坎坷,只要抓住今天,早晚會在奮鬥中嚐到人生的甘甜。抓住人生中的一分一秒,賽過虛度中的一月一年!(17)