尋夢新聞LINE@每日推播熱門推薦文章,趣聞不漏接❤️
面對互聯網大數據如火如荼發展、雲服務需求的急劇增加,對企業極其重要的數據要如何面對這些新的變革?
作為Apache基金會的分布式數據庫中間件項目-ShardingSphere將針對數據水平&垂直拆分、分布式事務、數據服務治理、數據安全等需求提供一套適用於互聯網應用架構、雲服務架構的多解決方案生態圈。
本次分享將介紹Apache ShardingSphere核心功能、在京東的具體落地實戰、產品生態圈發展等內容。
內容提綱:
- Apache ShardingSphere生態圈簡介
- Apache ShardingSphere核心功能&接入端
- Apache ShardingSphere京東落地實戰
- Apache ShardingSphere迭代&規劃
一、Apache ShardingSphere
生態圈簡介
Apache ShardingSphere是一款開源的分布式數據庫中間件組成的生態圈。自從2016年開源以來,不斷升級開發新功能、重構穩定微內核,並於2018年11月進入Apache基金會孵化器。
它由京東集團主導,並由多家公司以及整個ShardingSphere社區共同經營參與貢獻。其主要的功能模塊為:數據分片(分庫分表)、分布式事務、數據庫治理三大塊內容。
目前以在gitHub上收獲7000+關注度、70+公司落地的成功案例。
參考鏈接:
https://github.com/apache/incubator-shardingsphere
對新朋友而言,簡介部分主要為大家呈現Apache ShardingSphere生態圈概覽;對老朋友來說,它的迭代和發展是日新月異的,可以看到它最近的發展狀態和前進方向。目前,整個Apache ShardingSphere生態圈架構如下圖所示:
整體核心功能將組成一個閉環,它不僅為大家提供最為基礎和核心的數據分片和分布式事務功能,同時針對以ShardingSphere為中心的整個分布式數據庫系統,提供數據庫治理的功能,例如配置信息動態統一管理、調用鏈與拓撲圖、高可用管理、數據脫敏安全、權限控制等強大的管理功能。
此外,我們針對不同的數據庫,例如MySQL、Oracle、PostgreSQL、SQL Server提供多模式連接的支持,真正屏蔽底層數據庫選型的影響,做到無論使用何種數據庫都可在用戶無感知情況下進行數據分片、分布式事務、數據庫治理的功能操作。
管控界面模塊旨在為用戶提供清晰可見的信息查看、配置更新管理、統計報表等功能。
在接入端部分,為了滿足不同用戶針對不同場景的需求,ShardingSphere提供了多款接入端,包括Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(規劃中):
- Sharding-JDBC是一款輕量級的Java框架,在JDBC層提供上述核心功能,使用方式與正常的JDBC方式如出一轍,面向Java開發的用戶。
- Sharding-Proxy是一款做到了MySQL二進制協議的服務器端版本,大家可以把它當成升級版的MySQL數據庫使用。獨立部署後,即可按照正常MySQL操作方式來使用上述所有的核心功能。
- Sharding-Sidecar從Service Mesh的理念中應用而生,面向於雲原生架構。
Apache ShardingSphere是一個生態,它的開源基因注定它的發展開放自由、社區參與貢獻。所以在設計它的架構時,會更加注意營造微內核與開發生態。
我們提供各個方面的開放接口,以方便所有對此感興趣的朋友能參與其中,貢獻代碼,成為Apache基金會項目的提交者。
二、Apache ShardingSphere
核心功能&接入端
1、核心功能介紹
數據分片、分布式事務、數據庫治理功能已成熟,可提供給用戶用於生產;多模式連接和管控界面還在進行中,尚需時日才可與大家見面。
成熟的核心功能具體而言主要由以下內容組成:
可以看到Apache ShardingSphere整個生態圈的功能點多且強大。每個功能點展開來講,即可組成一個系列課程。限於篇幅所限,本次分享主要為大家介紹數據分片的內容,並結合京東落地實戰,講解數據分片在落地過程中遇到的問題以及對應的解決方法。
- 數據分片在ShardingSphere中主要被劃分為讀寫分離、數據拆分。讀寫分離主要是指:為數據庫搭建災備副本,並在訪問時將這些生產及災備庫分為主庫、從庫兩種角色。其中主庫處理所有的修改、變更操作以及少部分讀操作;從庫分擔主庫大部分的讀請求。
- 數據拆分在這里主要指數據水平分片,即真正意義上將一個數據庫拆分成多個分庫,分別存儲及訪問。具體架構如下圖所示:
在此基礎上,很多業務系統出於性能和安全考慮,會選擇這兩種方式的混合部署架構,即同時使用讀寫分離和水平分片策略,如下圖所示:
在這種情況下,底層數據的架構網路就會顯得異常複雜和繁瑣。因為在整個分布式的數據庫系統當中會存在:分庫1、分庫2……,還有對應的從庫1、從庫2……
對業務開發的同學來講,自身的精力和注意力不僅要放到跟KPI掛鉤的業務代碼開發上,還需要考慮如何做到和維護這樣一套分布式數據庫系統。
如何避免重復造輪子?如何將工作重心只落在自己的業務開發上?
Apache ShardingSphere便為大家充當這樣一個做到並維護分布式數據庫系統的管理員。作為一款分布式數據庫中間件,它將為大家解決這些場景下的數據庫管理維護的工作。
通過引入這層中間件,讓業務開發像使用一個數據庫一樣去使用整個複雜繁瑣的分布式數據庫系統,而完全無需關心底層所有的分庫以及讀寫庫的使用和維護,如下圖所示:
那麼,Apache ShardingSphere是如何做到的呢?
首先,它為用戶提供了各種內置的分片策略方式,並開放了自定義分片策略接口,用於幫助用戶完成特殊場景下的分片需求。
數據分片的重中之重是:如何去拆分數據庫表?
這將關係到今後整個數據庫系統的性能、與業務系統的匹配默契程度。ShardingSphere提供了如哈希取模、範圍劃分、標籤分類、時間範圍以及復合分片等多種切分策略。
舉例來說,業務方有可能會按照訂單號後幾十位做哈希取模來切分庫表;也有可能將日志文件信息按照日、月、年的維度進行切分數據,並存儲到數據庫;還可能按照業務類型進行分庫分表等。
針對各式各樣的業務場景,ShardingSphere提供了以下多種分片策略。雖然這些分配策略基本可以滿足80%以上業務方需求,但還是會存在一些變態的業務場景。
為此,我們開放了數據分片策略的接口,業務方可以選擇按照自己的變態需求做到這些數據分片接口,ShardingSphere就會通過SPI的方式將其加載使用。
在確定好數據分片策略後,ShardingSphere將使用該分片策略進行以下操作來完成對某條SQL的DDL&DML&DAL&DQL&TCL等操作。
但是這個過程對用戶來說是透明的,即在用戶無感知的情況下,ShardingSphere將用戶輸入的SQL進行解析,然後依據用戶指定的分片策略對這條不含分片信息的SQL進行改寫,將其改寫成為真正在某個或多個數據表上執行的某條或多條真實的SQL。
此外,還需要找到每一條真實的SQL究竟需要在哪個庫的哪張分表上執行,最終把改寫後的真實SQL下發到對應的分表上進行多線程的執行。而用戶會將拿到最終匯總後的數據結果集。
2、接入端介紹
Apache ShardingSphere作為一個生態圈,為用戶提供了多款接入端以滿足用戶不同應用場景的需求。分別為:
- Sharding-JDBC,一款輕量級的JAVA框架,面向JAVA開發更為友好;
- Sharding-Proxy,獨立部署的做到了MySQL二進制協議的服務器端版本,支持異構語言;
- Sharding-Sidecar,配合雲原生環境使用,面向Service Mesh使用。
目前,Sharding-JDBC和Sharding-Proxy可用於生產,Sharding-Sidecar還在開發中。
1)Sharding-JDBC
Sharding-JDBC被定位為輕量級Java框架,在Java的JDBC層提供的額外服務。它使用客戶端直連數據庫,以jar包形式提供服務,無需額外部署和依賴,可理解為增強版的JDBC驅動,完全兼容JDBC和各種ORM框架。
- 適用於任何基於Java的ORM框架,如:JPA、Hibernate、Mybatis、Spring JDBC Template或直接使用JDBC。
- 基於任何第三方的數據庫連接池,如:DBCP、C3P0、BoneCP、Druid、HikariCP等。
- 支持任意做到JDBC規範的數據庫。目前支持MySQL、Oracle、SQLServer和PostgreSQL。
2)Sharding-Proxy
Sharding-Proxy被定位為透明化的數據庫代理端,提供封裝了數據庫二進制協議的服務端版本,用於完成對異構語言的支持。
目前先提供MySQL版本,它可以使用任何兼容MySQL協議的訪問客戶端(如:MySQL Command Client、MySQL Workbench等)操作數據,對DBA更加友好:
- 向應用程序完全透明,可直接當做MySQL使用。
- 適用於任何兼容MySQL協議的客戶端。
3)Sharding-Sidecar
Sharding-Sidecar被定位為Kubernetes或Mesos的雲原生數據庫代理,以DaemonSet的形式代理所有對數據庫的訪問。
通過無中心、零侵入的方案提供與數據庫交互的的嚙合層,即Database Mesh,又可稱數據網格。
Database Mesh的關注重點在於如何將分布式的數據訪問應用與數據庫有機串聯起來,它更加關注的是交互,是將雜亂無章的應用與數據庫之間的交互有效的梳理。
使用Database Mesh,訪問數據庫的應用和數據庫終將形成一個巨大的網格體系,應用和數據庫只需在網格體系中對號入座即可,它們都是被嚙合層所治理的對象。
三、Apache ShardingSphere
京東落地實戰
當前ShardingSphere已在京東落地很多大小業務,這里只是列舉較為大型的系統,這些業務系統有的是重要程度較高,有的是業務較為新穎。如下圖所示:
從這個案例中可以看到:
- 大家熟知的白條業務以及運維部門的監控系統-秒級監控主要使用ShardingSphere的數據分片功能及正在開發的彈性伸縮功能,使用到的主要有Sharding-JDBC和Sharding-Proxy;
- 四要素加密主要是來自數據安全和審計的要求,主要使用到了數據脫敏的功能模塊,所採用的產品是Sharding-JDBC;
- 而城市計算這一新穎的業務,主要使用到了ShardingSphere的數據庫治理模塊,包括高可用管理和權限控制等。
每一個落地案例都可以成為獨立的分享來為大家講解,本次分享主要為大家介紹落地白條業務的實戰情況。
在這個落地過程中,我特意總結了落地實戰遇到的問題,已經對應的解決方案。我相信在各位的生產實踐中多少都會遇到類似的問題,希望這些解決方案能給予大家相關經驗和思考,送人玫瑰,手留餘香。
主要遇到的問題以及對應的解決方案可參考下圖所示:
1、SQL兼容程度
通過上面的講解,大家可以看到使用上任何一款分布式數據庫中間件都會面臨一個問題:SQL是否全支持?
因為一條不含分片信息的SQL是需要經過解析、改寫、路由、執行、歸並這些步驟的,所以對SQL的加工處理,有可能會致使中間件對於部分SQL是不支持的。
在我們真正落地白條業務時,也出現了這個問題。
白條業務的業務邏輯非常複雜且龐大,同時多樣化場景的需求對SQL的兼容程度有較高要求。
ShardingSphere為了能全面支撐白條業務,進行了兩方面的優化重構:
- 一方面是重構了SQL解析模塊;
- 另一方面是在除了解析模塊之外的模塊對更多的SQL進行兼容支持,例如COUNT(DISTINCT *) 等SQL。
SQL解析模塊是中間件的基石,如果基石不牢靠,上層建築將岌岌可危。
從第一代的解析引擎使用Druid的內置解析引擎到第二代自研了SQL解析引擎,再到現在使用Antlr解析器作為SQL解析器,經歷了2年之久。
耗時費力如此之多,只為了真正搭建好基石,做到解析引擎自主可控、對SQL高效全面支持。當前,SQL支持情況為:
- 路由至單節點,SQL100%支持;
- 路由至多節點,全面支持DQL、DML、DDL、DCL、TCL和MySQL的部分DAL。支持分頁、去重、排序、分組、聚合、關聯查詢(不支持跨庫關聯);
- 具體支持情況,詳見:
- https://shardingsphere.apache.org/document/current/cn/features/sharding/use-norms/sql/
2、分布式主鍵
傳統數據庫軟件開發中,主鍵自動生成技術是基本需求。而各個數據庫對於該需求也提供了相應的支持,比如MySQL的自增鍵、Oracle的自增序列等。
數據分片後,不同數據節點生成全局唯一主鍵是非常棘手的問題。同一個邏輯表內的不同實際表之間的自增鍵由於無法互相感知而產生重復主鍵。
雖然可通過約束自增主鍵初始值和步長的方式避免碰撞,但需引入額外的運維規則,使解決方案缺乏完整性和可擴展性。
目前有許多第三方解決方案可以完美解決這個問題,如UUID等依靠特定算法自生成不重復鍵,或者通過引入主鍵生成服務等。
為了方便用戶使用、滿足不同用戶不同使用場景的需求,ShardingSphere提供了內置的分布式主鍵生成器,例如UUID、SNOWFLAKE等分布式主鍵生成器,用戶僅需簡單配置即可使用,生成全局性的唯一自增ID。
此外,我們還抽離出分布式主鍵生成器的接口,方便用戶自行做到自定義的自增主鍵生成算法,以滿足用戶特殊場景的需求。
3、業務分片鍵值注入
通過解析SQL語句提取分片鍵列與值並進行分片,是ShardingSphere對SQL零侵入的做到方式。
若SQL語句中沒有分片條件,則無法進行分片,需要全路由。在一些應用場景中,分片條件並不存在於SQL,而存在於外部業務邏輯。因此需要提供一種通過外部指定分片結果的方式,在ShardingSphere中叫做Hint。
ShardingSphere使用ThreadLocal管理分片鍵值。可以通過編程的方式向HintManager中添加分片條件,該分片條件僅在當前線程內生效。
除了通過編程的方式使用強制分片路由,ShardingSphere還計劃通過SQL中的特殊註釋的方式引用Hint,使開發者可以採用更加透明的方式使用該功能。指定了強制分片路由的SQL將會無視原有的分片邏輯,直接路由至指定的真實數據節點。
下面的圖片將給出這一場景的具體實施案例:
通過向HintManager注入status和具體路由表的關係,ShardingSphere將按照用戶指定規則,強制到db_0.t_order_1執行SQL,並將結果返回給用戶。
4、性能優化
性能問題是任何一個上線系統在面臨業務高峰時都必須要考慮的問題。面對京東白條這個量級的應用,ShardingSphere為了滿足白條業務對TPS/QPS的強制要求,做了多方面優化,主要為:
- SQL解析結果緩存;
- JDBC元數據信息緩存;
- Bind表&廣播表的使用;
- 自動化執行引擎&流式歸並。
受篇幅所限,這里主要為大家介紹Bind表和廣播表使用。這兩種表的配置使用,主要是為了優化表關聯問題中,切分表與切分表之間笛卡爾積表關聯的情況,以及解決跨庫表關聯不支持的情況。
綁定表是指分片規則一致的主表和子表。例如:t_order表和t_order_item表,均按照order_id分片,則此兩張表互為綁定表關係。綁定表之間的多表關聯查詢不會出現笛卡爾積關聯,從而關聯查詢效率將大大提升。
因為主表和子表使用相同的分片策略,數據在主表和子表的分布情況將一模一樣,所以表關聯查詢的時候就能避免笛卡爾積。舉例說明,如果SQL為:
SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
在不配置綁定表關係時,假設分片鍵order_id將數值10路由至第0片,將數值11路由至第1片,那麼路由後的SQL應該為4條,它們呈現為笛卡爾積:
SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
在配置綁定表關係後,路由的SQL應該為2條:
SELECT i.* FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
SELECT i.* FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
其中t_order在FROM的最左側,ShardingSphere將會以它作為整個綁定表的主表。
所有路由計算將會只使用主表的策略,那麼t_order_item表的分片計算將會使用t_order的條件。故綁定表之間的分區鍵要完全相同。
廣播表是指所有底層分片數據源中都存在的表,表結構和表中的數據在每個分庫中完全一致。
這樣在進行關聯查詢的時候,由於廣播表在所有分庫均存在,就避免了笛卡爾積關聯查詢以及跨庫關聯的情況。比較適用於數據量不大且需要與海量數據的表進行關聯查詢的場景,例如:字典表。
四、Apache ShardingSphere
迭代&規劃
Apache ShardingSphere的發展及規劃如下圖所示:
官網及GitHub也歡迎大家的訪問:
- 官網:
- https://shardingsphere.apache.org/
- GitHub:
- https://github.com/apache/incubator-shardingsphere
五、寫在最後
感謝各位朋友能閱讀到文章最後,當然也可能是直接跳到了這里。這篇文章來自於線上的分享,有興趣的朋友可以回顧線上分享,應該會比文字更生動有趣一些。
從最開始入職做DBA到現在轉為分布式數據庫中間件JAVA開發程序猿,也開始在開源領域里去探索尋找自我定位和意義。互聯網行業如同大海航行時代,波濤洶湧,變化萬千。
願所有朋友都能做好舵手,直掛雲帆濟滄海。
直播回放
https://m.qlchat.com/topic/details?topicId=2000003991669127