MTDDL——分布式數(shù)據(jù)訪問層中間件

背景

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)主從延遲账阻、表變更困難等一系列問題蒂秘。

要解決上面所說(shuō)的問題,通常有兩種方案淘太。第一種方案是直接對(duì)現(xiàn)有的商品庫(kù)進(jìn)行垂直拆分姻僧,可以緩解目前寫峰值QPS過(guò)大、DB主從延遲的問題蒲牧。第二種方案是對(duì)現(xiàn)有的商品庫(kù)大表進(jìn)行分庫(kù)分表撇贺,從根本上解決現(xiàn)有問題。方案一實(shí)施起來(lái)周期較短冰抢,但只能解決一時(shí)之痛松嘶,由此可見,分庫(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ò)展性龙致、功能的全面性和接入的便利性蛀缝。到目前為止一共開發(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ì)展開下曙强,然后從源碼的角度來(lái)剖析下MTDDL的整個(gè)邏輯架構(gòu)和具體實(shí)現(xiàn)残拐。

業(yè)界調(diào)研

設(shè)計(jì)目標(biāo)

MTDDL(Meituan Distributed Data Layer),美團(tuán)點(diǎn)評(píng)分布式數(shù)據(jù)訪問層中間件碟嘴,旨在為全公司提供一個(gè)通用數(shù)據(jù)訪問層服務(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ù)源登疗。

功能特性

1.動(dòng)態(tài)數(shù)據(jù)源

2.讀寫分離

3.分布式唯一主鍵生成器

4.分庫(kù)分表

5.連接池及SQL監(jiān)控

6.動(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ù)源间校。具體流程圖如下:

配置和使用方式舉例

分布式唯一主鍵生成器

眾所周知,分庫(kù)分表首先要解決的就是分布式唯一主鍵的問題页慷,業(yè)界也有很多相關(guān)方案:

綜上憔足,方案3的缺點(diǎn)可以通過(guò)一些手段避免,但其他方案的缺點(diǎn)不好處理酒繁,所以選擇第3種方案滓彰。目前該方案已由美團(tuán)點(diǎn)評(píng)技術(shù)工程部實(shí)現(xiàn)——分布式ID生成系統(tǒng)Leaf,MTDDL集成了此功能州袒。

分布式ID生成系統(tǒng)Leaf

美團(tuán)點(diǎn)評(píng)分布式ID生成系統(tǒng)Leaf揭绑,其實(shí)是一種基于DB的Ticket服務(wù),通過(guò)一張通用的Ticket表來(lái)實(shí)現(xiàn)分布式ID的持久化郎哭,執(zhí)行update更新語(yǔ)句來(lái)獲取一批Ticket他匪,這些獲取到的Ticket會(huì)在內(nèi)存中進(jìn)行分配弓叛,分配完之后再?gòu)腄B獲取下一批Ticket。整體架構(gòu)圖如下:

每個(gè)業(yè)務(wù)tag對(duì)應(yīng)一條DB記錄诚纸,DB MaxID字段記錄當(dāng)前該Tag已分配出去的最大ID值撰筷。

IDGenerator服務(wù)啟動(dòng)之初向DB申請(qǐng)一個(gè)號(hào)段,傳入號(hào)段長(zhǎng)度如 genStep = 10000畦徘,DB事務(wù)置 MaxID = MaxID + genStep毕籽,DB設(shè)置成功代表號(hào)段分配成功。每次IDGenerator號(hào)段分配都通過(guò)原子加的方式井辆,待分配完畢后重新申請(qǐng)新號(hào)段关筒。

唯一主鍵生成算法擴(kuò)展

MTDDL不僅集成了Leaf算法,還支持唯一主鍵算法的擴(kuò)展杯缺,通過(guò)新增唯一主鍵生成策略類實(shí)現(xiàn)IDGenStrategy接口即可蒸播。IDGenStrategy接口包含兩個(gè)方法:getIDGenType用來(lái)指定唯一主鍵生成策略,getId用來(lái)實(shí)現(xiàn)具體的唯一主鍵生成算法萍肆。其類圖如下:

分庫(kù)分表

在動(dòng)態(tài)數(shù)據(jù)源AOP的基礎(chǔ)上擴(kuò)展出分庫(kù)分表AOP袍榆,通過(guò)分庫(kù)分表ShardHandle類實(shí)現(xiàn)分庫(kù)分表數(shù)據(jù)源路由及分表計(jì)算。ShardHandle關(guān)聯(lián)了分庫(kù)分表上下文ShardContext類塘揣,而ShardContext封裝了所有的分庫(kù)分表算法包雀。其類圖如下:

分庫(kù)分表流程圖如下:

分庫(kù)分表取模算法

分庫(kù)分表目前默認(rèn)使用的是取模算法,分表算法為 (#shard_key % (group_shard_num * table_shard_num))亲铡,分庫(kù)算法為 (#shard_key % (group_shard_num * table_shard_num)) / table_shard_num才写,其中g(shù)roup_shard_num為分庫(kù)個(gè)數(shù),table_shard_num為每個(gè)庫(kù)的分表個(gè)數(shù)奖蔓。

例如把一張大表分成100張小表然后散到2個(gè)庫(kù)赞草,則0-49落在第一個(gè)庫(kù)、50-99落在第二個(gè)庫(kù)吆鹤。核心實(shí)現(xiàn)如下:

分庫(kù)分表算法擴(kuò)展

MTDDL不僅支持分庫(kù)分表取模算法厨疙,還支持分庫(kù)分表算法的擴(kuò)展,通過(guò)新增分庫(kù)分表策略類實(shí)現(xiàn)ShardStrategy接口即可檀头。ShardStrategy接口包含兩個(gè)方法:getShardType用來(lái)指定分庫(kù)分表策略轰异,handle用來(lái)實(shí)現(xiàn)具體的數(shù)據(jù)源及分表計(jì)算邏輯。其類圖如下:

全注解方式接入

為了盡可能地方便業(yè)務(wù)方接入暑始,MTDDL采用全注解方式使用分庫(kù)分表功能搭独,通過(guò)ShardInfo、ShardOn廊镜、IDGen三個(gè)注解實(shí)現(xiàn)牙肝。

ShardInfo注解用來(lái)指定具體的分庫(kù)分表配置:包括分表名前綴tableName、分表數(shù)量tableShardNum、分庫(kù)數(shù)量dbShardNum配椭、分庫(kù)分表策略shardType虫溜、唯一鍵生成策略idGenType、唯一鍵業(yè)務(wù)方標(biāo)識(shí)idGenKey股缸;ShardOn注解用來(lái)指定分庫(kù)分表字段衡楞;IDGen注解用來(lái)指定唯一鍵字段。具體類圖如下:

配置和使用方式舉例

連接池及SQL監(jiān)控

DB連接池使用不合理容易引發(fā)很多問題敦姻,如連接池最大連接數(shù)設(shè)置過(guò)小導(dǎo)致線程獲取不到連接瘾境、獲取連接等待時(shí)間設(shè)置過(guò)大導(dǎo)致很多線程掛起、空閑連接回收器運(yùn)行周期過(guò)長(zhǎng)導(dǎo)致空閑連接回收不及時(shí)等等镰惦,如果缺乏有效準(zhǔn)確的監(jiān)控迷守,會(huì)造成無(wú)法快速定位問題以及追溯歷史。

再者旺入,如果缺乏SQL執(zhí)行情況相關(guān)監(jiān)控兑凿,會(huì)很難及時(shí)發(fā)現(xiàn)DB慢查詢等潛在風(fēng)險(xiǎn),而慢查詢往往就是DB服務(wù)端性能惡化乃至宕機(jī)的根源(關(guān)于慢查詢茵瘾,推薦閱讀《MySQL索引原理及慢查詢優(yōu)化》一文)礼华。MTDDL從1.0.2版本開始正式引入連接池及SQL監(jiān)控等相關(guān)功能。

連接池監(jiān)控

實(shí)現(xiàn)方案

結(jié)合Spring完美適配c3p0龄捡、dbcp1卓嫂、dbcp2、mtthrift等多種方案聘殖,自動(dòng)發(fā)現(xiàn)新加入到Spring容器中的數(shù)據(jù)源進(jìn)行監(jiān)控,通過(guò)美團(tuán)點(diǎn)評(píng)統(tǒng)一監(jiān)控組件JMonitor上報(bào)監(jiān)控?cái)?shù)據(jù)行瑞。整體架構(gòu)圖如下:

連接數(shù)量監(jiān)控

監(jiān)控連接池active奸腺、idle、total連接數(shù)量血久,Counter格式:(連接池類型.數(shù)據(jù)源.active/idle/total_connection)突照,效果圖如下:

獲取連接時(shí)間監(jiān)控

監(jiān)控獲取空閑連接時(shí)間,Counter格式:(ds.getConnection.數(shù)據(jù)源.time)氧吐,效果圖如下:

SQL監(jiān)控

實(shí)現(xiàn)方案

采用Spring AOP技術(shù)對(duì)所有DAO方法進(jìn)行功能增強(qiáng)處理讹蘑,通過(guò)美團(tuán)點(diǎn)評(píng)分布式會(huì)話跟蹤組件MTrace進(jìn)行SQL調(diào)用數(shù)據(jù)埋點(diǎn)及上報(bào),進(jìn)而實(shí)現(xiàn)從客戶端角度對(duì)SQL執(zhí)行耗時(shí)筑舅、QPS座慰、調(diào)用量、超時(shí)率翠拣、失敗率等指標(biāo)進(jìn)行監(jiān)控版仔。整體架構(gòu)圖如下:

實(shí)現(xiàn)效果

登錄美團(tuán)點(diǎn)評(píng)的服務(wù)治理平臺(tái)OCTO選擇服務(wù)查看去向分析,效果圖如下:

動(dòng)態(tài)化配置

為了滿足業(yè)務(wù)方一些動(dòng)態(tài)化需求,如解決線上DB緊急事故需動(dòng)態(tài)調(diào)整數(shù)據(jù)源或者分庫(kù)分表相關(guān)配置蛮粮,要求無(wú)需重啟在線修改立即生效益缎,MTDDL從1.0.3版本開始正式引入動(dòng)態(tài)化配置相關(guān)功能。

實(shí)現(xiàn)方案

在Spring容器啟動(dòng)的時(shí)候自動(dòng)注冊(cè)數(shù)據(jù)源及分庫(kù)分表相關(guān)配置到美團(tuán)點(diǎn)評(píng)的統(tǒng)一配置中心MCC然想,在MCC配置管理頁(yè)面可以進(jìn)行動(dòng)態(tài)調(diào)整莺奔,MCC客戶端在感知到變更事件后會(huì)刷新本地配置,如果是數(shù)據(jù)源配置變更會(huì)根據(jù)新的配置構(gòu)造出一個(gè)新數(shù)據(jù)源來(lái)替換老數(shù)據(jù)源变泄,最后再將老的數(shù)據(jù)源優(yōu)雅關(guān)閉掉弊仪。具體流程圖如下:

動(dòng)態(tài)化數(shù)據(jù)源

目前支持dbcp、dbcp2杖刷、c3p0等數(shù)據(jù)源励饵,效果圖如下:

分庫(kù)分表動(dòng)態(tài)化

支持動(dòng)態(tài)化配置分庫(kù)分表數(shù)量、分庫(kù)分表策略滑燃、唯一鍵生成策略役听、唯一鍵業(yè)務(wù)方標(biāo)識(shí)等,效果圖如下:

版本迭代

MTDDL到目前為止總共開發(fā)了四期表窘,后續(xù)考慮逐步開源典予,具體版本迭代如下:

美團(tuán)點(diǎn)評(píng)技術(shù)博客原文鏈接:http://tech.meituan.com/mtddl.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市乐严,隨后出現(xiàn)的幾起案子瘤袖,更是在濱河造成了極大的恐慌,老刑警劉巖昂验,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捂敌,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡既琴,警方通過(guò)查閱死者的電腦和手機(jī)占婉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)甫恩,“玉大人逆济,你說(shuō)我怎么就攤上這事』腔” “怎么了奖慌?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)松靡。 經(jīng)常有香客問我简僧,道長(zhǎng),這世上最難降的妖魔是什么击困? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任涎劈,我火速辦了婚禮广凸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蛛枚。我一直安慰自己谅海,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布蹦浦。 她就那樣靜靜地躺著扭吁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盲镶。 梳的紋絲不亂的頭發(fā)上侥袜,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音溉贿,去河邊找鬼枫吧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛宇色,可吹牛的內(nèi)容都是我干的九杂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼宣蠕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼例隆!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起抢蚀,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤镀层,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后皿曲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唱逢,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年谷饿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惶我。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡博投,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盯蝴,到底是詐尸還是另有隱情毅哗,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布捧挺,位于F島的核電站虑绵,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏闽烙。R本人自食惡果不足惜翅睛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一声搁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捕发,春花似錦疏旨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至法挨,卻和暖如春谁榜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凡纳。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工窃植, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荐糜。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓巷怜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親狞尔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丛版,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容