轉載: 詳解:淘寶大秒殺系統(tǒng)是如何設計的滑黔?

轉載: 詳解:淘寶大秒殺系統(tǒng)是如何設計的亮曹?

作者:小刀愛編程

鏈接:

https://my.oschina.net/u/3972077/blog/2231326

摘要

最初的秒殺系統(tǒng)的原型是淘寶詳情上的定時上架功能,由于有些賣家為了吸引眼球秦踪,把價格壓得很低机错。但這給的詳情系統(tǒng)帶來了很大壓力爬范,為了將這種突發(fā)流量隔離,才設計了秒殺系統(tǒng)弱匪,文章主要介紹大秒系統(tǒng)以及這種典型讀數(shù)據(jù)的熱點問題的解決思路和實踐經(jīng)驗青瀑。

一些數(shù)據(jù)

大家還記得2013年的小米秒殺嗎?三款小米手機各11萬臺開賣萧诫,走的都是大秒系統(tǒng)斥难,3分鐘后成為雙十一第一家也是最快破億的旗艦店。經(jīng)過日志統(tǒng)計帘饶,前端系統(tǒng)雙11峰值有效請求約60w以上的QPS 哑诊,而后端cache的集群峰值近2000w/s、單機也近30w/s及刻,但到真正的寫時流量要小很多了镀裤,當時最高下單減庫存tps是紅米創(chuàng)造,達到1500/s提茁。

一些概念

熱點隔離淹禾。秒殺系統(tǒng)設計的第一個原則就是將這種熱點數(shù)據(jù)隔離出來,不要讓1%的請求影響到另外的99%茴扁,隔離出來后也更方便對這1%的請求做針對性優(yōu)化铃岔。針對秒殺我們做了多個層次的隔離:

業(yè)務隔離。?把秒殺做成一種營銷活動峭火,賣家要參加秒殺這種營銷活動需要單獨報名毁习,從技術上來說,賣家報名后對我們來說就是已知熱點卖丸,當真正開始時我們可以提前做好預熱纺且。

系統(tǒng)隔離。?系統(tǒng)隔離更多是運行時的隔離稍浆,可以通過分組部署的方式和另外99%分開载碌。秒殺還申請了單獨的域名,目的也是讓請求落到不同的集群中衅枫。

數(shù)據(jù)隔離嫁艇。?秒殺所調用的數(shù)據(jù)大部分都是熱數(shù)據(jù),比如會啟用單獨cache集群或MySQL數(shù)據(jù)庫來放熱點數(shù)據(jù)弦撩,目前也是不想0.01%的數(shù)據(jù)影響另外99.99%步咪。

當然實現(xiàn)隔離很有多辦法,如可以按照用戶來區(qū)分益楼,給不同用戶分配不同cookie猾漫,在接入層路由到不同服務接口中点晴;還有在接入層可以對URL的不同Path來設置限流策略等。服務層通過調用不同的服務接口悯周;數(shù)據(jù)層可以給數(shù)據(jù)打上特殊的標來區(qū)分粒督。目的都是把已經(jīng)識別出來的熱點和普通請求區(qū)分開來。

動靜分離

前面介紹在系統(tǒng)層面上的原則是要做隔離禽翼,接下去就是要把熱點數(shù)據(jù)進行動靜分離坠陈,這也是解決大流量系統(tǒng)的一個重要原則。如何給系統(tǒng)做動靜分離的靜態(tài)化改造我以前寫過一篇《高訪問量系統(tǒng)的靜態(tài)化架構設計》詳細介紹了淘寶商品系統(tǒng)的靜態(tài)化設計思路捐康,感興趣的可以在《程序員》雜志上找一下仇矾。我們的大秒系統(tǒng)是從商品詳情系統(tǒng)發(fā)展而來,所以本身已經(jīng)實現(xiàn)了動靜分離解总,如圖1贮匕。


圖1 大秒系統(tǒng)動靜分離

除此之外還有如下特點:

把整個頁面Cache在用戶瀏覽器

如果強制刷新整個頁面,也會請求到CDN

實際有效請求只是“刷新?lián)寣殹卑粹o

這樣把90%的靜態(tài)數(shù)據(jù)緩存在用戶端或者CDN上花枫,當真正秒殺時用戶只需要點擊特殊的按鈕“刷新?lián)寣殹奔纯煽萄危恍枰⑿抡麄€頁面,這樣只向服務端請求很少的有效數(shù)據(jù)劳翰,而不需要重復請求大量靜態(tài)數(shù)據(jù)敦锌。秒殺的動態(tài)數(shù)據(jù)和普通的詳情頁面的動態(tài)數(shù)據(jù)相比更少,性能也比普通的詳情提升3倍以上佳簸。所以“刷新?lián)寣殹边@種設計思路很好地解決了不刷新頁面就能請求到服務端最新的動態(tài)數(shù)據(jù)乙墙。

基于時間分片削峰

熟悉淘寶秒殺的都知道,第一版的秒殺系統(tǒng)本身并沒有答題功能生均,后面才增加了秒殺答題听想,當然秒殺答題一個很重要的目的是為了防止秒殺器,2011年秒殺非陈黼剩火的時候汉买,秒殺器也比較猖獗,而沒有達到全民參與和營銷的目的佩脊,所以增加的答題來限制秒殺器蛙粘。增加答題后,下單的時間基本控制在2s后威彰,秒殺器的下單比例也下降到5%以下出牧。新的答題頁面如圖2。


圖2 秒答題頁面

其實增加答題還有一個重要的功能抱冷,就是把峰值的下單請求給拉長了崔列,從以前的1s之內(nèi)延長到2~10s左右梢褐,請求峰值基于時間分片了旺遮,這個時間的分片對服務端處理并發(fā)非常重要赵讯,會減輕很大壓力,另外由于請求的先后耿眉,靠后的請求自然也沒有庫存了边翼,也根本到不了最后的下單步驟,所以真正的并發(fā)寫就非常有限了鸣剪。其實這種設計思路目前也非常普遍组底,如支付寶的“咻一咻”已及微信的搖一搖。

除了在前端通過答題在用戶端進行流量削峰外筐骇,在服務端一般通過鎖或者隊列來控制瞬間請求债鸡。

數(shù)據(jù)分層校驗


圖3 分層校驗

對大流量系統(tǒng)的數(shù)據(jù)做分層校驗也是最重要的設計原則,所謂分層校驗就是對大量的請求做成“漏斗”式設計铛纬,如圖3所示:在不同層次盡可能把無效的請求過濾厌均,“漏斗”的最末端才是有效的請求,要達到這個效果必須對數(shù)據(jù)做分層的校驗告唆,下面是一些原則:

先做數(shù)據(jù)的動靜分離

將90%的數(shù)據(jù)緩存在客戶端瀏覽器

將動態(tài)請求的讀數(shù)據(jù)Cache在Web端

對讀數(shù)據(jù)不做強一致性校驗

對寫數(shù)據(jù)進行基于時間的合理分片

對寫請求做限流保護

對寫數(shù)據(jù)進行強一致性校驗

秒殺系統(tǒng)正是按照這個原則設計的系統(tǒng)架構棺弊,如圖4所示。


圖4 秒殺系統(tǒng)分層架構

把大量靜態(tài)不需要檢驗的數(shù)據(jù)放在離用戶最近的地方擒悬;在前端讀系統(tǒng)中檢驗一些基本信息模她,如用戶是否具有秒殺資格、商品狀態(tài)是否正常懂牧、用戶答題是否正確侈净、秒殺是否已經(jīng)結束等;在寫數(shù)據(jù)系統(tǒng)中再校驗一些如是否是非法請求僧凤,營銷等價物是否充足(淘金幣等)用狱,寫的數(shù)據(jù)一致性如檢查庫存是否還有等;最后在數(shù)據(jù)庫層保證數(shù)據(jù)最終準確性拼弃,如庫存不能減為負數(shù)夏伊。

實時熱點發(fā)現(xiàn)

其實秒殺系統(tǒng)本質是還是一個數(shù)據(jù)讀的熱點問題,而且是最簡單一種吻氧,因為在文提到通過業(yè)務隔離溺忧,我們已能提前識別出這些熱點數(shù)據(jù),我們可以提前做一些保護盯孙,提前識別的熱點數(shù)據(jù)處理起來還相對簡單鲁森,比如分析歷史成交記錄發(fā)現(xiàn)哪些商品比較熱門,分析用戶的購物車記錄也可以發(fā)現(xiàn)那些商品可能會比較好賣振惰,這些都是可以提前分析出來的熱點歌溉。比較困難的是那種我們提前發(fā)現(xiàn)不了突然成為熱點的商品成為熱點,這種就要通過實時熱點數(shù)據(jù)分析了,目前我們設計可以在3s內(nèi)發(fā)現(xiàn)交易鏈路上的實時熱點數(shù)據(jù)痛垛,然后根據(jù)實時發(fā)現(xiàn)的熱點數(shù)據(jù)每個系統(tǒng)做實時保護草慧。 具體實現(xiàn)如下:

構建一個異步的可以收集交易鏈路上各個中間件產(chǎn)品如Tengine、Tair緩存匙头、HSF等本身的統(tǒng)計的熱點key(Tengine和Tair緩存等中間件產(chǎn)品本身已經(jīng)有熱點統(tǒng)計模塊)漫谷。

建立一個熱點上報和可以按照需求訂閱的熱點服務的下發(fā)規(guī)范,主要目的是通過交易鏈路上各個系統(tǒng)(詳情蹂析、購物車舔示、交易、優(yōu)惠电抚、庫存惕稻、物流)訪問的時間差,把上游已經(jīng)發(fā)現(xiàn)的熱點能夠透傳給下游系統(tǒng)蝙叛,提前做好保護缩宜。比如大促高峰期詳情系統(tǒng)是最早知道的,在統(tǒng)計接入層上Tengine模塊統(tǒng)計的熱點URL甥温。

將上游的系統(tǒng)收集到熱點數(shù)據(jù)發(fā)送到熱點服務臺上锻煌,然后下游系統(tǒng)如交易系統(tǒng)就會知道哪些商品被頻繁調用,然后做熱點保護姻蚓。如圖5所示宋梧。


圖5 實時熱點數(shù)據(jù)后臺

重要的幾個:其中關鍵部分包括:

這個熱點服務后臺抓取熱點數(shù)據(jù)日志最好是異步的,一方面便于做到通用性狰挡,另一方面不影響業(yè)務系統(tǒng)和中間件產(chǎn)品的主流程捂龄。

熱點服務后臺、現(xiàn)有各個中間件和應用在做的沒有取代關系加叁,每個中間件和應用還需要保護自己倦沧,熱點服務后臺提供一個收集熱點數(shù)據(jù)提供熱點訂閱服務的統(tǒng)一規(guī)范和工具,便于把各個系統(tǒng)熱點數(shù)據(jù)透明出來它匕。

熱點發(fā)現(xiàn)要做到實時(3s內(nèi))展融。

關鍵技術優(yōu)化點

前面介紹了一些如何設計大流量讀系統(tǒng)中用到的原則,但是當這些手段都用了豫柬,還是有大流量涌入該如何處理呢告希?秒殺系統(tǒng)要解決幾個關鍵問題。

Java處理大并發(fā)動態(tài)請求優(yōu)化

其實Java和通用的Web服務器相比(Nginx或Apache)在處理大并發(fā)HTTP請求時要弱一點烧给,所以一般我們都會對大流量的Web系統(tǒng)做靜態(tài)化改造燕偶,讓大部分請求和數(shù)據(jù)直接在Nginx服務器或者Web代理服務器(Varnish、Squid等)上直接返回(可以減少數(shù)據(jù)的序列化與反序列化),不要將請求落到Java層上,讓Java層只處理很少數(shù)據(jù)量的動態(tài)請求,當然針對這些請求也有一些優(yōu)化手段可以使用:

直接使用Servlet處理請求值漫。?避免使用傳統(tǒng)的MVC框架也許能繞過一大堆復雜且用處不大的處理邏輯伯诬,節(jié)省個1ms時間晚唇,當然這個取決于你對MVC框架的依賴程度。

直接輸出流數(shù)據(jù)姑廉。?使用resp.getOutputStream()而不是resp.getWriter()可以省掉一些不變字符數(shù)據(jù)編碼,也能提升性能翁涤;還有數(shù)據(jù)輸出時也推薦使用JSON而不是模板引擎(一般都是解釋執(zhí)行)輸出頁面桥言。

同一商品大并發(fā)讀問題

你會說這個問題很容易解決,無非放到Tair緩存里面就行葵礼,集中式Tair緩存為了保證命中率号阿,一般都會采用一致性Hash,所以同一個key會落到一臺機器上鸳粉,雖然我們的Tair緩存機器單臺也能支撐30w/s的請求扔涧,但是像大秒這種級別的熱點商品還遠不夠,那如何徹底解決這種單點瓶頸届谈?答案是采用應用層的Localcache,即在秒殺系統(tǒng)的單機上緩存商品相關的數(shù)據(jù)艰山,如何cache數(shù)據(jù)湖雹?也分動態(tài)和靜態(tài):

像商品中的標題和描述這些本身不變的會在秒殺開始之前全量推送到秒殺機器上并一直緩存直到秒殺結束曙搬。

像庫存這種動態(tài)數(shù)據(jù)會采用被動失效的方式緩存一定時間(一般是數(shù)秒),失效后再去Tair緩存拉取最新的數(shù)據(jù)纵装。

你可能會有疑問征讲,像庫存這種頻繁更新數(shù)據(jù)一旦數(shù)據(jù)不一致會不會導致超賣?其實這就要用到我們前面介紹的讀數(shù)據(jù)分層校驗原則了橡娄,讀的場景可以允許一定的臟數(shù)據(jù),因為這里的誤判只會導致少量一些原本已經(jīng)沒有庫存的下單請求誤認為還有庫存而已挽唉,等到真正寫數(shù)據(jù)時再保證最終的一致性。這樣在數(shù)據(jù)的高可用性和一致性做平衡來解決這種高并發(fā)的數(shù)據(jù)讀取問題橱夭。

同一數(shù)據(jù)大并發(fā)更新問題

解決大并發(fā)讀問題采用Localcache和數(shù)據(jù)的分層校驗的方式氨距,但是無論如何像減庫存這種大并發(fā)寫還是避免不了,這也是秒殺這個場景下最核心的技術難題棘劣。

同一數(shù)據(jù)在數(shù)據(jù)庫里肯定是一行存儲(MySQL)俏让,所以會有大量的線程來競爭InnoDB行鎖,當并發(fā)度越高時等待的線程也會越多首昔,TPS會下降RT會上升,數(shù)據(jù)庫的吞吐量會嚴重受到影響勒奇。說到這里會出現(xiàn)一個問題,就是單個熱點商品會影響整個數(shù)據(jù)庫的性能赊颠,就會出現(xiàn)我們不愿意看到的0.01%商品影響99.99%的商品,所以一個思路也是要遵循前面介紹第一個原則進行隔離竣蹦,把熱點商品放到單獨的熱點庫中

但是無疑也會帶來維護的麻煩(要做熱點數(shù)據(jù)的動態(tài)遷移以及單獨的數(shù)據(jù)庫等)。

分離熱點商品到單獨的數(shù)據(jù)庫還是沒有解決并發(fā)鎖的問題痘括,要解決并發(fā)鎖有兩層辦法。

應用層做排隊纲菌。?按照商品維度設置隊列順序執(zhí)行,這樣能減少同一臺機器對數(shù)據(jù)庫同一行記錄操作的并發(fā)度翰舌,同時也能控制單個商品占用數(shù)據(jù)庫連接的數(shù)量,防止熱點商品占用太多數(shù)據(jù)庫連接灶芝。

數(shù)據(jù)庫層做排隊。?應用層只能做到單機排隊夜涕,但應用機器數(shù)本身很多,這種排隊方式控制并發(fā)仍然有限女器,所以如果能在數(shù)據(jù)庫層做全局排隊是最理想的,淘寶的數(shù)據(jù)庫團隊開發(fā)了針對這種MySQL的InnoDB層上的patch驾胆,可以做到數(shù)據(jù)庫層上對單行記錄做到并發(fā)排隊,如圖6所示丧诺。


圖6 數(shù)據(jù)庫層對單行記錄并發(fā)排隊

你可能會問排隊和鎖競爭不要等待嗎?有啥區(qū)別驳阎?如果熟悉MySQL會知道馁蒂,InnoDB內(nèi)部的死鎖檢測以及MySQL Server和InnoDB的切換會比較耗性能蜘腌,淘寶的MySQL核心團隊還做了很多其他方面的優(yōu)化沫屡,如COMMIT_ON_SUCCESS和ROLLBACK_ON_FAIL的patch,配合在SQL里面加hint撮珠,在事務里不需要等待應用層提交COMMIT而在數(shù)據(jù)執(zhí)行完最后一條SQL后直接根據(jù)TARGET_AFFECT_ROW結果提交或回滾沮脖,可以減少網(wǎng)絡的等待時間(平均約0.7ms)。據(jù)我所知芯急,目前阿里MySQL團隊已將這些patch及提交給MySQL官方評審勺届。

大促熱點問題思考

以秒殺這個典型系統(tǒng)為代表的熱點問題根據(jù)多年經(jīng)驗我總結了些通用原則:隔離、動態(tài)分離志于、分層校驗涮因,必須從整個全鏈路來考慮和優(yōu)化每個環(huán)節(jié)废睦,除了優(yōu)化系統(tǒng)提升性能伺绽,做好限流和保護也是必備的功課。

除去前面介紹的這些熱點問題外嗜湃,淘系還有多種其他數(shù)據(jù)熱點問題:

數(shù)據(jù)訪問熱點,比如Detail中對某些熱點商品的訪問度非常高购披,即使是Tair緩存這種Cache本身也有瓶頸問題,一旦請求量達到單機極限也會存在熱點保護問題刚陡。有時看起來好像很容易解決,比如說做好限流就行歌殃,但你想想一旦某個熱點觸發(fā)了一臺機器的限流閥值蝙云,那么這臺機器Cache的數(shù)據(jù)都將無效氓皱,進而間接導致Cache被擊穿勃刨,請求落地應用層數(shù)據(jù)庫出現(xiàn)雪崩現(xiàn)象。這類問題需要與具體Cache產(chǎn)品結合才能有比較好的解決方案身隐,這里提供一個通用的解決思路,就是在Cache的client端做本地Localcache躲因,當發(fā)現(xiàn)熱點數(shù)據(jù)時直接Cache在client里早敬,而不要請求到Cache的Server大脉。

數(shù)據(jù)更新熱點,更新問題除了前面介紹的熱點隔離和排隊處理之外琐驴,還有些場景,如對商品的lastmodifytime字段更新會非常頻繁绝淡,在某些場景下這些多條SQL是可以合并的苍姜,一定時間內(nèi)只執(zhí)行最后一條SQL就行了,可以減少對數(shù)據(jù)庫的update操作衙猪。另外熱點商品的自動遷移,理論上也可以在數(shù)據(jù)路由層來完成垫释,利用前面介紹的熱點實時發(fā)現(xiàn)自動將熱點從普通庫里遷移出來放到單獨的熱點庫中。

按照某種維度建的索引產(chǎn)生熱點數(shù)據(jù)棵譬,比如實時搜索中按照商品維度關聯(lián)評價數(shù)據(jù),有些熱點商品的評價非常多曼尊,導致搜索系統(tǒng)按照商品ID建評價數(shù)據(jù)的索引時內(nèi)存已經(jīng)放不下脏嚷,交易維度關聯(lián)訂單信息也同樣有這些問題骆撇。這類熱點數(shù)據(jù)需要做數(shù)據(jù)散列然眼,再增加一個維度,把數(shù)據(jù)重新組織屿岂。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鲸匿,一起剝皮案震驚了整個濱河市爷怀,隨后出現(xiàn)的幾起案子带欢,更是在濱河造成了極大的恐慌烤惊,老刑警劉巖吁朦,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異逗宜,居然都是意外死亡,警方通過查閱死者的電腦和手機擂仍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門熬甚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人乡括,你說我怎么就攤上這事∷谂校” “怎么了峦剔?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長呻澜。 經(jīng)常有香客問我,道長羹幸,這世上最難降的妖魔是什么辫愉? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮恭朗,結果婚禮上,老公的妹妹穿的比我還像新娘痰腮。我一直安慰自己,他們只是感情好棍丐,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著歌逢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪秘案。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天师骗,我揣著相機與錄音讨惩,去河邊找鬼辟癌。 笑死荐捻,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的处面。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼昵济,長吁一口氣:“原來是場噩夢啊……” “哼野揪!你這毒婦竟也來了访忿?” 一聲冷哼從身側響起斯稳,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎卧斟,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體珍语,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡唇辨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了赏枚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晓猛。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡凡辱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出透乾,到底是詐尸還是另有隱情,我是刑警寧澤乳乌,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布汉操,位于F島的核電站再来,受9級特大地震影響磷瘤,放射性物質發(fā)生泄漏。R本人自食惡果不足惜采缚,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望篡帕。 院中可真熱鬧,春花似錦赂苗、人聲如沸愉耙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赌渣。三九已至魏铅,卻和暖如春坚芜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鸿竖。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工铸敏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留悟泵,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓糕非,卻偏偏與公主長得像,于是被迫代替她去往敵國和親朽肥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容