1. 程式人生 > >網易分庫分表資料庫DDB

網易分庫分表資料庫DDB

作者:馬進,DDB專案負責人,2013年加入網易,熱衷於分散式中介軟體相關方面工作,從事過分庫分表資料庫DDB、快取NKV、分散式事務中介軟體TCC、分散式視訊處理系統NTS等專案。
本文為《程式設計師》原創文章,未經允許不得轉載,更多精彩文章請訂閱2017年《程式設計師》

網際網路時代,也是關係型資料庫獨領風騷的時代,從早期的Oracle獨步天下,到現在MySQL蒸蒸日上,關係型資料庫是大多數網際網路應用在資料可靠性儲存上的“命脈”。

隨著網際網路產品在體量和規模上日益膨脹,無論是Oracle還是MySQL,都會第一時間面臨來自磁碟、CPU和記憶體等單機瓶頸,為此,產品方除了需要不斷購買成本難以控制的高規格伺服器,還要面臨不斷迭代的線上資料遷移。在這種情況下,無論是海量的結構化資料還是快速成長的業務規模,都迫切需要一種水平擴充套件的方法將儲存成本分攤到成本可控的商用伺服器上。同時,也希望通過線性擴容降低全量資料遷移對線上服務帶來的影響,分庫分表方案便應運而生。

分庫分表的原理是將資料按照一定的分割槽規則Sharding到不同的關係型資料庫中,應用再通過中介軟體的方式訪問各個Shard中的資料。分庫分表的中介軟體,隱藏了資料Sharding和路由訪問的各項細節,使應用大多數場景下可以像使用單機資料庫一樣使用分庫分表後的分散式資料庫。業界中,網易DDB、阿里TDDL、Cobar、MyCat和HotDB等系統都是分庫分表中介軟體中的佼佼者。

背景——十年一劍

DDB(全稱Distributed Database)是網易杭研院立項最早、應用最為廣泛的後臺產品之一,也是國內最早出現的資料庫分庫分表中介軟體。

最早可以追溯到2006年,網易杭研成立之初,為了應對網易部落格這個日活超過800W的大體量應用,由現任杭研院院長的汪源帶隊主導開發了DDB這套分庫分表資料庫,伴隨著部落格的成長,DDB叢集也從最早的20+節點,到40+節點,最後到現在雲端100+個RDS例項。除了部落格外,十年來DDB也見證了很多其他大體量應用,如易信、雲音樂、雲閱讀、考拉等。在大家耳熟能詳的網易網際網路產品中,幾乎都可以看到DDB的身影。

經過10年的發展和演變,DDB的產品形態已全面趨於成熟,功能和效能得到了眾多產品的充分驗證,下面羅列一些大家比較關注的功能特性:

  1. 與SQL92標準的相容度達90%以上
  2. 支援跨庫JOIN和跨庫事務,支援大部分標量函式
  3. 支援COUNT、SUM、AVG、MAX、CONCAT等常用聚合函式
  4. 支援與MySQL高度一致的使用者管理
  5. 支援讀寫分離和資料節點高可用
  6. 支援資料節點線上擴縮容、線上更改表分佈
  7. 提供完善的資料庫管理工具、Web和命令列工具
  8. 資料節點支援Oracle和MySQL

目前DDB在網易內部有近50個產品使用,最大叢集過百資料節點,大部分部署在雲端,為應用提供透明、無侵入、MySQL標準協議的分庫分表服務。

DDB演變之路

十年來,DDB經歷了三次服務模式的重大更迭,從最早的Driver模式,到後來的Proxy模式,再到近幾年的雲模式,DDB服務模式的成長也深刻反映著網際網路流行架構的變遷。

Driver模式

Driver模式的特點在於應用通過DDB提供的JDBC Driver來訪問DDB,類似於通過MySQL的JDBC驅動訪問MySQL。而對於MySQL的驅動Connector/J,只需要實現將SQL按照特定協議編碼和轉碼即可。而DDB的驅動為了實現透明的分庫分表,需要做很多額外的工作,如圖1所示。

圖片描述

圖1

DDB Driver執行一條SQL時,會經歷以下幾個步驟:

  1. 由語法解析器解析SQL,生成抽象語法樹Parse Tree,並根據是否PreparedStatement決定是否進入PTC(Parse Tree Cache),PTC儲存了SQL模式到語法樹的對映,對PreparedStatement SQL,會優先進入PTC中查詢語法樹;

  2. 根據語法樹和啟發式規則生成分散式執行計劃,這個過程會涉及到多個步驟的SQL轉換和優化,如條件合併,JOIN拆分,LIMIT轉化等;

  3. 由SQL執行器按照執行計劃和語法樹生成下發給每個資料節點的真實SQL,然後通過標準資料庫驅動將SQL下發給各個資料節點,這個過程為併發執行;

  4. 將各個資料節點返回的結果按照執行計劃進行合併,並返回上層。具體的合併操作可能在應用呼叫結果時動態執行。

DBI模組作為DDB提供給應用的JDBC 驅動,包含了完整的透明分庫分表邏輯,是DDB最為核心的元件,除此之外,DDB中還有用於元資料管理和同步的Master元件、資料庫管理工具DBAdmin,和命令列工具ISQL,DDB的Driver模式整體架構如圖2所示。

圖片描述

圖2

管理操作以建表為例:

DBA通過DBAdmin的視窗建立表,或者用ISQL執行建表語句後,向Master發起實際建表請求,Master完成使用者認證和合法性校驗後,先在各個資料節點上建立新表,然後將新表元資料記錄在系統庫中,最後由Master將新表元資料同步給各個DBI模組。

對於建表語句中DDB特有的語法,會由ISQL或DBAdmin在解析DDL時完成相應處理,如自增ID的設定。

在DDB中,Master用於元資料管理、同步和報警監控。DBI模組啟動時,會第一時間向Master註冊,並拉取元資料,之後Master對元資料的同步保障了DBI模組元資料的更新。在DBI執行SQL,以及建立DB連線的過程中,不會涉及到與Master的互動。

在分庫分表中介軟體中,與DDB Driver模式同樣型別的還有阿里TDDL,優勢是部署簡單、成本較低、容易理解和上手。劣勢也非常明顯:只支援Java客戶端、版本難以管理、問題難以追蹤、DB連線難以歸斂等,另外一點是,中介軟體與應用繫結在一起,對應用本身是個巨大侵入,而且分庫分表的過程比較耗費CPU資源,所以在Driver模式下,無論是運維還是效能開銷上都存在不可控的因素。

Proxy模式

相比於Driver模式在多語言,版本管理,運維風險上存在的問題,Proxy模式很好地彌補了這些缺陷。所謂Proxy,就是在DDB中搭建了一組代理伺服器來提供標準的MySQL服務,在代理伺服器內部實現分庫分表的邏輯。本質上說,DDB Proxy作為一組獨立服務,實現了MySQL標準通訊協議,任何語言的MySQL驅動都可以訪問,而在Proxy內部,依賴DBI元件實現分庫分表,Proxy與DBI的關係如圖3所示。

圖片描述

圖3

應用通過標準資料庫驅動訪問DDB Proxy,Proxy內部通過MySQL解碼器將請求還原為SQL,並由DDB Driver,也就是DBI模組執行得到結果,最後通過MySQL編碼器返回給應用。

從圖3可以看出,Proxy在DBI上架設了MySQL編解碼模組,從而形成獨立標準的MySQL服務,而在MySQL編解碼模組之上,DDB Proxy也提供了很多特色命令支援,例如:

  1. show processlist:檢視Proxy所有連線狀態,與MySQL相關命令高度一致
  2. show connection_pool:查詢Proxy到資料節點的連線池狀態
  3. showtopsql:查詢按照SQL模式聚合的各項統計結果,如執行次數,平均執行時間
  4. count..from:查詢過去各個時間段內的吞吐量

此外,DDB Proxy內還提供了Slow Log等輔助功能,給運維帶來很大的便利。

DDB Proxy模式完整架構如圖4所示。

圖片描述

圖4

與Driver模式架構相比,除了QS(DDBProxy的內部稱謂,下同)取代了DBI的位置,還在多個QS節點之上部署了LVS或HAProxy + Keepalived的組合做負載均衡,從而實現多個DDBProxy節點的熱備,由於DDBProxy無狀態,或者說狀態統一由Master同步,在資料庫節點沒有達到瓶頸時,可以通過簡單地增設QS伺服器實現服務線性擴充套件。

私有云模式

在網易私有云專案啟動之前,DDB一直以一個個獨立叢集為不同業務提供服務,不同DDB各自為政毫不相干,這樣的好處是業務之間完全隔離,互不影響。不好之處在於隨著使用DDB的產品數目不斷增多,一個DBA往往同時運維數個甚至數十個DDB叢集,而之前我們一直缺乏一個平臺化的管理系統,DBA在各個叢集之間應接不暇時,我們沒有平臺化的統籌運維幫助應用及早發現問題,或是優化一些使用方法。例如版本管理,2013年我們在一個大版本中做了個Hotfix,並通知所有DBA將相關版本進行升級,但是最後由於管理疏漏,有個別集群沒有及時上線,為業務帶來了損失。當時如果我們有平臺化的管理方案,可以提供一些運維手段幫助和提醒運維人員及時更新所有有問題叢集,另外,平臺化的管理工具也可以定製一些自動化功能,如自動備份、報警組等。

網易私有云的出現為DDB的思變提供了契機,從2012年開始,我們就在基於網易私有云開發一套平臺化的管理工具Cloudadmin,為此,我們將DDB中原先Master的功能打散,一部分分庫相關功能整合到Proxy中,如分庫管理、表管理、使用者管理等,一部分中心化功能整合到Cloudadmin中,如報警監控,此外,Cloudadmin中提供了一鍵部署、自動和手動備份、版本管理等平臺化功能。私有云DDB的整體架構如圖5所示。

圖片描述

圖5

在雲DDB解決方案中,還打包了網易私有云LVS服務,Cloudadmin通過DDBAgent實現一鍵部署和報警監控。到目前為止,網易80%以上的DDB叢集都已部署雲端,雲DDB的出現極大減輕了運維人員的負擔。

DDB特性介紹

分散式執行計劃

分散式執行計劃定義了SQL在分庫分表環境中各個資料庫節點上執行的方法、順序和合並規則,是DDB實現中最為複雜的一環。

如SQL:select * from user order by id limit 10 offset 10;

這個SQL要查詢ID排名在10—20之間的user資訊,這裡涉及到兩個合併操作:全域性ID排序和全域性LIMIT OFFSET。對全域性ID排序,DDB的做法是將ID排序下發給各個資料庫節點,在DBI層再進行一層歸併排序,這樣可以充分利用資料庫節點的計算資源,同時將中介軟體層的排序複雜度降到最低,例如一些需要用到臨時檔案的排序場景,如果在中介軟體做全排序會導致極大開銷。

對全域性LIMIT OFFSET,DDB的做法是將OFFSET累加到LIMIT中下發,因為單個數據節點中的OFFSET沒有意義,且會造成錯誤的資料偏移,只有在中介軟體層的全域性OFFSET才能保證OFFSET的準確性。

所以最後下發給各個DBN的SQL變為:select * from user order by id limit 20。

又如SQL:select avg(age) from UserTet group by name

可以通過EXPLAIN語法得到SQL的執行計劃,如圖6所示。

圖片描述

圖6

上述SQL包含GROUP BY分組和AVG聚合兩種合併操作,與全域性ORDER BY類似,GROUP BY也可以下發給資料節點、中介軟體層做一個歸併去重,但是前提要將GROUP BY的欄位同時作為ORDER BY欄位下發,因為歸併的前提是排序。對AVG聚合,不能直接下發,因為得到所有資料節點各自的平均值,不能求出全域性平均值,需要在DBI層把AVG轉化為SUM和COUNT再下發,在結果集合並時再求平均。

DDB執行計劃的代價取決於DBI中的排序、過濾和連線,在大部分場景下,排序可以將ORDER BY下發簡化為一次性歸併排序,這種情況下代價較小,但是對GROUP BY和ORDER BY同時存在的場景,需要優先下發GROUP BY欄位的排序,以達到歸併分組的目的,這種情況下,就需要將所有元素做一次全排序,除非GROUP BY和ORDER BY欄位相同。

DDB的連線運算有兩種實現,第一種是將連線直接下發,若連線的兩張表資料分佈完全相同,並且在分割槽欄位上連線,則滿足連線直接下發的條件,因為在不同資料節點的分割槽欄位必然沒有相同值,不會出現跨庫連線的問題。若不滿足連線下發條件,會在DBI內部執行Nest Loop演算法,驅動表的順序與FROM表排列次序一致,此時若出現ORDER BY表次序與表排列次序不一致,則不滿足ORDER BY下發條件,也需要在DBI內做一次全排序。

分庫分表的執行計劃代價相比單機資料庫而言,更加難以掌控,即便是相同的SQL模式,在不同的資料分佈和分割槽欄位使用方式上,也存在很大的效能差距,DDB的使用要求開發者和DBA對執行計劃的原理具有一定認識。

如分庫分表在分割槽欄位的使用上很有講究:一般建議應用中80%以上的SQL查詢通過分割槽欄位過濾,使SQL可以單庫執行。對於那些沒有走分割槽欄位的查詢,需要在所有資料節點中並行下發,這對執行緒和CPU資源是一種極大的消耗,伴隨著資料節點的擴充套件,這種消耗會越來越劇烈。另外,基於分割槽欄位跨庫不重合的原理,在分割槽欄位上的分組、聚合、DISTINCT、連線等操作,都可以直接下發,這樣對中介軟體的代價往往最小。

分散式事務

分散式事務是個歷久彌新的話題,分庫分表、分散式事務的目的是保障分庫資料一致性,而跨庫事務會遇到各種不可控制的問題,如個別節點永久性宕機,如此像單機事務一樣的ACID是無法奢望的。另外,業界著名的CAP理論也告訴我們,對分散式系統,需要將資料一致性和系統可用性、分割槽容忍性放在天平上一起考慮。

兩階段提交協議(簡稱2PC)是實現分散式事務較為經典的方案,適用於中介軟體這種資料節點無耦合的場景。2PC的核心原理是通過提交分階段和記日誌的方式,記錄下事務提交所處的階段狀態,在元件宕機重啟後,可通過日誌恢復事務提交的階段狀態,並在這個狀態節點重試,如Coordinator重啟後,通過日誌可以確定提交處於Prepare還是PrepareAll狀態,若是前者,說明有節點可能沒有Prepare成功,或所有節點Prepare成功但還沒有下發Commit,狀態恢復後給所有節點下發RollBack;若是PrepareAll狀態,需要給所有節點下發Commit,資料庫節點需要保證Commit冪等。與很多其他一致性協議相同,2PC保障的是最終一致性。

2PC整個過程如圖7所示。

圖片描述

圖7

在DDB中,DBI和Proxy元件都作為Coordinator存在,2PC實現時,記錄Prepare和PrepareAll的日誌必須sync,以保障重啟後恢復狀態正確,而Coordinator最後的Commit日誌主要作用是回收之前日誌,可非同步執行。

由於2PC要求Coordinator記日誌,事務吞吐率受到磁碟I/O效能的約束,為此DDB實現了GROUP I/O優化,可極大程度提升2P C的吞吐率。2PC本質上說是一種阻塞式協議,兩階段提交過程需要大量執行緒資源,因此CPU和磁碟都有額外消耗,與單機事務相比,2PC在響應時間和吞吐率上相差很多,從CAP角度出發,可以認為2PC在一定程度上成全了C,犧牲了A。

另外,目前MySQL最流行的5.5和5.6版本中,XA事務日誌無法Replicate到從節點,這意味著主庫一旦宕機,切換到從庫後,XA的狀態會丟失,可能造成資料不一致,這方面MySQL 5.7已經有所改善。

雖然2PC有諸多不足,我們依然認為在DDB中有實現價值,DDB作為中介軟體,其迭代週期要比資料庫這種底層服務頻繁很多,若沒有2PC,一次更新或重啟就可能造成應用資料不一致。從應用角度看,分散式事務的現實場景常常無法規避,在有能力給出其他解決方案前,2PC也是一個不錯的選擇。

對購物轉賬等電商和金融業務,中介軟體層的2PC最大問題在於業務不可見,一旦出現不可抗力或意想不到的一致性破壞,如資料節點永久性宕機,業務難以根據2PC的日誌進行補償。金融場景下,資料一致性是命根,業務需要對資料有百分之百的掌控力,建議使用TCC這類分散式事務模型,或基於訊息佇列的柔性事務框架,這兩種方案都在業務層實現,業務開發者具有足夠掌控力,可以結合SOA框架來架構。原理上說,這兩種方案都是大事務拆小事務,小事務變本地事務,最後通過冪等的Retry來保障最終一致性。

彈性擴縮容

分庫分表資料庫中,線上資料遷移也是核心需求,會用在以下兩種場景:

  • 資料節點彈性擴容

隨著應用規模不斷增長,DDB現有的分庫可能有一天不足以支撐更多資料,要求DDB的資料節點具有線上彈性擴容的能力,而新節點加入集群后,按照不同的Sharding策略,可能需要將原有一些資料遷入新節點,如HASH分割槽,也有可能不需要線上資料遷移,如一些場景下的Range分割槽。無論如何,具備線上資料遷移是DDB支援彈性擴容的前提。

  • 資料重分佈

開發者在使用DDB過程中,有時會陷入困局,比如一些表的分割槽欄位一開始沒考慮清楚,在業務已經初具規模後才明確應該選擇其它欄位。又如一些表一開始認為資料量很小,單節點分佈足以,而隨著業務變化,需要轉變為多節點Sharding。這兩種場景都體現了開發者對DDB線上資料遷移功能的潛在需求。

無論是彈性擴容,還是表重分佈,都可當做DDB以表或庫為單位的一次完整線上資料遷移。可分為兩個階段:全量遷移和增量遷移:全量遷移是將原庫或原表中需要遷移的資料DUMP出來,並使用工具按照分割槽策略Apply到新庫新表中。增量遷移是要將全量遷移過程中產生的增量資料更新按照分割槽策略Apply到新庫新表。

全量遷移的方案相對簡單,使用DDB自帶工具按照特定分割槽策略DUMP和Load即可。對增量遷移,DDB實現了一套獨立的遷移工具Hamal來訂閱各個資料節點的增量更新,Hamal內部又依賴DBI模組將增量更新Apply到新庫新表,如圖8所示。

圖片描述

圖8

Hamal作為獨立服務,與Proxy一樣由DDB統一配置和管理,每個Hamal程序負責一個數據節點的增量遷移,啟動時模擬Slave向原庫拉取Binlog儲存本地,之後實時通過DBI模組Apply到新庫新表,除了基本的遷移功能外,Hamal具備以下兩個特性:

  1. 並行複製:Hamal的並行複製元件,通過在增量事件之間建立有向無環圖,實時判斷哪些事件可以並行執行,Hamal的並行複製與MySQL的並行複製相比快10倍以上;

  2. 斷點續傳:Hamal的增量Apply具有冪等性,在網路中斷或程序重啟之後可以斷點續傳。

全域性表

考慮一種場景:City表記錄了國內所有城市資訊,應用中有很多業務表需要與City做聯表查詢,如按照城市分組統計一些業務資訊。假設City的主鍵和分割槽鍵都是CityId,若連線操作發生在中介軟體層,代價較高,為了將連線操作下發資料節點,需要讓聯接的業務表同樣按照CityId分割槽,而大多數業務表往往不能滿足這個條件。

聯接直接下發需要滿足兩個條件,資料分佈相同和分割槽鍵上聯接,除此之外,其實還有一種解法,可以把City表冗餘到所有資料節點中,這樣各個資料節點本地聯接的集合便是所求結果。DDB將這種型別的表稱之為全域性表。

全域性表的特點是更新極少,通過2PC保障各個節點冗餘表的一致性。可以通過在建表語句新增相關 Hint指定全域性表型別,在應用使用DDB過程中,全域性表的概念對應用不可見。

未來——獨立平臺,與雲共舞

DDB作為網易濃縮了10年技術經驗與精華的分庫分表資料庫,近一兩年除了滿足內部產品使用外,也漸漸開始幫助外部企業客戶解決海量結構化資料儲存的難題。隨著公有云技術的大力發展和日趨成熟,各種IaaS和PaaS平臺如雨後春筍層出不窮,如網易蜂巢的推出,為應用開發、部署和運維提供了極大便利。而隨著IaaS層和PaaS平臺的普及,各種SaaS服務也會慢慢為廣大開發者所接納,未來DDB也將重點為網易蜂巢客戶打包DDB的SaaS服務,與蜂巢一同構建一套更加豐富的資料儲存生態系統。

我們對DDB的SaaS服務化無比堅定,同時DDB的公有云之路絕非私有云的生搬硬套,在與蜂巢一同幫助企業客戶解決分庫分表難題的同時,未來我們也會更加註重平臺獨立,首先要做的是將DDB的SaaS層與底層PaaS和IaaS層解耦,實現將DDB平臺所依賴的PaaS和IaaS以外掛方式注入。這樣既可以為客戶提供更靈活的服務方式,也可以極大程度降低DDB平臺本身的開發和運維成本:一套平臺管理工具,適用所有內外部DDB使用者,這是我們正在進行並將持續優化的目標。

訂閱諮詢:

• 線上諮詢(QQ):2251809102
• 電話諮詢:010-64351436
• 更多訊息,歡迎關注“程式設計師編輯部