每秒處理10萬(wàn)訂單樂(lè)視集團(tuán)支付架構(gòu)
隨著樂(lè)視硬件搶購(gòu)的不斷升級(jí),樂(lè)視集團(tuán)支付面臨的請(qǐng)求壓力百倍乃至千倍的暴增沦辙。作為商品購(gòu)買(mǎi)的最后一環(huán)夫植,保證用戶快速穩(wěn)定的完成支付尤為重要。所以在15年11月油讯,我們對(duì)整個(gè)支付系統(tǒng)進(jìn)行了全面的架構(gòu)升級(jí)详民,使之具備了每秒穩(wěn)定處理10萬(wàn)訂單的能力。為樂(lè)視生態(tài)各種形式的搶購(gòu)秒殺活動(dòng)提供了強(qiáng)有力的支撐陌兑。
一. 分庫(kù)分表
在redis沈跨,memcached等緩存系統(tǒng)盛行的互聯(lián)網(wǎng)時(shí)代,構(gòu)建一個(gè)支撐每秒十萬(wàn)只讀的系統(tǒng)并不復(fù)雜兔综,無(wú)非是通過(guò)一致性哈希擴(kuò)展緩存節(jié)點(diǎn)饿凛,水平擴(kuò)展web服務(wù)器等。支付系統(tǒng)要處理每秒十萬(wàn)筆訂單软驰,需要的是每秒數(shù)十萬(wàn)的數(shù)據(jù)庫(kù)更新操作(insert加update)涧窒,這在任何一個(gè)獨(dú)立數(shù)據(jù)庫(kù)上都是不可能完成的任務(wù),所以我們首先要做的是對(duì)訂單表(簡(jiǎn)稱(chēng)order)進(jìn)行分庫(kù)與分表锭亏。
在進(jìn)行數(shù)據(jù)庫(kù)操作時(shí)纠吴,一般都會(huì)有用戶ID(簡(jiǎn)稱(chēng)uid)字段,所以我們選擇以u(píng)id進(jìn)行分庫(kù)分表贰镣。
分庫(kù)策略我們選擇了“二叉樹(shù)分庫(kù)”呜象,所謂“二叉樹(shù)分庫(kù)”指的是:我們?cè)谶M(jìn)行數(shù)據(jù)庫(kù)擴(kuò)容時(shí),都是以2的倍數(shù)進(jìn)行擴(kuò)容碑隆。比如:1臺(tái)擴(kuò)容到2臺(tái)恭陡,2臺(tái)擴(kuò)容到4臺(tái),4臺(tái)擴(kuò)容到8臺(tái)上煤,以此類(lèi)推休玩。這種分庫(kù)方式的好處是,我們?cè)谶M(jìn)行擴(kuò)容時(shí)劫狠,只需DBA進(jìn)行表級(jí)的數(shù)據(jù)同步拴疤,而不需要自己寫(xiě)腳本進(jìn)行行級(jí)數(shù)據(jù)同步。
光是有分庫(kù)是不夠的独泞,經(jīng)過(guò)持續(xù)壓力測(cè)試我們發(fā)現(xiàn)呐矾,在同一數(shù)據(jù)庫(kù)中,對(duì)多個(gè)表進(jìn)行并發(fā)更新的效率要遠(yuǎn)遠(yuǎn)大于對(duì)一個(gè)表進(jìn)行并發(fā)更新懦砂,所以我們?cè)诿總€(gè)分庫(kù)中都將order表拆分成10份:order_0蜒犯,order_1组橄,....,order_9罚随。
最后我們把order表放在了8個(gè)分庫(kù)中(編號(hào)1到8玉工,分別對(duì)應(yīng)DB1到DB8),每個(gè)分庫(kù)中10個(gè)分表(編號(hào)0到9淘菩,分別對(duì)應(yīng)order_0到order_9)遵班,部署結(jié)構(gòu)如下圖所示:
根據(jù)uid計(jì)算數(shù)據(jù)庫(kù)編號(hào):
數(shù)據(jù)庫(kù)編號(hào) = (uid / 10) % 8 + 1
根據(jù)uid計(jì)算表編號(hào):
表編號(hào) = uid % 10
當(dāng)uid=9527時(shí),根據(jù)上面的算法潮改,其實(shí)是把uid分成了兩部分952和7狭郑,其中952模8加1等于1為數(shù)據(jù)庫(kù)編號(hào),而7則為表編號(hào)进陡。所以u(píng)id=9527的訂單信息需要去DB1庫(kù)中的order_7表查找愿阐。具體算法流程也可參見(jiàn)下圖:
有了分庫(kù)分表的結(jié)構(gòu)與算法最后就是尋找分庫(kù)分表的實(shí)現(xiàn)工具微服,目前市面上約有兩種類(lèi)型的分庫(kù)分表工具:
客戶端分庫(kù)分表趾疚,在客戶端完成分庫(kù)分表操作,直連數(shù)據(jù)庫(kù)
使用分庫(kù)分表中間件以蕴,客戶端連分庫(kù)分表中間件糙麦,由中間件完成分庫(kù)分表操作
這兩種類(lèi)型的工具市面上都有,這里不一一列舉丛肮,總的來(lái)看這兩類(lèi)工具各有利弊赡磅。客戶端分庫(kù)分表由于直連數(shù)據(jù)庫(kù)宝与,所以性能比使用分庫(kù)分表中間件高15%到20%焚廊。而使用分庫(kù)分表中間件由于進(jìn)行了統(tǒng)一的中間件管理,將分庫(kù)分表操作和客戶端隔離习劫,模塊劃分更加清晰咆瘟,便于DBA進(jìn)行統(tǒng)一管理。
我們選擇的是在客戶端分庫(kù)分表诽里,因?yàn)槲覀冏约洪_(kāi)發(fā)并開(kāi)源了一套數(shù)據(jù)層訪問(wèn)框架袒餐,它的代號(hào)叫“芒果”,芒果框架原生支持分庫(kù)分表功能谤狡,并且配置起來(lái)非常簡(jiǎn)單灸眼。
芒果主頁(yè):mango.jfaster.org
芒果源碼:github.com/jfaster/mango
二. 訂單ID
訂單系統(tǒng)的ID必須具有全局唯一的特征,最簡(jiǎn)單的方式是利用數(shù)據(jù)庫(kù)的序列墓懂,每操作一次就能獲得一個(gè)全局唯一的自增ID焰宣,如果要支持每秒處理10萬(wàn)訂單,那每秒將至少需要生成10萬(wàn)個(gè)訂單ID捕仔,通過(guò)數(shù)據(jù)庫(kù)生成自增ID顯然無(wú)法完成上述要求匕积。所以我們只能通過(guò)內(nèi)存計(jì)算獲得全局唯一的訂單ID佛嬉。
JAVA領(lǐng)域最著名的唯一ID應(yīng)該算是UUID了,不過(guò)UUID太長(zhǎng)而且包含字母闸天,不適合作為訂單ID暖呕。通過(guò)反復(fù)比較與篩選,我們借鑒了Twitter的Snowflake算法苞氮,實(shí)現(xiàn)了全局唯一ID湾揽。下面是訂單ID的簡(jiǎn)化結(jié)構(gòu)圖:
上圖分為3個(gè)部分:
1.時(shí)間戳
這里時(shí)間戳的粒度是毫秒級(jí),生成訂單ID時(shí)笼吟,使用System.currentTimeMillis()作為時(shí)間戳库物。
2.機(jī)器號(hào)
每個(gè)訂單服務(wù)器都將被分配一個(gè)唯一的編號(hào),生成訂單ID時(shí)贷帮,直接使用該唯一編號(hào)作為機(jī)器號(hào)即可戚揭。
3.自增序號(hào)
當(dāng)在同一服務(wù)器的同一毫秒中有多個(gè)生成訂單ID的請(qǐng)求時(shí),會(huì)在當(dāng)前毫秒下自增此序號(hào)撵枢,下一個(gè)毫秒此序號(hào)繼續(xù)從0開(kāi)始民晒。比如在同一服務(wù)器同一毫秒有3個(gè)生成訂單ID的請(qǐng)求,這3個(gè)訂單ID的自增序號(hào)部分將分別是0锄禽,1潜必,2。
上面3個(gè)部分組合沃但,我們就能快速生成全局唯一的訂單ID磁滚。不過(guò)光全局唯一還不夠,很多時(shí)候我們會(huì)只根據(jù)訂單ID直接查詢訂單信息宵晚,這時(shí)由于沒(méi)有uid垂攘,我們不知道去哪個(gè)分庫(kù)的分表中查詢,遍歷所有的庫(kù)的所有表淤刃?這顯然不行晒他。所以我們需要將分庫(kù)分表的信息添加到訂單ID上,下面是帶分庫(kù)分表信息的訂單ID簡(jiǎn)化結(jié)構(gòu)圖:
我們?cè)谏傻娜钟唵蜪D頭部添加了分庫(kù)與分表的信息钝凶,這樣只根據(jù)訂單ID仪芒,我們也能快速的查詢到對(duì)應(yīng)的訂單信息。
分庫(kù)分表信息具體包含哪些內(nèi)容耕陷?第一部分有討論到掂名,我們將訂單表按uid維度拆分成了8個(gè)數(shù)據(jù)庫(kù),每個(gè)數(shù)據(jù)庫(kù)10張表哟沫,最簡(jiǎn)單的分庫(kù)分表信息只需一個(gè)長(zhǎng)度為2的字符串即可存儲(chǔ)饺蔑,第1位存數(shù)據(jù)庫(kù)編號(hào),取值范圍1到8嗜诀,第2位存表編號(hào)猾警,取值范圍0到9孔祸。
還是按照第一部分根據(jù)uid計(jì)算數(shù)據(jù)庫(kù)編號(hào)和表編號(hào)的算法,當(dāng)uid=9527時(shí)发皿,分庫(kù)信息=1崔慧,分表信息=7,將他們進(jìn)行組合穴墅,兩位的分庫(kù)分表信息即為"17"惶室。具體算法流程參見(jiàn)下圖:
上述使用表編號(hào)作為分表信息沒(méi)有任何問(wèn)題,但使用數(shù)據(jù)庫(kù)編號(hào)作為分庫(kù)信息卻存在隱患玄货,考慮未來(lái)的擴(kuò)容需求皇钞,我們需要將8庫(kù)擴(kuò)容到16庫(kù),這時(shí)取值范圍1到8的分庫(kù)信息將無(wú)法支撐1到16的分庫(kù)場(chǎng)景松捉,分庫(kù)路由將無(wú)法正確完成夹界,我們將上訴問(wèn)題簡(jiǎn)稱(chēng)為分庫(kù)信息精度丟失。
為解決分庫(kù)信息精度丟失問(wèn)題隘世,我們需要對(duì)分庫(kù)信息精度進(jìn)行冗余可柿,即我們現(xiàn)在保存的分庫(kù)信息要支持以后的擴(kuò)容。這里我們假設(shè)最終我們會(huì)擴(kuò)容到64臺(tái)數(shù)據(jù)庫(kù)以舒,所以新的分庫(kù)信息算法為:
分庫(kù)信息 = (uid / 10) % 64 + 1
當(dāng)uid=9527時(shí)趾痘,根據(jù)新的算法慢哈,分庫(kù)信息=57蔓钟,這里的57并不是真正數(shù)據(jù)庫(kù)的編號(hào),它冗余了最后擴(kuò)展到64臺(tái)數(shù)據(jù)庫(kù)的分庫(kù)信息精度卵贱。我們當(dāng)前只有8臺(tái)數(shù)據(jù)庫(kù)滥沫,實(shí)際數(shù)據(jù)庫(kù)編號(hào)還需根據(jù)下面的公式進(jìn)行計(jì)算:
實(shí)際數(shù)據(jù)庫(kù)編號(hào) = (分庫(kù)信息 - 1) % 8 + 1
當(dāng)uid=9527時(shí),分庫(kù)信息=57键俱,實(shí)際數(shù)據(jù)庫(kù)編號(hào)=1兰绣,分庫(kù)分表信息="577"。
由于我們選擇模64來(lái)保存精度冗余后的分庫(kù)信息编振,保存分庫(kù)信息的長(zhǎng)度由1變?yōu)榱?缀辩,最后的分庫(kù)分表信息的長(zhǎng)度為3。具體算法流程也可參見(jiàn)下圖:
如上圖所示踪央,在計(jì)算分庫(kù)信息的時(shí)候采用了模64的方式冗余了分庫(kù)信息精度臀玄,這樣當(dāng)我們的系統(tǒng)以后需要擴(kuò)容到16庫(kù),32庫(kù)畅蹂,64庫(kù)都不會(huì)再有問(wèn)題健无。
上面的訂單ID結(jié)構(gòu)已經(jīng)能很好的滿足我們當(dāng)前與之后的擴(kuò)容需求,但考慮到業(yè)務(wù)的不確定性液斜,我們?cè)谟唵蜪D的最前方加了1位用于標(biāo)識(shí)訂單ID的版本累贤,這個(gè)版本號(hào)屬于冗余數(shù)據(jù)叠穆,目前并沒(méi)有用到。下面是最終訂單ID簡(jiǎn)化結(jié)構(gòu)圖:
Snowflake算法:github.com/twitter/snowflake
三. 最終一致性
到目前為止臼膏,我們通過(guò)對(duì)order表uid維度的分庫(kù)分表硼被,實(shí)現(xiàn)了order表的超高并發(fā)寫(xiě)入與更新,并能通過(guò)uid和訂單ID查詢訂單信息渗磅。但作為一個(gè)開(kāi)放的集團(tuán)支付系統(tǒng)祷嘶,我們還需要通過(guò)業(yè)務(wù)線ID(又稱(chēng)商戶ID,簡(jiǎn)稱(chēng)bid)來(lái)查詢訂單信息夺溢,所以我們引入了bid維度的order表集群论巍,將uid維度的order表集群冗余一份到bid維度的order表集群中,要根據(jù)bid查詢訂單信息時(shí)风响,只需查bid維度的order表集群即可嘉汰。
上面的方案雖然簡(jiǎn)單,但保持兩個(gè)order表集群的數(shù)據(jù)一致性是一件很麻煩的事情状勤。兩個(gè)表集群顯然是在不同的數(shù)據(jù)庫(kù)集群中鞋怀,如果在寫(xiě)入與更新中引入強(qiáng)一致性的分布式事務(wù),這無(wú)疑會(huì)大大降低系統(tǒng)效率持搜,增長(zhǎng)服務(wù)響應(yīng)時(shí)間密似,這是我們所不能接受的,所以我們引入了消息隊(duì)列進(jìn)行異步數(shù)據(jù)同步葫盼,來(lái)實(shí)現(xiàn)數(shù)據(jù)的最終一致性残腌。當(dāng)然消息隊(duì)列的各種異常也會(huì)造成數(shù)據(jù)不一致,所以我們又引入了實(shí)時(shí)監(jiān)控服務(wù)贫导,實(shí)時(shí)計(jì)算兩個(gè)集群的數(shù)據(jù)差異抛猫,并進(jìn)行一致性同步。
下面是簡(jiǎn)化的一致性同步圖:
四. 數(shù)據(jù)庫(kù)高可用
沒(méi)有任何機(jī)器或服務(wù)能保證在線上穩(wěn)定運(yùn)行不出故障孩灯。比如某一時(shí)間闺金,某一數(shù)據(jù)庫(kù)主庫(kù)宕機(jī),這時(shí)我們將不能對(duì)該庫(kù)進(jìn)行讀寫(xiě)操作峰档,線上服務(wù)將受到影響败匹。
所謂數(shù)據(jù)庫(kù)高可用指的是:當(dāng)數(shù)據(jù)庫(kù)由于各種原因出現(xiàn)問(wèn)題時(shí),能實(shí)時(shí)或快速的恢復(fù)數(shù)據(jù)庫(kù)服務(wù)并修補(bǔ)數(shù)據(jù)讥巡,從整個(gè)集群的角度看掀亩,就像沒(méi)有出任何問(wèn)題一樣。需要注意的是尚卫,這里的恢復(fù)數(shù)據(jù)庫(kù)服務(wù)并不一定是指修復(fù)原有數(shù)據(jù)庫(kù)归榕,也包括將服務(wù)切換到另外備用的數(shù)據(jù)庫(kù)。
數(shù)據(jù)庫(kù)高可用的主要工作是數(shù)據(jù)庫(kù)恢復(fù)與數(shù)據(jù)修補(bǔ)吱涉,一般我們以完成這兩項(xiàng)工作的時(shí)間長(zhǎng)短刹泄,作為衡量高可用好壞的標(biāo)準(zhǔn)外里。這里有一個(gè)惡性循環(huán)的問(wèn)題,數(shù)據(jù)庫(kù)恢復(fù)的時(shí)間越長(zhǎng)特石,不一致數(shù)據(jù)越多盅蝗,數(shù)據(jù)修補(bǔ)的時(shí)間就會(huì)越長(zhǎng),整體修復(fù)的時(shí)間就會(huì)變得更長(zhǎng)姆蘸。所以數(shù)據(jù)庫(kù)的快速恢復(fù)成了數(shù)據(jù)庫(kù)高可用的重中之重墩莫,試想一下如果我們能在數(shù)據(jù)庫(kù)出故障的1秒之內(nèi)完成數(shù)據(jù)庫(kù)恢復(fù),修復(fù)不一致的數(shù)據(jù)和成本也會(huì)大大降低逞敷。
下圖是一個(gè)最經(jīng)典的主從結(jié)構(gòu):
上圖中有1臺(tái)web服務(wù)器和3臺(tái)數(shù)據(jù)庫(kù)狂秦,其中DB1是主庫(kù),DB2和DB3是從庫(kù)推捐。我們?cè)谶@里假設(shè)web服務(wù)器由項(xiàng)目組維護(hù)裂问,而數(shù)據(jù)庫(kù)服務(wù)器由DBA維護(hù)。
當(dāng)從庫(kù)DB2出現(xiàn)問(wèn)題時(shí)牛柒,DBA會(huì)通知項(xiàng)目組堪簿,項(xiàng)目組將DB2從web服務(wù)的配置列表中刪除,重啟web服務(wù)器皮壁,這樣出錯(cuò)的節(jié)點(diǎn)DB2將不再被訪問(wèn)椭更,整個(gè)數(shù)據(jù)庫(kù)服務(wù)得到恢復(fù),等DBA修復(fù)DB2時(shí)蛾魄,再由項(xiàng)目組將DB2添加到web服務(wù)虑瀑。
當(dāng)主庫(kù)DB1出現(xiàn)問(wèn)題時(shí),DBA會(huì)將DB2切換為主庫(kù)畏腕,并通知項(xiàng)目組缴川,項(xiàng)目組使用DB2替換原有的主庫(kù)DB1,重啟web服務(wù)器描馅,這樣web服務(wù)將使用新的主庫(kù)DB2,而DB1將不再被訪問(wèn)而线,整個(gè)數(shù)據(jù)庫(kù)服務(wù)得到恢復(fù)铭污,等DBA修復(fù)DB1時(shí),再將DB1作為DB2的從庫(kù)即可膀篮。
上面的經(jīng)典結(jié)構(gòu)有很大的弊侧谀:不管主庫(kù)或從庫(kù)出現(xiàn)問(wèn)題,都需要DBA和項(xiàng)目組協(xié)同完成數(shù)據(jù)庫(kù)服務(wù)恢復(fù)誓竿,這很難做到自動(dòng)化磅网,而且恢復(fù)工程也過(guò)于緩慢。
我們認(rèn)為筷屡,數(shù)據(jù)庫(kù)運(yùn)維應(yīng)該和項(xiàng)目組分開(kāi)涧偷,當(dāng)數(shù)據(jù)庫(kù)出現(xiàn)問(wèn)題時(shí)簸喂,應(yīng)由DBA實(shí)現(xiàn)統(tǒng)一恢復(fù),不需要項(xiàng)目組操作服務(wù)燎潮,這樣便于做到自動(dòng)化喻鳄,縮短服務(wù)恢復(fù)時(shí)間。
先來(lái)看從庫(kù)高可用結(jié)構(gòu)圖:
如上圖所示确封,web服務(wù)器將不再直接連接從庫(kù)DB2和DB3除呵,而是連接LVS負(fù)載均衡,由LVS連接從庫(kù)爪喘。這樣做的好處是LVS能自動(dòng)感知從庫(kù)是否可用颜曾,從庫(kù)DB2宕機(jī)后,LVS將不會(huì)把讀數(shù)據(jù)請(qǐng)求再發(fā)向DB2秉剑。同時(shí)DBA需要增減從庫(kù)節(jié)點(diǎn)時(shí)泛啸,只需獨(dú)立操作LVS即可,不再需要項(xiàng)目組更新配置文件秃症,重啟服務(wù)器來(lái)配合候址。
再來(lái)看主庫(kù)高可用結(jié)構(gòu)圖:
如上圖所示,web服務(wù)器將不再直接連接主庫(kù)DB1种柑,而是連接KeepAlive虛擬出的一個(gè)虛擬ip岗仑,再將此虛擬ip映射到主庫(kù)DB1上,同時(shí)添加DB_bak從庫(kù)聚请,實(shí)時(shí)同步DB1中的數(shù)據(jù)荠雕。正常情況下web還是在DB1中讀寫(xiě)數(shù)據(jù),當(dāng)DB1宕機(jī)后驶赏,腳本會(huì)自動(dòng)將DB_bak設(shè)置成主庫(kù)炸卑,并將虛擬ip映射到DB_bak上,web服務(wù)將使用健康的DB_bak作為主庫(kù)進(jìn)行讀寫(xiě)訪問(wèn)煤傍。這樣只需幾秒的時(shí)間盖文,就能完成主數(shù)據(jù)庫(kù)服務(wù)恢復(fù)。
組合上面的結(jié)構(gòu)蚯姆,得到主從高可用結(jié)構(gòu)圖:
數(shù)據(jù)庫(kù)高可用還包含數(shù)據(jù)修補(bǔ)五续,由于我們?cè)诓僮骱诵臄?shù)據(jù)時(shí),都是先記錄日志再執(zhí)行更新龄恋,加上實(shí)現(xiàn)了近乎實(shí)時(shí)的快速恢復(fù)數(shù)據(jù)庫(kù)服務(wù)疙驾,所以修補(bǔ)的數(shù)據(jù)量都不大,一個(gè)簡(jiǎn)單的恢復(fù)腳本就能快速完成數(shù)據(jù)修復(fù)郭毕。
五. 數(shù)據(jù)分級(jí)
支付系統(tǒng)除了最核心的支付訂單表與支付流水表外它碎,還有一些配置信息表和一些用戶相關(guān)信息表。如果所有的讀操作都在數(shù)據(jù)庫(kù)上完成,系統(tǒng)性能將大打折扣扳肛,所以我們引入了數(shù)據(jù)分級(jí)機(jī)制傻挂。
我們簡(jiǎn)單的將支付系統(tǒng)的數(shù)據(jù)劃分成了3級(jí):
第1級(jí):訂單數(shù)據(jù)和支付流水?dāng)?shù)據(jù);這兩塊數(shù)據(jù)對(duì)實(shí)時(shí)性和精確性要求很高敞峭,所以不添加任何緩存踊谋,讀寫(xiě)操作將直接操作數(shù)據(jù)庫(kù)。
第2級(jí):用戶相關(guān)數(shù)據(jù)旋讹;這些數(shù)據(jù)和用戶相關(guān)殖蚕,具有讀多寫(xiě)少的特征,所以我們使用redis進(jìn)行緩存沉迹。
第3級(jí):支付配置信息睦疫;這些數(shù)據(jù)和用戶無(wú)關(guān),具有數(shù)據(jù)量小鞭呕,頻繁讀蛤育,幾乎不修改的特征,所以我們使用本地內(nèi)存進(jìn)行緩存葫松。
使用本地內(nèi)存緩存有一個(gè)數(shù)據(jù)同步問(wèn)題瓦糕,因?yàn)榕渲眯畔⒕彺嬖趦?nèi)存中,而本地內(nèi)存無(wú)法感知到配置信息在數(shù)據(jù)庫(kù)的修改腋么,這樣會(huì)造成數(shù)據(jù)庫(kù)中數(shù)據(jù)和本地內(nèi)存中數(shù)據(jù)不一致的問(wèn)題咕娄。
為了解決此問(wèn)題,我們開(kāi)發(fā)了一個(gè)高可用的消息推送平臺(tái)珊擂,當(dāng)配置信息被修改時(shí)圣勒,我們可以使用推送平臺(tái),給支付系統(tǒng)所有的服務(wù)器推送配置文件更新消息摧扇,服務(wù)器收到消息會(huì)自動(dòng)更新配置信息圣贸,并給出成功反饋。
六. 粗細(xì)管道
黑客攻擊扛稽,前端重試等一些原因會(huì)造成請(qǐng)求量的暴漲吁峻,如果我們的服務(wù)被激增的請(qǐng)求給一波打死,想要重新恢復(fù)庇绽,就是一件非常痛苦和繁瑣的過(guò)程锡搜。
舉個(gè)簡(jiǎn)單的例子,我們目前訂單的處理能力是平均10萬(wàn)下單每秒瞧掺,峰值14萬(wàn)下單每秒,如果同一秒鐘有100萬(wàn)個(gè)下單請(qǐng)求進(jìn)入支付系統(tǒng)凡傅,毫無(wú)疑問(wèn)我們的整個(gè)支付系統(tǒng)就會(huì)崩潰辟狈,后續(xù)源源不斷的請(qǐng)求會(huì)讓我們的服務(wù)集群根本啟動(dòng)不起來(lái),唯一的辦法只能是切斷所有流量,重啟整個(gè)集群哼转,再慢慢導(dǎo)入流量明未。
我們?cè)趯?duì)外的web服務(wù)器上加一層“粗細(xì)管道”,就能很好的解決上面的問(wèn)題壹蔓。
下面是粗細(xì)管道簡(jiǎn)單的結(jié)構(gòu)圖:
請(qǐng)看上面的結(jié)構(gòu)圖趟妥,http請(qǐng)求在進(jìn)入web集群前,會(huì)先經(jīng)過(guò)一層粗細(xì)管道佣蓉。入口端是粗口披摄,我們?cè)O(shè)置最大能支持100萬(wàn)請(qǐng)求每秒,多余的請(qǐng)求會(huì)被直接拋棄掉勇凭。出口端是細(xì)口疚膊,我們?cè)O(shè)置給web集群10萬(wàn)請(qǐng)求每秒。剩余的90萬(wàn)請(qǐng)求會(huì)在粗細(xì)管道中排隊(duì)虾标,等待web集群處理完老的請(qǐng)求后寓盗,才會(huì)有新的請(qǐng)求從管道中出來(lái),給web集群處理璧函。這樣web集群處理的請(qǐng)求數(shù)每秒永遠(yuǎn)不會(huì)超過(guò)10萬(wàn)原押,在這個(gè)負(fù)載下,集群中的各個(gè)服務(wù)都會(huì)高校運(yùn)轉(zhuǎn)分歇,整個(gè)集群也不會(huì)因?yàn)楸┰龅恼?qǐng)求而停止服務(wù)哥遮。
如何實(shí)現(xiàn)粗細(xì)管道?nginx商業(yè)版中已經(jīng)有了支持美澳,相關(guān)資料請(qǐng)搜索
nginx max_conns销部,需要注意的是max_conns是活躍連接數(shù),具體設(shè)置除了需要確定最大TPS外制跟,還需確定平均響應(yīng)時(shí)間舅桩。
nginx相關(guān):http://nginx.org/en/docs/http/ngx_http_upstream_module.html