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