支撐支付寶雙11雙12的核心架構(gòu)
本文轉(zhuǎn)載自微信公眾號(hào)「安琪拉的博客」,作者安琪拉 。轉(zhuǎn)載本文請(qǐng)聯(lián)系安琪拉的博客公眾號(hào)。
現(xiàn)在還依稀記得去年雙11在支付寶作戰(zhàn)室,接近0點(diǎn)的時(shí)候,所有人都盯著值班室的秒級(jí)監(jiān)控大盤(pán),當(dāng)交易峰值曲線慢慢爬升,最后變得無(wú)比陡峭,值班室的同學(xué)都很激動(dòng),歡呼聲伴隨著爬升的曲線達(dá)到了頂峰,58.3萬(wàn)筆/秒,也是新的交易峰值記錄,但相比往年動(dòng)輒翻一倍,漲30%~40%,增長(zhǎng)率還是小了很多。
2010年雙11的支付峰值是2萬(wàn)筆/分鐘,到2017雙11時(shí)變?yōu)榱?5.6萬(wàn)筆/秒,再到去年的58.3萬(wàn)筆/秒,是09年第一次雙11的一千多倍。
要抗住這么大的支付TPS,螞蟻?zhàn)隽撕芏囗攲蛹軜?gòu)的設(shè)計(jì)和底層實(shí)現(xiàn)的優(yōu)化,其中最為最核心的就是LDC架構(gòu)。
LDC 的全稱(chēng)為: Logic Data Center, 邏輯數(shù)據(jù)中心,之所以叫LDC,是跟傳統(tǒng)的IDC( Internet Data Center )相比而提出來(lái)的概念。
IDC 相信大家都很清楚,就是物理的數(shù)據(jù)中心,說(shuō)白了就是能夠建站的物理機(jī)房。
LDC(邏輯數(shù)據(jù)中心),核心架構(gòu)思想就是不管你物理機(jī)房部署是怎樣的,比如你可能有三個(gè)IDC,分別在二個(gè)不同城市(常說(shuō)的兩地三中心),在邏輯上是統(tǒng)一的,我邏輯上看成一個(gè)整體,統(tǒng)一協(xié)調(diào)調(diào)配。
為什么會(huì)出現(xiàn)LDC
LDC是為了解決什么問(wèn)題?還得從架構(gòu)的演進(jìn)說(shuō)起。上一篇文章講的機(jī)房容災(zāi)設(shè)計(jì)的架構(gòu)演進(jìn),我們用具體的應(yīng)用推演一次。
先看如下圖所示的單體應(yīng)用架構(gòu),請(qǐng)求到網(wǎng)關(guān)接口,網(wǎng)關(guān)接口直接調(diào)應(yīng)用或者服務(wù),服務(wù)調(diào)存儲(chǔ)層查詢(xún)或?qū)懭霐?shù)據(jù),一竿子捅到底。
這種架構(gòu)模式最大的風(fēng)險(xiǎn)是服務(wù)、存儲(chǔ)都是單點(diǎn)的,訪問(wèn)容量和性能受限于存儲(chǔ)和應(yīng)用的容量和性能,容災(zāi)方面,一旦發(fā)生故障只能死等單點(diǎn)應(yīng)用或存儲(chǔ)的恢復(fù)。
后來(lái)工程師們開(kāi)始對(duì)應(yīng)用做水平拆分,對(duì)服務(wù)做垂直拆分。
水平拆分應(yīng)該都很熟悉,就是加服務(wù)器,每臺(tái)服務(wù)器都部署實(shí)例,垂直拆分就是把服務(wù)按域做拆分,比如一個(gè)交易系統(tǒng),有商戶(hù)域、商品域、用戶(hù)域、訂單域等,拆分成多個(gè)微服務(wù),服務(wù)解耦,服務(wù)可以獨(dú)立發(fā)布,應(yīng)用的復(fù)雜度會(huì)更高。
這個(gè)分布式架構(gòu)解決了服務(wù)單點(diǎn)的問(wèn)題,某臺(tái)服務(wù)器宕機(jī),服務(wù)還是可用的,但是存儲(chǔ)層還是單點(diǎn)的,而且隨著業(yè)務(wù)增長(zhǎng),擴(kuò)容加的機(jī)器越多,大家發(fā)現(xiàn)查詢(xún)寫(xiě)入效率耗時(shí)到一定階段反倒是變慢了,分析發(fā)現(xiàn)存儲(chǔ)層出現(xiàn)了性能瓶頸。上面圖只花了2臺(tái)服務(wù)器連接數(shù)據(jù)庫(kù),真實(shí)分布式系統(tǒng)可能幾十百來(lái)臺(tái),甚至上千臺(tái),如果都連一臺(tái)DB,連接數(shù)、鎖爭(zhēng)用等問(wèn)題, SQL性能變慢可想而知。
后來(lái)的事情大家也都知道,互聯(lián)網(wǎng)公司開(kāi)始紛紛做讀寫(xiě)分離,把讀請(qǐng)求和寫(xiě)請(qǐng)求分開(kāi)。
讀寫(xiě)分離這里面隱含了一個(gè)邏輯,那就是數(shù)據(jù)寫(xiě)入之后,不會(huì)立即被使用。
數(shù)據(jù)從寫(xiě)入到被立即使用有個(gè)時(shí)間差,等從庫(kù)同步數(shù)據(jù)才會(huì)被讀取,實(shí)際統(tǒng)計(jì)發(fā)現(xiàn),常規(guī)的應(yīng)用,90%的數(shù)據(jù)確實(shí)在寫(xiě)入之后不會(huì)立即被使用,當(dāng)然我這里說(shuō)的立即的時(shí)間單位是ms,一般同步延遲也就是幾毫秒,不超過(guò)10 ~20ms。
但是這個(gè)架構(gòu)并沒(méi)有解決寫(xiě)的問(wèn)題,隨著業(yè)務(wù)量的增長(zhǎng),寫(xiě)數(shù)據(jù)成為了瓶頸。分庫(kù)分表應(yīng)運(yùn)而生,分庫(kù)分表的中間件開(kāi)始變得流行起來(lái),現(xiàn)在基本成了中大型互聯(lián)網(wǎng)公司的標(biāo)配。
基本思想就是把數(shù)據(jù)按照指定維度拆分,比較常見(jiàn)的是userId維度,例如取userId的后2位,可以拆分成百庫(kù)百表,也有的除以指定模數(shù)取余數(shù),例如除以64取余,可以按余數(shù)范圍0-63拆成64個(gè)庫(kù)。
關(guān)于分庫(kù)分表,很多人都知道有垂直拆分和水平拆分二種(上面說(shuō)的垂直和水平是系統(tǒng)的拆分,這里指的是存儲(chǔ)的),垂直拆分就是按照業(yè)務(wù)維度拆分,把同一個(gè)業(yè)務(wù)類(lèi)型的表放到一個(gè)庫(kù),經(jīng)常會(huì)按領(lǐng)域模型的概念拆分,比如訂單庫(kù)、用戶(hù)庫(kù)、商品庫(kù)等,水平拆分就是把大數(shù)據(jù)量的表(庫(kù))切分成很多個(gè)小數(shù)據(jù)量的表(庫(kù)),減小庫(kù)和表的訪問(wèn)壓力,可以和系統(tǒng)的水平垂直切分比一下:
水平拆分 | 垂直拆分 | |
---|---|---|
系統(tǒng)維度 | 加服務(wù)器 | 大系統(tǒng)按照業(yè)務(wù)域拆分成多個(gè)子系統(tǒng) |
數(shù)據(jù)庫(kù)維度 | 大數(shù)據(jù)量表按照userId分表規(guī)則拆成多個(gè)小表 | 大表按照業(yè)務(wù)域含義拆分成多個(gè)子表 |
為什么叫水平和垂直呢?其實(shí)很好理解,你想象一張用戶(hù)表,里面放了很多字段,如下圖:
那垂直拆分,就是垂直從中間劃一刀,把藍(lán)色的用戶(hù)信息表和右邊綠色的訂單信息表拆分成2張表。庫(kù)拆分成用戶(hù)庫(kù)和訂單庫(kù)。
水平拆分,就是水平劃一刀,把數(shù)據(jù)量降低。
大家看到這,是不是以為問(wèn)題都解決了,上面分庫(kù)分表之后,如果應(yīng)用層面扛得住,數(shù)據(jù)庫(kù)層面的確能做到并發(fā)量到萬(wàn)這個(gè)級(jí)別。但是容量要再上一個(gè)數(shù)量級(jí)就有點(diǎn)困難了。
為什么呢?因?yàn)橐粋€(gè)庫(kù)實(shí)例是被所有應(yīng)用共享的,也就是你每增加一臺(tái)機(jī)器,數(shù)據(jù)庫(kù)連接就會(huì)相應(yīng)的增加一些,增量是至少機(jī)器設(shè)置的最小連接數(shù)。
為什么應(yīng)用需要連接所有的數(shù)據(jù)庫(kù)實(shí)例呢?
答:網(wǎng)關(guān)層的流量可能走到任何一臺(tái)服務(wù)器,比如A用戶(hù)的請(qǐng)求到服務(wù)器上了,這時(shí)服務(wù)器一定要有A這個(gè)用戶(hù)userId 分片的數(shù)據(jù)庫(kù)連接,否則要么把流量路由走,要么執(zhí)行失敗。
分庫(kù)分表只是解決了單庫(kù)單表訪問(wèn)壓力的問(wèn)題,但是由于每一臺(tái)服務(wù)器都同時(shí)連接所有的分庫(kù)實(shí)例,到一定階段是沒(méi)發(fā)繼續(xù)擴(kuò)容的,因?yàn)閹?kù)實(shí)例的連接數(shù)有瓶頸。
那數(shù)據(jù)庫(kù)存在瓶頸怎么弄?
相信聰明的你們其實(shí)已經(jīng)猜到了,那就是按userId 分片在應(yīng)用層就做隔離,在網(wǎng)關(guān)層流量路由的時(shí)候把指定uid分片的流量路由到指定應(yīng)用單元執(zhí)行,這個(gè)應(yīng)用單元流量?jī)?nèi)部自消化,如下圖:
比如uid = 37487834,最后二位是34 屬于 00-49范圍,那用戶(hù)流量直接路由到00-49這個(gè)應(yīng)用分組,在這個(gè)單元內(nèi)的完成所有數(shù)據(jù)交互的操作。
這樣uid 00-49 這個(gè)分組單元中的應(yīng)用只用連userId 00-49 分庫(kù)的數(shù)據(jù)庫(kù),uid 50-99分組單元的應(yīng)用也是如此,數(shù)據(jù)庫(kù)的連接數(shù)一下直接降一半,而且還可以拆分單元,現(xiàn)在是2個(gè)單元,最多可以拆分到100個(gè)單元。
這里我加重了單元這個(gè)詞,因?yàn)檫@個(gè)是LDC中核心概念,下面重點(diǎn)說(shuō)一下單元這個(gè)詞的具體含義。
單元在螞蟻有個(gè)名稱(chēng)叫做 Zone,Zone內(nèi)部署的是完整的服務(wù),例如,一個(gè)用戶(hù)在一個(gè)Zone內(nèi)可以完成一整套業(yè)務(wù)流程,流量不需要其他Zone 來(lái)提供服務(wù),擁有完成一整套服務(wù)的能力,在單個(gè)Zone就能完成一整套業(yè)務(wù),是邏輯自包含的,這樣有什么好處,某個(gè)Zone如果出現(xiàn)故障,路由層直接把這個(gè)Zone流量轉(zhuǎn)移到其他Zone,接受這個(gè)Zone流量的其他幾個(gè)Zone可以分?jǐn)偭髁?,流量調(diào)撥很方便。
下面這張圖是螞蟻Zone 按照地區(qū)和userId 分片的部署架構(gòu)示意圖,做了一些簡(jiǎn)化,實(shí)際Zone部署單元會(huì)稍微復(fù)雜一點(diǎn)。
上面介紹的Zone 是有能力完成uid維度的一整套業(yè)務(wù)流程的,應(yīng)用互相依賴(lài)的服務(wù)都由本Zone提供,服務(wù)之間的調(diào)用都在本Zone內(nèi)完成的。但是聰明的你可以會(huì)想到一個(gè)問(wèn)題,有的數(shù)據(jù)不能按照userid維度拆分,全局只有一份怎么搞,比如配置中心的數(shù)據(jù),那是集中存儲(chǔ)的,全局只有一份配置,配置后也是全局生效。
其實(shí)在螞蟻內(nèi)部,Zone一共分為三種:RZone、GZone、CZone。
RZone: 上面說(shuō)的邏輯自包含的,業(yè)務(wù)系統(tǒng)整體部署的最小單元,能夠按照userId維度拆分服務(wù)和庫(kù)的都部署在RZone內(nèi)。
GZone:GZone是Global Zone,聽(tīng)這個(gè)名字,也知道,GZone的服務(wù)和庫(kù)全局只會(huì)部署一份,一定是在某個(gè)機(jī)房的,異地也會(huì)部署,但是只是為了災(zāi)備,不會(huì)啟用。
CZone:CZone比較有意思,為什么會(huì)有CZone,是為了解決GZone的弊端而產(chǎn)生的,上一篇《從B站崩了看互聯(lián)網(wǎng)公司如何做好高可用》架構(gòu)文章里面講過(guò),跨城調(diào)用,因?yàn)榫嚯x原因耗時(shí)比較高,如果GZone的服務(wù)部署在上海,杭州機(jī)房的服務(wù)需要用到GZone部署的服務(wù),只能跨城跨機(jī)房調(diào)用,很可能一個(gè)服務(wù)有很多次rpc調(diào)用,這樣耗時(shí)一定會(huì)很爆炸,那怎么弄?在城市與城市之間架起一座數(shù)據(jù)同步的橋梁,CZone就是起到了橋梁的作用,負(fù)責(zé)把GZone的數(shù)據(jù)在城市之前同步,C是city的意思。
也是因?yàn)榍懊嫖姨岬降?ldquo;寫(xiě)讀時(shí)間差現(xiàn)象”,寫(xiě)入GZone的數(shù)據(jù),允許一定的延遲,同步CZone同步給其他CZone。