背景
2016年Q3季度初,在美團(tuán)外賣上單2.0項(xiàng)目上線后,商家和商品數(shù)量急速增長(zhǎng),預(yù)估商品庫(kù)的容量和寫峰值QPS會(huì)很快遇到巨大壓力。隨之而來(lái)也會(huì)影響線上服務(wù)的查詢性能、DB(數(shù)據(jù)庫(kù),以下統(tǒng)一稱DB)主從延遲、表變更困難等一系列問(wèn)題。
要解決上面所說(shuō)的問(wèn)題,通常有兩種方案。第一種方案是直接對(duì)現(xiàn)有的商品庫(kù)進(jìn)行垂直拆分,可以緩解目前寫峰值QPS過(guò)大、DB主從延遲的問(wèn)題。第二種方案是對(duì)現(xiàn)有的商品庫(kù)大表進(jìn)行分庫(kù)分表,從根本上解決現(xiàn)有問(wèn)題。方案一實(shí)施起來(lái)周期較短,但只能解決一時(shí)之痛,由此可見(jiàn),分庫(kù)分表是必然的。
在確定分庫(kù)分表的方案之后,我們調(diào)研了外賣訂單、結(jié)算以及主站等業(yè)務(wù)的分庫(kù)分表實(shí)現(xiàn)方案,也調(diào)研了業(yè)界很多分庫(kù)分表中間件。在綜合考慮性能、穩(wěn)定性及實(shí)現(xiàn)成本的前提下,最終決定自主研發(fā)客戶端分庫(kù)分表中間件MTDDL來(lái)支撐外賣商品分庫(kù)分表項(xiàng)目,這也就是MTDDL的由來(lái)。
當(dāng)然,在MTDDL的設(shè)計(jì)研發(fā)過(guò)程中,我們充分考慮了MTDDL的通用性、可擴(kuò)展性、功能的全面性和接入的便利性。到目前為止一共開(kāi)發(fā)了四期,實(shí)現(xiàn)了MySQL動(dòng)態(tài)數(shù)據(jù)源、讀寫分離、分布式唯一主鍵生成器、分庫(kù)分表、連接池及SQL監(jiān)控、動(dòng)態(tài)化配置等一系列功能,支持分庫(kù)分表算法、分布式唯一主鍵生成算法的高可擴(kuò)展性,而且支持全注解的方式接入,業(yè)務(wù)方不需要引入任何配置文件。
下面就部分業(yè)界方案及MTDDL的設(shè)計(jì)目標(biāo)詳細(xì)展開(kāi)下,然后從源碼的角度來(lái)剖析下MTDDL的整個(gè)邏輯架構(gòu)和具體實(shí)現(xiàn)。
業(yè)界調(diào)研
業(yè)界組件簡(jiǎn)介實(shí)現(xiàn)方案功能特性優(yōu)點(diǎn)缺點(diǎn)AtlasQihoo 360開(kāi)發(fā)維護(hù)的一個(gè)基于MySQL協(xié)議的數(shù)據(jù)中間層項(xiàng)目。它實(shí)現(xiàn)了MySQL的客戶端與服務(wù)端協(xié)議,作為服務(wù)端與應(yīng)用程序通信,同時(shí)作為客戶端與MySQL通信proxy-based實(shí)現(xiàn)讀寫分離、單庫(kù)分表功能簡(jiǎn)單,性能跟穩(wěn)定性較好不支持分庫(kù)分表MTAtlas原美團(tuán)DBA團(tuán)隊(duì)在開(kāi)源Atlas基礎(chǔ)上做的一系列升級(jí)改造proxy-based在讀寫分離、單庫(kù)分表的基礎(chǔ)上,完成了分庫(kù)分表的功能開(kāi)發(fā)在Atlas基礎(chǔ)上支持了分庫(kù)分表當(dāng)時(shí)還處于測(cè)試階段,暫不推薦業(yè)務(wù)方使用TDDL淘寶根據(jù)自己的業(yè)務(wù)特點(diǎn)開(kāi)發(fā)了TDDL框架,主要解決了分庫(kù)分表對(duì)應(yīng)用的透明化以及異構(gòu)數(shù)據(jù)庫(kù)之間的數(shù)據(jù)復(fù)制,它是一個(gè)基于集中式配置的JDBC datasource實(shí)現(xiàn)client-based實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源、讀寫分離、分庫(kù)分表功能齊全分庫(kù)分表功能還未開(kāi)源,當(dāng)前公布文檔較少,并且需要依賴diamond(淘寶內(nèi)部使用的一個(gè)管理持久配置的系統(tǒng))ZebraZebra是原點(diǎn)評(píng)內(nèi)部使用數(shù)據(jù)源、DAO以及監(jiān)控等和數(shù)據(jù)庫(kù)打交道的中間件集client-based實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源、讀寫分離、分庫(kù)分表、CAT監(jiān)控功能齊全且有監(jiān)控接入較為復(fù)雜,當(dāng)時(shí)只支持c3p0、Druid、Tomcat JDBC等連接池,且分庫(kù)分表算法只支持Groovy表達(dá)式不易擴(kuò)展設(shè)計(jì)目標(biāo)
MTDDL(Meituan Distributed Data Layer),美團(tuán)點(diǎn)評(píng)分布式數(shù)據(jù)訪問(wèn)層中間件,旨在為全公司提供一個(gè)通用數(shù)據(jù)訪問(wèn)層服務(wù),支持MySQL動(dòng)態(tài)數(shù)據(jù)源、讀寫分離、分布式唯一主鍵生成器、分庫(kù)分表、動(dòng)態(tài)化配置等功能,并且支持從客戶端角度對(duì)數(shù)據(jù)源的各方面(比如連接池、SQL等)進(jìn)行監(jiān)控,后續(xù)考慮支持NoSQL、Cache等多種數(shù)據(jù)源。
功能特性
- 動(dòng)態(tài)數(shù)據(jù)源
- 讀寫分離
- 分布式唯一主鍵生成器
- 分庫(kù)分表
- 連接池及SQL監(jiān)控
- 動(dòng)態(tài)化配置
邏輯架構(gòu)
下圖是一次完整的DAO層insert方法調(diào)用時(shí)序圖,簡(jiǎn)單闡述了MTDDL的整個(gè)邏輯架構(gòu)。其中包含了分布式唯一主鍵的獲取、動(dòng)態(tài)數(shù)據(jù)源的路由以及SQL埋點(diǎn)監(jiān)控等過(guò)程:

具體實(shí)現(xiàn)
動(dòng)態(tài)數(shù)據(jù)源及讀寫分離
在Spring JDBC AbstractRoutingDataSource的基礎(chǔ)上擴(kuò)展出MultipleDataSource動(dòng)態(tài)數(shù)據(jù)源類,通過(guò)動(dòng)態(tài)數(shù)據(jù)源注解及AOP實(shí)現(xiàn)。
動(dòng)態(tài)數(shù)據(jù)源
MultipleDataSource動(dòng)態(tài)數(shù)據(jù)源類,繼承于Spring JDBC AbstractRoutingDataSource抽象類,實(shí)現(xiàn)了determineCurrentLookupKey方法,通過(guò)setDataSourceKey方法來(lái)動(dòng)態(tài)調(diào)整dataSourceKey,進(jìn)而達(dá)到動(dòng)態(tài)調(diào)整數(shù)據(jù)源的功能。其類圖如下:

動(dòng)態(tài)數(shù)據(jù)源AOP
ShardMultipleDataSourceAspect動(dòng)態(tài)數(shù)據(jù)源切面類,針對(duì)DAO方法進(jìn)行功能增強(qiáng),通過(guò)掃描DataSource動(dòng)態(tài)數(shù)據(jù)源注解來(lái)獲取相應(yīng)的dataSourceKey,從而指定具體的數(shù)據(jù)源。具體流程圖如下: