對于蘇寧易購主站而言,正常的用戶購物流程囊括選品、下單、庫存扣減、付款、訂單狀態(tài)更新、物流履約等。但是在電商業(yè)務(wù)中往往會涉及到對某些熱點(diǎn)商品的秒殺場景。相比于正常購物流程,秒殺場景具有時效性高、并發(fā)量大、瞬時業(yè)務(wù)量極高的業(yè)務(wù)特性,往往會出現(xiàn)顯著的分布式一致性問題。正常的業(yè)務(wù)系統(tǒng)不能很好地應(yīng)對瞬時高并發(fā)的業(yè)務(wù)需求,因此就需要針對于秒殺場景進(jìn)行相應(yīng)的架構(gòu)優(yōu)化,抑或是設(shè)計專門用于秒殺的中臺業(yè)務(wù)系統(tǒng)。
就秒殺業(yè)務(wù)而言,系統(tǒng)在瞬時會達(dá)到極高的并發(fā)量,如果與其它業(yè)務(wù)耦合,那么勢必會對其它業(yè)務(wù)造成風(fēng)險,因此基于安全性考慮和業(yè)務(wù)隔離原則,秒殺系統(tǒng)在設(shè)計上應(yīng)該與其它系統(tǒng)充分解耦,單獨(dú)部署。本文將討論在蘇寧現(xiàn)有的技術(shù)架構(gòu)和中臺組件的基礎(chǔ)上,如何去實現(xiàn)一個通用型秒殺業(yè)務(wù)中臺。
1-系統(tǒng)前端與負(fù)載層設(shè)計
圖一:前端與負(fù)載層設(shè)計
鑒于秒殺業(yè)務(wù)本身的高并發(fā)特性,對用戶請求進(jìn)行前端分流是必不可少的一步。在系統(tǒng)上游就對部分用戶請求進(jìn)行處理,可以避免海量請求對后端服務(wù)器產(chǎn)生過大壓力。因為用戶往往在秒殺前幾分鐘就開始點(diǎn)擊下單按鈕,因此在秒殺開始前可以使用靜態(tài)資源頁面,用戶請求由 CDN 直接響應(yīng),不必到達(dá)后端服務(wù)器。
此外,由于秒殺業(yè)務(wù)的高時效性特征,下單窗口基本集中在秒殺開始后的幾秒鐘之內(nèi)。因此我們可以在秒殺前某個時間點(diǎn)再將下單 URL 發(fā)送給前端。為了防止有人提前拿到下單 URL 進(jìn)入支付流程,可以在 URL 中加入服務(wù)端生成的隨機(jī)字符串,或者對下單請求進(jìn)行時間校驗,單就性能而言,前一種方案校驗邏輯更少,性能更優(yōu)。
在秒殺開始前,需要在商品秒殺頁顯示活動開始倒計時,其一般情況下直接調(diào)用用戶本地時鐘,因此就可能存在客戶端與服務(wù)端時鐘不一致的情況。因此在服務(wù)端需要提供定期授時接口將服務(wù)端時鐘同步給客戶端,為了節(jié)省帶寬可以將時間戳信息優(yōu)化壓縮為盡可能短的 JSON 格式,去除掉不必要的信息,減輕網(wǎng)絡(luò)帶寬壓力。
參與秒殺活動的商品一般數(shù)量稀少,注定只有少數(shù)用戶能夠進(jìn)入下單支付流程,因此可以在負(fù)載層進(jìn)行相應(yīng)控制。下單接口可以在蘇寧應(yīng)用防火墻配置流量控制,當(dāng)下單請求超過閥值后熔斷下單接口。而對于那些被應(yīng)用防火墻放行的下單請求,由 Ngnix 集群將流量均勻負(fù)載到后端應(yīng)用服務(wù)器。在服務(wù)器內(nèi)存中可以定義一個請求計數(shù)器,當(dāng)某臺服務(wù)器受理的下單請求超過閥值后,則該服務(wù)器不再受理用戶的下單信息,直接返回給用戶“活動已結(jié)束”頁面。
2-系統(tǒng)服務(wù)端設(shè)計
(1)系統(tǒng)服務(wù)端縱向拆分
圖二:系統(tǒng)服務(wù)端縱向拆分
秒殺系統(tǒng)在縱向架構(gòu)層面將主要分為三大模塊:web 模塊、admin 模塊和 task 模塊。其中 web 和 admin 模塊為了兼容獨(dú)占型業(yè)務(wù)將會包含一個接口路由子模塊用于接口級路由策略控制,三大模塊將分別部署在不同的 JBoss 集群上,通過分布式遠(yuǎn)程調(diào)用框架協(xié)同工作。
web 層:前臺業(yè)務(wù)模塊,該模塊主要用于處理用戶請求,這一模塊承擔(dān)最關(guān)鍵也是載荷最重的業(yè)務(wù),因此必須對這一模塊進(jìn)行單獨(dú)優(yōu)化,除了服務(wù)器橫向擴(kuò)容外,前臺模塊在系統(tǒng)部署層面將會分為兩個實例,用于展示鏈路和交易鏈路的業(yè)務(wù)分流。
admin 層:后臺業(yè)務(wù)模塊,本模塊主要用于運(yùn)維管理人員的日常數(shù)據(jù)維護(hù),新增和管理秒殺活動的報名信息、商品信息、活動信息等。
task 層:中臺定時任務(wù)模塊,本模塊主要負(fù)責(zé)處理來自統(tǒng)一調(diào)度平臺的定時任務(wù)調(diào)度請求,如定時向前端授時,處理過期的活動,商品數(shù)據(jù)等。為便于集中管理,授時任務(wù)每分鐘執(zhí)行一次,對于需要向前端授時的活動,將單獨(dú)存表,每分鐘掃描需要執(zhí)行授時任務(wù)的活動信息并下發(fā)時間戳。
(2)系統(tǒng)服務(wù)端橫向拆分
圖三:系統(tǒng)服務(wù)端橫向拆分
網(wǎng)絡(luò)層:鑒于秒殺系統(tǒng)本身的高并發(fā)特性,在架構(gòu)設(shè)計上要盡可能踐行前端處理的原則,能在前端響應(yīng)的請求,就絕不放在后端。在秒殺開始前,CDN 直接響應(yīng)靜態(tài)頁面給用戶,為服務(wù)器分流大部分流量。在靜態(tài)資源緩存時間設(shè)計上要精準(zhǔn)靈活,當(dāng)秒殺開始前幾秒向服務(wù)器放行用戶請求。如果 CDN 本身存在性能瓶頸或者后端服務(wù)器業(yè)務(wù)處理能力有限的話還可以在負(fù)載層加一套 Varish 集群作為二級緩存,進(jìn)一步為后端分流。
負(fù)載層:到達(dá)蘇寧內(nèi)網(wǎng)的請求,首先經(jīng)過蘇寧應(yīng)用防火墻。防火墻將會作為到應(yīng)用服務(wù)器的第二道防線,承擔(dān)過濾惡意請求,黃牛用戶,黑客攻擊的任務(wù)。對于下單接口,應(yīng)用防火墻應(yīng)當(dāng)設(shè)置合理的流控策略。對于同一 IP 的用戶,最多執(zhí)行 10 次下單操作,超過 10 次的請求將直接攔截不再轉(zhuǎn)發(fā)到后端。同時防火墻還應(yīng)當(dāng)在宏觀層面對流量閥值進(jìn)行控制,TPS 超過閥值后進(jìn)行接口級熔斷,防止流量過高引發(fā)應(yīng)用服務(wù)器宕機(jī)。
應(yīng)用層:在 CDN 和防火墻兩層防線的加持下,最終到達(dá)應(yīng)用服務(wù)器的請求應(yīng)當(dāng)只剩占比較小的一部分。有使于龐大的用戶基數(shù),這部分流量仍然不容小覷。除了校驗,下單,支付外,還會有一部分商品信息相關(guān)的狀態(tài)查詢請求。因為前端頁面已經(jīng)盡可能實現(xiàn)了靜態(tài)化,所以只需要對返回前端的商品狀態(tài)數(shù)據(jù)格式進(jìn)行合理的壓縮,并在前端予以更新即可。為了進(jìn)一步解除業(yè)務(wù)耦合,可以對展示鏈路和交易鏈路采用分集群部署,按域名分流的方案,進(jìn)一步按業(yè)務(wù)分導(dǎo)流量,提高系統(tǒng)安全性和可用性。
數(shù)據(jù)層:為了有效減輕數(shù)據(jù)庫壓力,在數(shù)據(jù)層設(shè)計上將會采用雙機(jī)房數(shù)據(jù)互補(bǔ)的獨(dú)占型數(shù)據(jù)庫設(shè)計,這一部分將在后文中詳述。
(3)系統(tǒng)緩存設(shè)計與庫存扣減方案
就秒殺業(yè)務(wù)場景而言,因為存在下單校驗等前置流程,這就注定大部分用戶都走不到支付這一步。該部分用戶對數(shù)據(jù)庫都只是發(fā)送讀請求,而只有少部分下單成功的用戶才會對數(shù)據(jù)庫產(chǎn)生寫請求。因此將大部分讀請求放在緩存中處理將使系統(tǒng)性能顯著提升。
圖四:系統(tǒng)緩存設(shè)計
以庫存為例,秒殺場景中庫存校驗和庫存扣減必然在短時間內(nèi)產(chǎn)生極高的并發(fā)量,庫存緩存的設(shè)計將對系統(tǒng)性能產(chǎn)生即為重要的影響。秒殺活動開始前,運(yùn)營會在后臺維護(hù)商品的總庫存,剩余庫存和可鎖庫存信息,同時將信息提前預(yù)熱到 Redis 緩存中。當(dāng)用戶通過支付校驗并進(jìn)入下單流程后,系統(tǒng)會首先操作 Redis 中的可鎖庫存數(shù),同時在 DB 中寫入一條鎖庫存記錄。當(dāng)用戶支付成功后,扣減 Redis 中的剩余庫存,同時刪除 DB 中的鎖庫存記錄。因為在這一過程中主要數(shù)據(jù)更新發(fā)生在 Redis 中,因此需要將 Redis 中的數(shù)據(jù)定時同步給 DB。系統(tǒng)管理員可以根據(jù)業(yè)務(wù)需求和實際的系統(tǒng)性能對數(shù)據(jù)同步周期進(jìn)行配置。對 DB 和 Redis 的操作將放置在 TCC 分布式一致性框架中,當(dāng)某一步驟失敗時同時回滾 DB 和 Redis,避免數(shù)據(jù)庫和緩存出現(xiàn)數(shù)據(jù)不一致的情形。
即便將熱點(diǎn)數(shù)據(jù)操作都放置在 Redis 中,仍然有可能產(chǎn)生活動超賣的情形。比如某商品只剩一件時,同時有多個用戶提交下單請求。因為庫存剩余一件,因此每個用戶都通過庫存校驗并進(jìn)入下單流程,進(jìn)而引發(fā)商品超售,對此我們可以采用以下幾種解決方案:
圖五:Redis 悲觀鎖機(jī)制下的庫存扣減方案
方案一,采用 Redis 的悲觀鎖機(jī)制,當(dāng)一個線程訪問庫存數(shù)據(jù)時拒絕其它線程的訪問,這樣顯然可以解決多個用戶同時通過下單引發(fā)超售的問題。但是這一方案會顯著拖累系統(tǒng)性能,尤其是秒殺場景下并發(fā)量極高,如果每個用戶都只能等到其他用戶鎖釋放之后才能訪問庫存數(shù)據(jù),那么有一部分用戶可能永遠(yuǎn)都沒有機(jī)會進(jìn)入下單流程。
圖六:FIFO 隊列機(jī)制下的庫存扣減方案
方案二,采用 FIFO 隊列進(jìn)行多線程轉(zhuǎn)單線程處理,用一個先進(jìn)先出的隊列使用戶請求實現(xiàn)序列化,這就保證每個用戶請求都將基于先后順序到達(dá) Redis,進(jìn)而有效避免了某些用戶永遠(yuǎn)訪問不到庫存數(shù)據(jù)的情況。不過這一方案也存在弊端,因為這一中間隊列顯然會是一個入多出少的隊列,那么如果隊列本身內(nèi)存冗余不夠,那么海量用戶請求有可能瞬間將隊列擠爆,而中間隊列所需要的資源也將進(jìn)一步提升系統(tǒng)開銷。
圖七:Redis 樂觀鎖機(jī)制下的庫存扣減方案
方案三,采用 Redis 的樂觀鎖機(jī)制。樂觀鎖與悲觀鎖的區(qū)別在于,當(dāng)多個線程同時訪問某個資源時,樂觀鎖并不會阻滯未得到鎖的線程對資源的訪問。但是更新數(shù)據(jù)是,只有版本號符合的請求才能夠成功更新緩存數(shù)據(jù)。一言以蔽之,樂觀鎖是一種只限制更新,不限制查詢的加鎖機(jī)制。我們此處以雙線程并發(fā)場景為例:
當(dāng)庫存為 1 時,兩個用戶同時進(jìn)入庫存校驗流程。此時用戶 A 先訪問庫存數(shù)據(jù),并拿到庫存為 1,當(dāng)前版本號為 10,通過校驗后,用戶 A 進(jìn)入下單流程。此時用戶 B 訪問庫存數(shù)據(jù),庫存為 1,當(dāng)前版本號為 10,并進(jìn)入下單流程。之后用戶 A 下單成功,庫存信息更新為 0,版本號置為 11。此時用戶 B 嘗試修改庫存信息,但拿到版本號信息為 11,版本不符合,放棄更新庫存,回滾相關(guān)操作,并向用戶返回秒殺結(jié)束頁面。這一機(jī)制將能夠很好實現(xiàn)庫存數(shù)據(jù)在高并發(fā)場景下的線程安全問題,有效規(guī)避商品超售的情況。雖然這一方案會增加 CPU 開銷,但是相較于前兩種方案,在整體設(shè)計上更為均衡,沒有明顯的短板,是最為適合的一種庫存緩存設(shè)計方案。
(4)系統(tǒng)數(shù)據(jù)庫設(shè)計
鑒于秒殺系統(tǒng)對安全性和可用性的要求,在數(shù)據(jù)層設(shè)計上要盡可能細(xì)化和深化,分割業(yè)務(wù)數(shù)據(jù),盡量避免一刀切的情況。因此在秒殺系統(tǒng)數(shù)據(jù)層將采用 8+1 型獨(dú)占數(shù)據(jù)庫設(shè)計。
圖八:系統(tǒng)數(shù)據(jù)庫設(shè)計
首先我們按照作用域?qū)I(yè)務(wù)數(shù)據(jù)切分為全局?jǐn)?shù)據(jù)和用戶數(shù)據(jù),全局作用的數(shù)據(jù),比如活動信息,商品信息,價格信息,所有用戶看到的都是一樣的。而用戶數(shù)據(jù)則是和用戶相關(guān)的差異性數(shù)據(jù),比如用戶個人的訂單記錄等,更具體的說就是帶有 memberId 字段信息的數(shù)據(jù)。在這一數(shù)據(jù)分類的基礎(chǔ)上,進(jìn)一步采用 8+1 型數(shù)據(jù)庫設(shè)計。所謂 8+1 指的是 8 個分庫組 +1 個單庫的設(shè)計,8 個分庫組只保存帶有 memberId 的用戶數(shù)據(jù),并通過 MyCat 中間件按照 memberId 取模分片,而一個單庫中只保存活動信息,商品信息等全局?jǐn)?shù)據(jù),8 個分庫組采用獨(dú)占型多活部署,而 1 個單庫采用競爭型多活部署,這一部分將在后文中詳細(xì)解釋。
1-系統(tǒng)多活部署方案
就秒殺業(yè)務(wù)而言,系統(tǒng)的安全性和可用性無疑是第一考量,因此多活部署幾乎是一個必然的選擇。蘇寧秒殺中臺系統(tǒng)采用同城雙機(jī)房部署方案,一方面可以對用戶請求持續(xù)分流,同時也可以規(guī)避單點(diǎn)部署策略在意外因素下整機(jī)房宕機(jī)的風(fēng)險,保證業(yè)務(wù)的持續(xù)可用性。
圖九:系統(tǒng)多活部署方案
在網(wǎng)絡(luò)層,CDN 首先對公網(wǎng)流量進(jìn)行初次劃撥,正常情況下每個機(jī)房負(fù)載 1/2 流量。
在負(fù)載層,對于 CDN 調(diào)撥過來的公網(wǎng)流量,經(jīng)過高可用 VIP 到達(dá)防火墻后,防火墻按分片策略二次切分。當(dāng) CDN 與防火墻的流量切分策略一致時,防火墻不會進(jìn)行額外的流量劃撥(不帶分片路由信息的請求除外)。當(dāng) CDN 和防火墻切分策略不一致時,防火墻會進(jìn)行補(bǔ)償性撥分,最終實際的流量調(diào)撥情況將遵循防火墻層面的撥分策略。
防火墻流量調(diào)度以系統(tǒng)為基本單元,不同系統(tǒng)可根據(jù)實際情況配置分撥策略。除了對 CDN 初次調(diào)撥進(jìn)行補(bǔ)償外,防火墻還可以承擔(dān)在 CDN 失效后的替代方案,保證不會因為 CDN 失效而導(dǎo)致單機(jī)房負(fù)載壓力過大。
在應(yīng)用層,所有 HTTP 請求,經(jīng)由接口路由子模塊封裝后,進(jìn)一步轉(zhuǎn)發(fā)到服務(wù)層和數(shù)據(jù)層。根據(jù)接口作用域的不同,采用主機(jī)房路由和分片路由的復(fù)合型策略來精準(zhǔn)調(diào)度請求。對于涉及到全局?jǐn)?shù)據(jù)的請求,比如活動新增,商品報名,庫存查詢,庫存更新等,采用主機(jī)房路由策略路。而對于用戶數(shù)據(jù)相關(guān)請求,則采取分片路由策略調(diào)撥到對應(yīng)的獨(dú)占庫。蘇寧分布式調(diào)用中臺支持根據(jù)接口參數(shù)切分路由,這一規(guī)則可根據(jù)獨(dú)占庫設(shè)置自行定制。
在數(shù)據(jù)層面,采用與應(yīng)用層一致的獨(dú)占型加競爭型復(fù)合部署策略,所有全局?jǐn)?shù)據(jù)的讀寫請求均路由到機(jī)房 A 的單庫,并拓?fù)鋸?fù)制給機(jī)房 B。而用戶數(shù)據(jù)則采用交叉互備的分庫設(shè)計,機(jī)房 A 編號 1,2,3,4 的分庫為主庫,編號 5,6,7,8 的庫為從庫,機(jī)房 B 反之,數(shù)據(jù)通過數(shù)據(jù)庫服務(wù)中臺進(jìn)行拓?fù)鋸?fù)制。
2-單機(jī)房宕機(jī)場景下的降級方案
當(dāng)發(fā)生單機(jī)房故障時(以機(jī)房 A 宕機(jī)為例):
圖十:單機(jī)房宕機(jī)場景下的降級方案
在網(wǎng)絡(luò)層,由 CDN 統(tǒng)一控制將所有回源請求分撥到機(jī)房 B。
在負(fù)載層,此時機(jī)房 A 已經(jīng)沒有來自公網(wǎng)的請求,但是可能仍然會有部分內(nèi)網(wǎng)請求,因此需要修改內(nèi)網(wǎng) DNS 解析值,完成內(nèi)網(wǎng)流量的調(diào)撥。同時需要在應(yīng)用防火墻層面切換流量分撥策略,防止仍有流量被防火墻分撥到機(jī)房 A。
在應(yīng)用層面,需要將分布式調(diào)用中臺的主機(jī)房策略修改為機(jī)房 B,同時將分片路由策略修改為“機(jī)房 A 流量:機(jī)房 B 流量”為“0:1”,將所有請求調(diào)度到機(jī)房 B。
在數(shù)據(jù)層面,需要將機(jī)房 B 單庫和編號 1,2,3,4 的分庫置為主庫,修改拓?fù)鋸?fù)制關(guān)系。
至此,完成了機(jī)房 A 宕機(jī)情況下的降級,機(jī)房 B 將負(fù)載所有業(yè)務(wù)請求。
就秒殺系統(tǒng)的設(shè)計而言,關(guān)鍵是要緊抓幾條設(shè)計原則,一是前端過濾,將大部分請求截流在上游緩存,減輕服務(wù)端壓力。二是高并發(fā)安全,在瞬時極高并發(fā)的情況下既要保證系統(tǒng)可用性,又要避免出現(xiàn)超售場景等業(yè)務(wù)異常。三是多活容災(zāi),冗余部署,在系統(tǒng)風(fēng)險較大的情況下要盡可能異地分流,均攤風(fēng)險,提高系統(tǒng)抗災(zāi)容災(zāi)能力。只要抓住這幾點(diǎn),那么就掌握了秒殺系統(tǒng)設(shè)計的核心奧義。
瑪氏中國|2025年度冠軍寵物進(jìn)口貨運(yùn)代理服務(wù)遴選
2866 閱讀知名網(wǎng)絡(luò)貨運(yùn)平臺去年營收397.97億,凈利潤實現(xiàn)1.4億元
1110 閱讀多條航線運(yùn)價下跌!美西暴跌超三成!
941 閱讀即時零售行業(yè)深度報告:即時零售萬億高成長賽道,平臺模式三國殺開拓長期增量
875 閱讀獲菜鳥1.7億美元投資,年營收12.5億美元,這家跨境物流巨頭即將上市
879 閱讀極兔云倉發(fā)展迅猛,“618”服務(wù)再突破
894 閱讀倉庫管理升級:需要打破一些慣性思維
812 閱讀物流企業(yè)如何判斷“大客戶業(yè)務(wù)機(jī)會”是不是靠譜
844 閱讀中國綠證價格持續(xù)暴漲,即將超過10元/張
777 閱讀劉強(qiáng)東分享會:京東做餐飲酒旅都是為供應(yīng)鏈
752 閱讀