自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

看完這篇,你也能設(shè)計一個高性能的“秒殺”系統(tǒng)

新聞 架構(gòu)
從架構(gòu)視角來看,秒殺系統(tǒng)本質(zhì)是一個高性能、高一致、高可用的三高系統(tǒng)。而打造并維護(hù)一個超大流量的秒殺系統(tǒng)需要進(jìn)行哪些關(guān)注,就是本文討論的話題。

前言

秒殺大家都不陌生。自2011年首次出現(xiàn)以來,無論是雙十一購物還是 12306 搶票,秒殺場景已隨處可見。簡單來說,秒殺就是在同一時刻大量請求爭搶購買同一商品并完成交易的過程。

從架構(gòu)視角來看,秒殺系統(tǒng)本質(zhì)是一個高性能、高一致、高可用的三高系統(tǒng)。而打造并維護(hù)一個超大流量的秒殺系統(tǒng)需要進(jìn)行哪些關(guān)注,就是本文討論的話題。

整體思考

首先從高維度出發(fā),整體思考問題。秒殺無外乎解決兩個核心問題,一是并發(fā)讀,一是并發(fā)寫,對應(yīng)到架構(gòu)設(shè)計,就是高可用、一致性和高性能的要求。關(guān)于秒殺系統(tǒng)的設(shè)計思考,本文即基于此 3 層依次推進(jìn),簡述如下:

  • 高性能 秒殺涉及高讀和高寫的支持,如何支撐高并發(fā),如何抵抗高IOPS?核心優(yōu)化理念其實是類似的:高讀就盡量”少讀”或”讀少”,高寫就數(shù)據(jù)拆分。本文將從動靜分離、熱點優(yōu)化以及服務(wù)端性能優(yōu)化 3 個方面展開。
  • 一致性 秒殺的核心關(guān)注是商品庫存,有限的商品在同一時間被多個請求同時扣減,而且要保證準(zhǔn)確性,顯而易見是一個難題。如何做到既不多又不少?本文將從業(yè)界通用的幾種減庫存方案切入,討論一致性設(shè)計的核心邏輯。
  • 高可用 大型分布式系統(tǒng)在實際運(yùn)行過程中面對的工況是非常復(fù)雜的,業(yè)務(wù)流量的突增、依賴服務(wù)的不穩(wěn)定、應(yīng)用自身的瓶頸、物理資源的損壞等方方面面都會對系統(tǒng)的運(yùn)行帶來大大小小的的沖擊。如何保障應(yīng)用在復(fù)雜工況環(huán)境下還能高效穩(wěn)定運(yùn)行,如何預(yù)防和面對突發(fā)問題,系統(tǒng)設(shè)計時應(yīng)該從哪些方面著手?本文將從架構(gòu)落地的全景視角進(jìn)行關(guān)注思考。

高性能

1 動靜分離

大家可能會注意到,秒殺過程中你是不需要刷新整個頁面的,只有時間在不停跳動。這是因為一般都會對大流量的秒殺系統(tǒng)做系統(tǒng)的靜態(tài)化改造,即數(shù)據(jù)意義上的動靜分離。動靜分離三步走:1、數(shù)據(jù)拆分;2、靜態(tài)緩存;3、數(shù)據(jù)整合。

1.1 數(shù)據(jù)拆分

動靜分離的首要目的是將動態(tài)頁面改造成適合緩存的靜態(tài)頁面。因此第一步就是分離出動態(tài)數(shù)據(jù),主要從以下 2 個方面進(jìn)行:

  1. 用戶 用戶身份信息包括登錄狀態(tài)以及登錄畫像等,相關(guān)要素可以單獨(dú)拆分出來,通過動態(tài)請求進(jìn)行獲??;與之相關(guān)的廣平推薦,如用戶偏好、地域偏好等,同樣可以通過異步方式進(jìn)行加載。

  2. 時間 秒殺時間是由服務(wù)端統(tǒng)一管控的,可以通過動態(tài)請求進(jìn)行獲取。

1.2 靜態(tài)緩存

分離出動靜態(tài)數(shù)據(jù)之后,第二步就是將靜態(tài)數(shù)據(jù)進(jìn)行合理的緩存,由此衍生出兩個問題:1、怎么緩存;2、哪里緩存

1.2.1 怎么緩存

靜態(tài)化改造的一個特點是直接緩存整個 HTTP 連接而不是僅僅緩存靜態(tài)數(shù)據(jù),如此一來,Web 代理服務(wù)器根據(jù)請求 URL,可以直接取出對應(yīng)的響應(yīng)體然后直接返回,響應(yīng)過程無需重組 HTTP 協(xié)議,也無需解析 HTTP 請求頭。而作為緩存鍵,URL唯一化是必不可少的,只是對于商品系統(tǒng),URL 天然是可以基于商品 ID 來進(jìn)行唯一標(biāo)識的,比如淘寶的 https://item.taobao.com/item....。

1.2.2 哪里緩存

靜態(tài)數(shù)據(jù)緩存到哪里呢?可以有三種方式:1、瀏覽器;2、CDN ;3、服務(wù)端。

瀏覽器當(dāng)然是第一選擇,但用戶的瀏覽器是不可控的,主要體現(xiàn)在如果用戶不主動刷新,系統(tǒng)很難主動地把消息推送給用戶(注意,當(dāng)討論靜態(tài)數(shù)據(jù)時,潛臺詞是 “相對不變”,言外之意是 “可能會變”),如此可能會導(dǎo)致用戶端在很長一段時間內(nèi)看到的信息都是錯誤的。對于秒殺系統(tǒng),保證緩存可以在秒級時間內(nèi)失效是不可或缺的。

服務(wù)端主要進(jìn)行動態(tài)邏輯計算及加載,本身并不擅長處理大量連接,每個連接消耗內(nèi)存較多,同時 Servlet 容器解析 HTTP 較慢,容易侵占邏輯計算資源;另外,靜態(tài)數(shù)據(jù)下沉至此也會拉長請求路徑。

因此通常將靜態(tài)數(shù)據(jù)緩存在 CDN,其本身更擅長處理大并發(fā)的靜態(tài)文件請求,既可以做到主動失效,又離用戶盡可能近,同時規(guī)避 Java 語言層面的弱點。需要注意的是,上 CDN 有以下幾個問題需要解決:

  1. 失效問題。任何一個緩存都應(yīng)該是有時效的,尤其對于一個秒殺場景。所以,系統(tǒng)需要保證全國各地的 CDN 在秒級時間內(nèi)失效掉緩存信息,這實際對 CDN 的失效系統(tǒng)要求是很高的

  2. 命中率問題。高命中是緩存系統(tǒng)最為核心的性能要求,不然緩存就失去了意義。如果將數(shù)據(jù)放到全國各地的 CDN ,勢必會導(dǎo)致請求命中同一個緩存的可能性降低,那么命中率就成為一個問題

因此,將數(shù)據(jù)放到全國所有的 CDN 節(jié)點是不太現(xiàn)實的,失效問題、命中率問題都會面臨比較大的挑戰(zhàn)。更為可行的做法是選擇若干 CDN 節(jié)點進(jìn)行靜態(tài)化改造,節(jié)點的選取通常需要滿足以下幾個條件:

  1. 臨近訪問量集中的地區(qū)

  2. 距離主站較遠(yuǎn)的地區(qū)

  3. 節(jié)點與主站間網(wǎng)絡(luò)質(zhì)量良好的地區(qū) 

基于以上因素,選擇 CDN 的二級緩存比較合適,因為二級緩存數(shù)量偏少,容量也更大,訪問量相對集中,這樣就可以較好解決緩存的失效問題以及命中率問題,是當(dāng)前比較理想的一種 CDN 化方案。部署方式如下圖所示:

 çœ‹å®Œè¿™ç¯‡ï¼Œä½ ä¹Ÿèƒ½è®¾è®¡ä¸€ä¸ªé«˜æ€§èƒ½çš„“秒杀”系统

1.3 數(shù)據(jù)整合

分離出動靜態(tài)數(shù)據(jù)之后,前端如何組織數(shù)據(jù)頁就是一個新的問題,主要在于動態(tài)數(shù)據(jù)的加載處理,通常有兩種方案:ESI(Edge Side Includes)方案和 CSI(Client Side Include)方案。

  1. ESI 方案:Web 代理服務(wù)器上請求動態(tài)數(shù)據(jù),并將動態(tài)數(shù)據(jù)插入到靜態(tài)頁面中,用戶看到頁面時已經(jīng)是一個完整的頁面。這種方式對服務(wù)端性能要求高,但用戶體驗較好

  2. CSI 方案:Web 代理服務(wù)器上只返回靜態(tài)頁面,前端單獨(dú)發(fā)起一個異步 JS 請求動態(tài)數(shù)據(jù)。這種方式對服務(wù)端性能友好,但用戶體驗稍差

1.4 小結(jié)

動靜分離對于性能的提升,抽象起來只有兩點,一是數(shù)據(jù)要盡量少,以便減少沒必要的請求,二是路徑要盡量短,以便提高單次請求的效率。具體方法其實就是基于這個大方向進(jìn)行的。

2 熱點優(yōu)化

熱點分為熱點操作和熱點數(shù)據(jù),以下分開進(jìn)行討論。

2.1 熱點操作

零點刷新、零點下單、零點添加購物車等都屬于熱點操作。熱點操作是用戶的行為,不好改變,但可以做一些限制保護(hù),比如用戶頻繁刷新頁面時進(jìn)行提示阻斷。

2.2 熱點數(shù)據(jù)

熱點數(shù)據(jù)的處理三步走,一是熱點識別,二是熱點隔離,三是熱點優(yōu)化。

2.2.1 熱點識別

熱點數(shù)據(jù)分為靜態(tài)熱點和動態(tài)熱點,具體如下:

  1. 靜態(tài)熱點:能夠提前預(yù)測的熱點數(shù)據(jù)。大促前夕,可以根據(jù)大促的行業(yè)特點、活動商家等緯度信息分析出熱點商品,或者通過賣家報名的方式提前篩選;另外,還可以通過技術(shù)手段提前預(yù)測,例如對買家每天訪問的商品進(jìn)行大數(shù)據(jù)計算,然后統(tǒng)計出 TOP N 的商品,即可視為熱點商品

  2. 動態(tài)熱點:無法提前預(yù)測的熱點數(shù)據(jù)。冷熱數(shù)據(jù)往往是隨實際業(yè)務(wù)場景發(fā)生交替變化的,尤其是如今直播賣貨模式的興起——帶貨商臨時做一個廣告,就有可能導(dǎo)致一件商品在短時間內(nèi)被大量購買。由于此類商品日常訪問較少,即使在緩存系統(tǒng)中一段時間后也會被逐出或過期掉,甚至在db中也是冷數(shù)據(jù)。瞬時流量的涌入,往往導(dǎo)致緩存被擊穿,請求直接到達(dá)DB,引發(fā)DB壓力過大

因此秒殺系統(tǒng)需要實現(xiàn)熱點數(shù)據(jù)的動態(tài)發(fā)現(xiàn)能力,一個常見的實現(xiàn)思路是:

  1. 異步采集交易鏈路各個環(huán)節(jié)的熱點 Key 信息,如 Nginx采集訪問URL或 Agent 采集熱點日志(一些中間件本身已具備熱點發(fā)現(xiàn)能力),提前識別潛在的熱點數(shù)據(jù)

  2. 聚合分析熱點數(shù)據(jù),達(dá)到一定規(guī)則的熱點數(shù)據(jù),通過訂閱分發(fā)推送到鏈路系統(tǒng),各系統(tǒng)根據(jù)自身需求決定如何處理熱點數(shù)據(jù),或限流或緩存,從而實現(xiàn)熱點保護(hù)

需要注意的是:

  1. 熱點數(shù)據(jù)采集最好采用異步方式,一方面不會影響業(yè)務(wù)的核心交易鏈路,一方面可以保證采集方式的通用性

  2. 熱點發(fā)現(xiàn)最好做到秒級實時,這樣動態(tài)發(fā)現(xiàn)才有意義,實際上也是對核心節(jié)點的數(shù)據(jù)采集和分析能力提出了較高的要求

2.2.2 熱點隔離

熱點數(shù)據(jù)識別出來之后,第一原則就是將熱點數(shù)據(jù)隔離出來,不要讓 1% 影響到另外的 99%,可以基于以下幾個層次實現(xiàn)熱點隔離:

  1. 業(yè)務(wù)隔離。秒殺作為一種營銷活動,賣家需要單獨(dú)報名,從技術(shù)上來說,系統(tǒng)可以提前對已知熱點做緩存預(yù)熱

  2. 系統(tǒng)隔離。系統(tǒng)隔離是運(yùn)行時隔離,通過分組部署和另外 99% 進(jìn)行分離,另外秒殺也可以申請單獨(dú)的域名,入口層就讓請求落到不同的集群中

  3. 數(shù)據(jù)隔離。秒殺數(shù)據(jù)作為熱點數(shù)據(jù),可以啟用單獨(dú)的緩存集群或者DB服務(wù)組,從而更好的實現(xiàn)橫向或縱向能力擴(kuò)展

當(dāng)然,實現(xiàn)隔離還有很多種辦法。比如,可以按照用戶來區(qū)分,為不同的用戶分配不同的 Cookie,入口層路由到不同的服務(wù)接口中;再比如,域名保持一致,但后端調(diào)用不同的服務(wù)接口;又或者在數(shù)據(jù)層給數(shù)據(jù)打標(biāo)進(jìn)行區(qū)分等等,這些措施的目的都是把已經(jīng)識別的熱點請求和普通請求區(qū)分開來。

2.2.3 熱點優(yōu)化

熱點數(shù)據(jù)隔離之后,也就方便對這 1% 的請求做針對性的優(yōu)化,方式無外乎兩種:

  1. 緩存:熱點緩存是最為有效的辦法。如果熱點數(shù)據(jù)做了動靜分離,那么可以長期緩存靜態(tài)數(shù)據(jù)

  2. 限流:流量限制更多是一種保護(hù)機(jī)制。需要注意的是,各服務(wù)要時刻關(guān)注請求是否觸發(fā)限流并及時進(jìn)行review

2.2.4 小結(jié)

數(shù)據(jù)的熱點優(yōu)化與動靜分離是不一樣的,熱點優(yōu)化是基于二八原則對數(shù)據(jù)進(jìn)行了縱向拆分,以便進(jìn)行針對性地處理。熱點識別和隔離不僅對“秒殺”這個場景有意義,對其他的高性能分布式系統(tǒng)也非常有參考價值。

3 系統(tǒng)優(yōu)化

對于一個軟件系統(tǒng),提高性能可以有很多種手段,如提升硬件水平、調(diào)優(yōu)JVM 性能,這里主要關(guān)注代碼層面的性能優(yōu)化——

  1. 減少序列化:減少 Java 中的序列化操作可以很好的提升系統(tǒng)性能。序列化大部分是在 RPC 階段發(fā)生,因此應(yīng)該盡量減少 RPC 調(diào)用,一種可行的方案是將多個關(guān)聯(lián)性較強(qiáng)的應(yīng)用進(jìn)行 “合并部署”,從而減少不同應(yīng)用之間的 RPC 調(diào)用(微服務(wù)設(shè)計規(guī)范)

  2. 直接輸出流數(shù)據(jù):只要涉及字符串的I/O操作,無論是磁盤 I/O 還是網(wǎng)絡(luò) I/O,都比較耗費(fèi) CPU 資源,因為字符需要轉(zhuǎn)換成字節(jié),而這個轉(zhuǎn)換又必須查表編碼。所以對于常用數(shù)據(jù),比如靜態(tài)字符串,推薦提前編碼成字節(jié)并緩存,具體到代碼層面就是通過 OutputStream() 類函數(shù)從而減少數(shù)據(jù)的編碼轉(zhuǎn)換;另外,熱點方法toString()不要直接調(diào)用ReflectionToString實現(xiàn),推薦直接硬編碼,并且只打印DO的基礎(chǔ)要素和核心要素

  3. 裁剪日志異常堆棧:無論是外部系統(tǒng)異常還是應(yīng)用本身異常,都會有堆棧打出,超大流量下,頻繁的輸出完整堆棧,只會加劇系統(tǒng)當(dāng)前負(fù)載??梢酝ㄟ^日志配置文件控制異常堆棧輸出的深度

  4. 去組件框架:極致優(yōu)化要求下,可以去掉一些組件框架,比如去掉傳統(tǒng)的 MVC 框架,直接使用 Servlet 處理請求。這樣可以繞過一大堆復(fù)雜且用處不大的處理邏輯,節(jié)省毫秒級的時間,當(dāng)然,需要合理評估你對框架的依賴程度

4 總結(jié)一下

性能優(yōu)化需要一個基準(zhǔn)值,所以系統(tǒng)還需要做好應(yīng)用基線,比如性能基線(何時性能突然下降)、成本基線(去年大促用了多少機(jī)器)、鏈路基線(核心流程發(fā)生了哪些變化),通過基線持續(xù)關(guān)注系統(tǒng)性能,促使系統(tǒng)在代碼層面持續(xù)提升編碼質(zhì)量、業(yè)務(wù)層面及時下掉不合理調(diào)用、架構(gòu)層面不斷優(yōu)化改進(jìn)。

一致性

秒殺系統(tǒng)中,庫存是個關(guān)鍵數(shù)據(jù),賣不出去是個問題,超賣更是個問題。秒殺場景下的一致性問題,主要就是庫存扣減的準(zhǔn)確性問題。

1 減庫存的方式

電商場景下的購買過程一般分為兩步:下單和付款。“提交訂單”即為下單,“支付訂單”即為付款?;诖嗽O(shè)定,減庫存一般有以下幾個方式:

  1. 下單減庫存。買家下單后,扣減商品庫存。下單減庫存是最簡單的減庫存方式,也是控制最為精確的一種

  2. 付款減庫存。買家下單后,并不立即扣減庫存,而是等到付款后才真正扣減庫存。但因為付款時才減庫存,如果并發(fā)比較高,可能出現(xiàn)買家下單后付不了款的情況,因為商品已經(jīng)被其他人買走了

  3. 預(yù)扣庫存。這種方式相對復(fù)雜一些,買家下單后,庫存為其保留一定的時間(如 15 分鐘),超過這段時間,庫存自動釋放,釋放后其他買家可以購買

能夠看到,減庫存方式是基于購物過程的多階段進(jìn)行劃分的,但無論是在下單階段還是付款階段,都會存在一些問題,下面進(jìn)行具體分析。

2 減庫存的問題

2.1 下單減庫存

優(yōu)勢:用戶體驗最好。下單減庫存是最簡單的減庫存方式,也是控制最精確的一種。下單時可以直接通過數(shù)據(jù)庫事務(wù)機(jī)制控制商品庫存,所以一定不會出現(xiàn)已下單卻付不了款的情況。

劣勢:可能賣不出去。正常情況下,買家下單后付款概率很高,所以不會有太大問題。但有一種場景例外,就是當(dāng)賣家參加某個促銷活動時,競爭對手通過惡意下單的方式將該商品全部下單,導(dǎo)致庫存清零,那么這就不能正常售賣了——要知道,惡意下單的人是不會真正付款的,這正是 “下單減庫存” 的不足之處。

2.2 付款減庫存

優(yōu)勢:一定實際售賣。“下單減庫存” 可能導(dǎo)致惡意下單,從而影響賣家的商品銷售, “付款減庫存” 由于需要付出真金白銀,可以有效避免。

劣勢:用戶體驗較差。用戶下單后,不一定會實際付款,假設(shè)有 100 件商品,就可能出現(xiàn) 200 人下單成功的情況,因為下單時不會減庫存,所以也就可能出現(xiàn)下單成功數(shù)遠(yuǎn)遠(yuǎn)超過真正庫存數(shù)的情況,這尤其會發(fā)生在大促的熱門商品上。如此一來就會導(dǎo)致很多買家下單成功后卻付不了款,購物體驗自然是比較差的。

2.3 預(yù)扣庫存

優(yōu)勢:緩解了以上兩種方式的問題。預(yù)扣庫存實際就是“下單減庫存”和 “付款減庫存”兩種方式的結(jié)合,將兩次操作進(jìn)行了前后關(guān)聯(lián),下單時預(yù)扣庫存,付款時釋放庫存。

劣勢:并沒有徹底解決以上問題。比如針對惡意下單的場景,雖然可以把有效付款時間設(shè)置為 10 分鐘,但惡意買家完全可以在 10 分鐘之后再次下單。

2.4 小結(jié)

減庫存的問題主要體現(xiàn)在用戶體驗和商業(yè)訴求兩方面,其本質(zhì)原因在于購物過程存在兩步甚至多步操作,在不同階段減庫存,容易存在被惡意利用的漏洞。

3 實際如何減庫存

業(yè)界最為常見的是預(yù)扣庫存。無論是外賣點餐還是電商購物,下單后一般都有個 “有效付款時間”,超過該時間訂單自動釋放,這就是典型的預(yù)扣庫存方案。但如上所述,預(yù)扣庫存還需要解決惡意下單的問題,保證商品賣的出去;另一方面,如何避免超賣,也是一個痛點。

  1. 賣的出去:

    惡意下單的解決方案主要還是結(jié)合安全和反作弊措施來制止。

    比如,識別頻繁下單不付款的買家并進(jìn)行打標(biāo),這樣可以在打標(biāo)買家下單時不減庫存;

    再比如為大促商品設(shè)置單人最大購買件數(shù),一人最多只能買 N 件商品;

    又或者對重復(fù)下單不付款的行為進(jìn)行次數(shù)限制阻斷等

  2. 避免超賣:

    庫存超賣的情況實際分為兩種。

    對于普通商品,秒殺只是一種大促手段,即使庫存超賣,商家也可以通過補(bǔ)貨來解決;而對于一些商品,秒殺作為一種營銷手段,完全不允許庫存為負(fù),也就是在數(shù)據(jù)一致性上,需要保證大并發(fā)請求時數(shù)據(jù)庫中的庫存字段值不能為負(fù),一般有多種方案:

    一是在通過事務(wù)來判斷,即保證減后庫存不能為負(fù),否則就回滾;

    二是直接設(shè)置數(shù)據(jù)庫字段類型為無符號整數(shù),這樣一旦庫存為負(fù)就會在執(zhí)行 SQL 時報錯;

    三是使用 CASE WHEN 判斷語句——

  1. UPDATE item SET inventory = CASE WHEN inventory >= xxx THEN inventory-xxx ELSE inventory END 

業(yè)務(wù)手段保證商品賣的出去,技術(shù)手段保證商品不會超賣,庫存問題從來就不是簡單的技術(shù)難題,解決問題的視角是多種多樣的。

4 一致性性能的優(yōu)化

庫存是個關(guān)鍵數(shù)據(jù),更是個熱點數(shù)據(jù)。對系統(tǒng)來說,熱點的實際影響就是 “高讀” 和 “高寫”,也是秒殺場景下最為核心的一個技術(shù)難題。

4.1 高并發(fā)讀

秒殺場景解決高并發(fā)讀問題,關(guān)鍵詞是“分層校驗”。即在讀鏈路時,只進(jìn)行不影響性能的檢查操作,如用戶是否具有秒殺資格、商品狀態(tài)是否正常、用戶答題是否正確、秒殺是否已經(jīng)結(jié)束、是否非法請求等,而不做一致性校驗等容易引發(fā)瓶頸的檢查操作;直到寫鏈路時,才對庫存做一致性檢查,在數(shù)據(jù)層保證最終準(zhǔn)確性。

因此,在分層校驗設(shè)定下,系統(tǒng)可以采用分布式緩存甚至LocalCache來抵抗高并發(fā)讀。即允許讀場景下一定的臟數(shù)據(jù),這樣只會導(dǎo)致少量原本無庫存的下單請求被誤認(rèn)為是有庫存的,等到真正寫數(shù)據(jù)時再保證最終一致性,由此做到高可用和一致性之間的平衡。

實際上,分層校驗的核心思想是:不同層次盡可能過濾掉無效請求,只在“漏斗” 最末端進(jìn)行有效處理,從而縮短系統(tǒng)瓶頸的影響路徑。

4.2 高并發(fā)寫

高并發(fā)寫的優(yōu)化方式,一種是更換DB選型,一種是優(yōu)化DB性能,以下分別進(jìn)行討論。

4.2.1 更換DB選型

秒殺商品和普通商品的減庫存是有差異的,核心區(qū)別在數(shù)據(jù)量級小、交易時間短,因此能否把秒殺減庫存直接放到緩存系統(tǒng)中實現(xiàn)呢,也就是直接在一個帶有持久化功能的緩存中進(jìn)行減庫存操作,比如 Redis?

如果減庫存邏輯非常單一的話,比如沒有復(fù)雜的 SKU 庫存和總庫存這種聯(lián)動關(guān)系的話,個人認(rèn)為是完全可以的。但如果有比較復(fù)雜的減庫存邏輯,或者需要使用到事務(wù),那就必須在數(shù)據(jù)庫中完成減庫存操作。

4.2.2 優(yōu)化DB性能

庫存數(shù)據(jù)落地到數(shù)據(jù)庫實現(xiàn)其實是一行存儲(MySQL),因此會有大量線程來競爭 InnoDB 行鎖。但并發(fā)越高,等待線程就會越多,TPS 下降,RT 上升,吞吐量會受到嚴(yán)重影響——注意,這里假設(shè)數(shù)據(jù)庫已基于上文【性能優(yōu)化】完成數(shù)據(jù)隔離,以便于討論聚焦 。

解決并發(fā)鎖的問題,有兩種辦法:

  1. 應(yīng)用層排隊

    通過緩存加入集群分布式鎖,從而控制集群對數(shù)據(jù)庫同一行記錄進(jìn)行操作的并發(fā)度,同時也能控制單個商品占用數(shù)據(jù)庫連接的數(shù)量,防止熱點商品占用過多的數(shù)據(jù)庫連接
  2. 數(shù)據(jù)層排隊

    應(yīng)用層排隊是有損性能的,數(shù)據(jù)層排隊是最為理想的。
    業(yè)界中,阿里的數(shù)據(jù)庫團(tuán)隊開發(fā)了針對InnoDB 層上的補(bǔ)丁程序(patch),可以基于DB層對單行記錄做并發(fā)排隊,從而實現(xiàn)秒殺場景下的定制優(yōu)化——注意,排隊和鎖競爭是有區(qū)別的,如果熟悉 MySQL 的話,就會知道 InnoDB 內(nèi)部的死鎖檢測,以及 MySQL Server 和 InnoDB 的切換都是比較消耗性能的。
    另外阿里的數(shù)據(jù)庫團(tuán)隊還做了很多其他方面的優(yōu)化,如 COMMIT_ON_SUCCESS 和 ROLLBACK_ON_FAIL 的補(bǔ)丁程序,通過在 SQL 里加入提示(hint),實現(xiàn)事務(wù)不需要等待實時提交,而是在數(shù)據(jù)執(zhí)行完最后一條 SQL 后,直接根據(jù) TARGET_AFFECT_ROW 的結(jié)果進(jìn)行提交或回滾,減少網(wǎng)絡(luò)等待的時間(毫秒級)。

    目前阿里已將包含這些補(bǔ)丁程序的 MySQL 開源:AliSQL

4.3 小結(jié)

高讀和高寫的兩種處理方式大相徑庭。讀請求的優(yōu)化空間要大一些,而寫請求的瓶頸一般都在存儲層,優(yōu)化思路的本質(zhì)還是基于 CAP 理論做平衡。

5 總結(jié)一下

當(dāng)然,減庫存還有很多細(xì)節(jié)問題,例如預(yù)扣的庫存超時后如何進(jìn)行回補(bǔ),再比如第三方支付如何保證減庫存和付款時的狀態(tài)一致性,這些也是很大的挑戰(zhàn)。

高可用

盯過秒殺流量監(jiān)控的話,會發(fā)現(xiàn)它不是一條蜿蜒而起的曲線,而是一條挺拔的直線,這是因為秒殺請求高度集中于某一特定的時間點。這樣一來就會造成一個特別高的零點峰值,而對資源的消耗也幾乎是瞬時的。所以秒殺系統(tǒng)的可用性保護(hù)是不可或缺的。

1 流量削峰

對于秒殺的目標(biāo)場景,最終能夠搶到商品的人數(shù)是固定的,無論 100 人和 10000 人參加結(jié)果都是一樣的,即有效請求額度是有限的。并發(fā)度越高,無效請求也就越多。但秒殺作為一種商業(yè)營銷手段,活動開始之前是希望有更多的人來刷頁面,只是真正開始后,秒殺請求不是越多越好。因此系統(tǒng)可以設(shè)計一些規(guī)則,人為的延緩秒殺請求,甚至可以過濾掉一些無效請求。

1.1 答題

早期秒殺只是簡單的點擊秒殺按鈕,后來才增加了答題。為什么要增加答題呢?主要是通過提升購買的復(fù)雜度,達(dá)到兩個目的:

  1. 防止作弊。

    早期秒殺器比較猖獗,存在惡意買家或競爭對手使用秒殺器掃貨的情況,商家沒有達(dá)到營銷的目的,所以增加答題來進(jìn)行限制

  2. 延緩請求。

    零點流量的起效時間是毫秒級的,答題可以人為拉長峰值下單的時長,由之前的 <1s 延長到 <10s。

    這個時間對于服務(wù)端非常重要,會大大減輕高峰期并發(fā)壓力;

    另外,由于請求具有先后順序,答題后置的請求到來時可能已經(jīng)沒有庫存了,因此根本無法下單,此階段落到數(shù)據(jù)層真正的寫也就非常有限了

需要注意的是,答題除了做正確性驗證,還需要對提交時間做驗證,比如<1s 人為操作的可能性就很小,可以進(jìn)一步防止機(jī)器答題的情況。

答題目前已經(jīng)使用的非常普遍了,本質(zhì)是通過在入口層削減流量,從而讓系統(tǒng)更好地支撐瞬時峰值。

1.2 排隊

最為常見的削峰方案是使用消息隊列,通過把同步的直接調(diào)用轉(zhuǎn)換成異步的間接推送緩沖瞬時流量。除了消息隊列,類似的排隊方案還有很多,例如:

  1. 線程池加鎖等待

  2. 本地內(nèi)存蓄洪等待

  3. 本地文件序列化寫,再順序讀

排隊方式的弊端也是顯而易見的,主要有兩點:

  1. 請求積壓。

    流量高峰如果長時間持續(xù),達(dá)到了隊列的水位上限,隊列同樣會被壓垮,這樣雖然保護(hù)了下游系統(tǒng),但是和請求直接丟棄也沒多大區(qū)別

  2. 用戶體驗。

    異步推送的實時性和有序性自然是比不上同步調(diào)用的,由此可能出現(xiàn)請求先發(fā)后至的情況,影響部分敏感用戶的購物體驗

排隊本質(zhì)是在業(yè)務(wù)層將一步操作轉(zhuǎn)變成兩步操作,從而起到緩沖的作用,但鑒于此種方式的弊端,最終還是要基于業(yè)務(wù)量級和秒殺場景做出妥協(xié)和平衡。

1.3 過濾

過濾的核心結(jié)構(gòu)在于分層,通過在不同層次過濾掉無效請求,達(dá)到數(shù)據(jù)讀寫的精準(zhǔn)觸發(fā)。常見的過濾主要有以下幾層:

1、讀限流:對讀請求做限流保護(hù),將超出系統(tǒng)承載能力的請求過濾掉
2、讀緩存:對讀請求做數(shù)據(jù)緩存,將重復(fù)的請求過濾掉
3、寫限流:對寫請求做限流保護(hù),將超出系統(tǒng)承載能力的請求過濾掉
4、寫校驗:對寫請求做一致性校驗,只保留最終的有效數(shù)據(jù)

過濾的核心目的是通過減少無效請求的數(shù)據(jù)IO保障有效請求的IO性能。

1.4 小結(jié)

系統(tǒng)可以通過入口層的答題、業(yè)務(wù)層的排隊、數(shù)據(jù)層的過濾達(dá)到流量削峰的目的,本質(zhì)是在尋求商業(yè)訴求與架構(gòu)性能之間的平衡。另外,新的削峰手段也層出不窮,以業(yè)務(wù)切入居多,比如零點大促時同步發(fā)放優(yōu)惠券或發(fā)起抽獎活動,將一部分流量分散到其他系統(tǒng),這樣也能起到削峰的作用。

2 Plan B

當(dāng)一個系統(tǒng)面臨持續(xù)的高峰流量時,其實是很難單靠自身調(diào)整來恢復(fù)狀態(tài)的,日常運(yùn)維沒有人能夠預(yù)估所有情況,意外總是無法避免。尤其在秒殺這一場景下,為了保證系統(tǒng)的高可用,必須設(shè)計一個 Plan B 方案來進(jìn)行兜底。

高可用建設(shè),其實是一個系統(tǒng)工程,貫穿在系統(tǒng)建設(shè)的整個生命周期。

看完这篇,你也能设计一个高性能的“秒杀”系统

具體來說,系統(tǒng)的高可用建設(shè)涉及架構(gòu)階段、編碼階段、測試階段、發(fā)布階段、運(yùn)行階段,以及故障發(fā)生時,逐一進(jìn)行分析:

  1. 架構(gòu)階段:

    考慮系統(tǒng)的可擴(kuò)展性和容錯性,避免出現(xiàn)單點問題。

    例如多地單元化部署,即使某個IDC甚至地市出現(xiàn)故障,仍不會影響系統(tǒng)運(yùn)轉(zhuǎn)

  2. 編碼階段:

    保證代碼的健壯性,例如RPC調(diào)用時,設(shè)置合理的超時退出機(jī)制,防止被其他系統(tǒng)拖垮,同時也要對無法預(yù)料的返回錯誤進(jìn)行默認(rèn)的處理

  3. 測試階段:

    保證CI的覆蓋度以及Sonar的容錯率,對基礎(chǔ)質(zhì)量進(jìn)行二次校驗,并定期產(chǎn)出整體質(zhì)量的趨勢報告

  4. 發(fā)布階段:

    系統(tǒng)部署最容易暴露錯誤,因此要有前置的checklist模版、中置的上下游周知機(jī)制以及后置的回滾機(jī)制

  5. 運(yùn)行階段:

    系統(tǒng)多數(shù)時間處于運(yùn)行態(tài),最重要的是運(yùn)行時的實時監(jiān)控,及時發(fā)現(xiàn)問題、準(zhǔn)確報警并能提供詳細(xì)數(shù)據(jù),以便排查問題

  6. 故障發(fā)生:

    首要目標(biāo)是及時止損,防止影響面擴(kuò)大,然后定位原因、解決問題,最后恢復(fù)服務(wù)

對于日常運(yùn)維而言,高可用更多是針對運(yùn)行階段而言的,此階段需要額外進(jìn)行加強(qiáng)建設(shè),主要有以下幾種手段:

  1. 預(yù)防:

    建立常態(tài)壓測體系,定期對服務(wù)進(jìn)行單點壓測以及全鏈路壓測,摸排水位

  2. 管控:

    做好線上運(yùn)行的降級、限流和熔斷保護(hù)。

    需要注意的是,無論是限流、降級還是熔斷,對業(yè)務(wù)都是有損的,所以在進(jìn)行操作前,一定要和上下游業(yè)務(wù)確認(rèn)好再進(jìn)行。

    就拿限流來說,哪些業(yè)務(wù)可以限、什么情況下限、限流時間多長、什么情況下進(jìn)行恢復(fù),都要和業(yè)務(wù)方反復(fù)確認(rèn)

  3. 監(jiān)控:

    建立性能基線,記錄性能的變化趨勢;

    建立報警體系,發(fā)現(xiàn)問題及時預(yù)警

  4. 恢復(fù):

    遇到故障能夠及時止損,并提供快速的數(shù)據(jù)訂正工具,不一定要好,但一定要有

在系統(tǒng)建設(shè)的整個生命周期中,每個環(huán)節(jié)中都可能犯錯,甚至有些環(huán)節(jié)犯的錯,后面是無法彌補(bǔ)的或者成本極高的。所以高可用是一個系統(tǒng)工程,必須放到整個生命周期中進(jìn)行全面考慮。同時,考慮到服務(wù)的增長性,高可用更需要長期規(guī)劃并進(jìn)行體系化建設(shè)。

3 總結(jié)一下

高可用其實是在說 “穩(wěn)定性”,穩(wěn)定性是一個平時不重要,但出了問題就要命的事情,然而它的落地又是一個問題——平時業(yè)務(wù)發(fā)展良好,穩(wěn)定性建設(shè)就會降級給業(yè)務(wù)讓路。

解決這個問題必須在組織上有所保障,比如讓業(yè)務(wù)負(fù)責(zé)人背上穩(wěn)定性績效指標(biāo),同時在部門中建立穩(wěn)定性建設(shè)小組,小組成員由每條線的核心力量兼任,績效由穩(wěn)定性負(fù)責(zé)人來打分,這樣就可以把體系化的建設(shè)任務(wù)落實到具體的業(yè)務(wù)系統(tǒng)中了。

個人總結(jié)

一個秒殺系統(tǒng)的設(shè)計,可以根據(jù)不同級別的流量,由簡單到復(fù)雜打造出不同的架構(gòu),本質(zhì)是各方面的取舍和權(quán)衡。當(dāng)然,你可能注意到,本文并沒有涉及具體的選型方案,因為這些對于架構(gòu)來說并不重要,作為架構(gòu)師,應(yīng)該時刻提醒自己主線是什么。

同時也在這里抽象、提煉一下,主要是個人對于秒殺設(shè)計的提綱式整理,方便各位同學(xué)進(jìn)行參考——!

看完这篇,你也能设计一个高性能的“秒杀”系统

 

 

責(zé)任編輯:張燕妮 來源: 高效運(yùn)維
相關(guān)推薦

2019-06-06 09:36:37

高并發(fā)高性能系統(tǒng)

2019-06-27 09:50:49

高性能秒殺系統(tǒng)

2024-11-20 08:09:19

RabbitMQ項目客戶端

2024-06-21 08:15:25

2024-03-19 13:51:31

JavaScript插件

2024-08-28 08:38:51

2022-07-18 08:02:16

秒殺系統(tǒng)后端

2025-01-22 08:00:00

架構(gòu)秒殺系統(tǒng)Java

2020-03-18 21:12:22

Nginx網(wǎng)站Linux

2023-07-26 13:29:43

高性能短鏈系統(tǒng)

2018-03-28 21:40:03

2021-03-16 16:35:39

網(wǎng)關(guān)Java代碼

2024-06-17 11:59:39

2019-10-31 13:58:32

阿里電商系統(tǒng)

2023-10-08 19:06:41

2019-05-17 09:33:50

圖像識別三維重建文本識別

2016-10-27 11:11:12

頭條

2011-09-14 10:08:07

Beanstalkd

2017-02-09 19:45:07

Linux系統(tǒng)Linux 發(fā)行版

2024-09-02 18:10:20

點贊
收藏

51CTO技術(shù)棧公眾號