秒杀系统的架构解决之道
http://www.infoq.com/cn/articles/solution-to-the-architecture-of-spike-system
本文將會(huì)從三個(gè)方面來(lái)分別探討如何設(shè)計(jì)應(yīng)用架構(gòu)以更好的支持“秒殺”類需求,包括秒殺帶來(lái)的問(wèn)題和挑戰(zhàn)、產(chǎn)品架構(gòu)解決之道、流量控制解決方案。
秒殺場(chǎng)景下帶來(lái)的海量用戶所造成的流量突增對(duì)系統(tǒng)沖擊力可想而知,瞬時(shí)流量之高一方面造成的讀寫沖突,數(shù)據(jù)庫(kù)鎖會(huì)非常嚴(yán)重,另一方面應(yīng)用服務(wù)器能否撐住也是一個(gè)問(wèn)題。同時(shí)由于秒殺業(yè)務(wù)一般是各種活動(dòng)帶來(lái),需要快速上下線,這在開發(fā)上也會(huì)提出更高的標(biāo)準(zhǔn),快速支持需求而不出錯(cuò)。從系統(tǒng)上講我們要做到高可用和高并發(fā);從開發(fā)效率上我們要做到敏捷開發(fā)以支持產(chǎn)品快速迭代。接下來(lái)讓我們從產(chǎn)品架構(gòu)和流量控制這兩個(gè)方面來(lái)討論并解決這個(gè)問(wèn)題。如果把解決秒殺問(wèn)題看成一種武林秘籍,則產(chǎn)品架構(gòu)是內(nèi)功,流量控制是招法,上乘內(nèi)力搭配制勝招法則無(wú)往而不利。
內(nèi)功:產(chǎn)品架構(gòu)解決之道
向一站式架構(gòu)說(shuō)"NO"
上圖是一個(gè)典型的一站式架構(gòu),未經(jīng)過(guò)良好的設(shè)計(jì)的系統(tǒng)隨著時(shí)間的推移逐漸會(huì)轉(zhuǎn)換成上圖這樣,一方面是產(chǎn)品業(yè)務(wù)的壓力,另一方面也是先天的設(shè)計(jì)不足。一站式架構(gòu)存在很多問(wèn)題。
首先就是不易擴(kuò)展,難以維護(hù)。隨著業(yè)務(wù)的發(fā)展,對(duì)系統(tǒng)進(jìn)行擴(kuò)容難以避免,而一站式架構(gòu)的可擴(kuò)展性卻令人堪憂,對(duì)其擴(kuò)容則相當(dāng)于對(duì)系統(tǒng)中的所有功能進(jìn)行擴(kuò)容,從代碼確認(rèn)到測(cè)試再到環(huán)境都是一項(xiàng)艱巨的任務(wù)。一站式架構(gòu)中的擴(kuò)容往往建立在“既然什么都沒改,則運(yùn)行應(yīng)該正常”的假設(shè)之上,而擴(kuò)容遷移中的各種BUG則隱藏在這種假設(shè)之中。系統(tǒng)所需的各種權(quán)限也隨著規(guī)模而不斷增多,連接的各種組件也越來(lái)越多,由此帶來(lái)的維護(hù)性問(wèn)題也會(huì)持續(xù)加重。
其次是代碼難以理解,開發(fā)質(zhì)量得不到保證。隨著系統(tǒng)規(guī)模的擴(kuò)大,即便是最初經(jīng)過(guò)良好設(shè)計(jì)的代碼,經(jīng)過(guò)人員迭代,需求壓力,也難免會(huì)逐漸走向混亂。漸漸的,各種跨層調(diào)用,不合適的封裝,有副作用的函數(shù)等都會(huì)出現(xiàn)在代碼中,這些設(shè)計(jì)侵入到代碼中的每個(gè)角落,每個(gè)人都能見,而每個(gè)人都會(huì)選擇性忽略,因?yàn)殄e(cuò)綜復(fù)雜的調(diào)用難以調(diào)整,也很難找到人員來(lái)進(jìn)行整體測(cè)試。而這些都是BUG產(chǎn)生的溫床。
最后在一站式架構(gòu)下項(xiàng)目的可靠性是無(wú)法得到保證的,由于業(yè)務(wù)調(diào)整而修改一處邏輯,往往會(huì)影響到代碼中很多功能的邏輯,而這些額外受到影響的功能則通常不會(huì)得到測(cè)試,只是在假定這些都是正常的,而這種假定也通常正確,直接潛在的問(wèn)題爆發(fā)。該出錯(cuò)的總會(huì)出錯(cuò),墨菲定律往往這時(shí)候是最有效的。
綜上可以看出一站式架構(gòu)設(shè)計(jì)與敏捷開發(fā)格格不入,持續(xù)開發(fā),持續(xù)集成,持續(xù)部署也就只能變成空談了。
微服務(wù)架構(gòu)
上圖是優(yōu)化后的微服務(wù)架構(gòu),將整個(gè)系統(tǒng)拆分成訂單、推送、折扣、產(chǎn)品、個(gè)人信息等各個(gè)微服務(wù),每個(gè)服務(wù)都有自己的數(shù)據(jù)庫(kù)和緩存等,并且不會(huì)互相交叉。各服務(wù)之間使用消息隊(duì)列、RPC調(diào)用等傳輸數(shù)據(jù)。目前大部分系統(tǒng)設(shè)計(jì)可能處于一站式架構(gòu)和微服務(wù)架構(gòu)之間,即上層應(yīng)用可能已經(jīng)服務(wù)化,但是數(shù)據(jù)庫(kù)層面還是使用同一個(gè)庫(kù)。但個(gè)人以為系統(tǒng)應(yīng)該朝完全微服務(wù)化努力,隔離數(shù)據(jù)庫(kù)層面的共用,以獲得更高的系統(tǒng)可靠性。
微服務(wù)架構(gòu)下的系統(tǒng)更加容易進(jìn)行擴(kuò)展,可以只針對(duì)需要擴(kuò)容的系統(tǒng)來(lái)進(jìn)行擴(kuò)容,例如訂單量增大,可以只擴(kuò)容訂單服務(wù),而對(duì)于其他服務(wù)例如個(gè)人信息、折扣中心等都都不進(jìn)行調(diào)整,這樣一方面減少了系統(tǒng)擴(kuò)容而對(duì)整體穩(wěn)定性帶來(lái)的變化,即只需測(cè)試新環(huán)境中的訂單服務(wù)即可,隨著微服務(wù)拆分的越細(xì),這種優(yōu)勢(shì)也就越大。
在這種微服務(wù)架構(gòu)下,開發(fā)人員可以更加集中精力,將重點(diǎn)放到少量的代碼和明確的業(yè)務(wù)上,這樣能夠產(chǎn)出更加優(yōu)雅的代碼和良好的設(shè)計(jì),在代碼優(yōu)化調(diào)整中,也不會(huì)由于到處調(diào)用而畏手畏腳。每個(gè)微服務(wù)可以安排2-3人的小組專門維護(hù),這樣也會(huì)減少一個(gè)微服務(wù)內(nèi)部的溝通成本,而進(jìn)一步提高生產(chǎn)力。每個(gè)微服務(wù)小組可以獨(dú)立工作,無(wú)需過(guò)多協(xié)調(diào)即可實(shí)踐新功能或想法。
隨著技術(shù)的不斷發(fā)展,項(xiàng)目所用的技術(shù)架構(gòu)總會(huì)過(guò)時(shí),在系統(tǒng)技術(shù)革新上,對(duì)于傳統(tǒng)的一站式架構(gòu),甚至是之前提到的服務(wù)化架構(gòu)在應(yīng)用新技術(shù)上都會(huì)遇到不小的困難,牽一發(fā)動(dòng)全身,技術(shù)改革往往除了推倒重來(lái)而沒有其他辦法。對(duì)于微服務(wù)架構(gòu),由于系統(tǒng)的完全拆分,公共組件依賴只剩下異步的消息隊(duì)列,在新技術(shù)應(yīng)用這方面則有了天然優(yōu)勢(shì)。微服務(wù)基于組件開發(fā)設(shè)計(jì),提供了在開發(fā)過(guò)程中技術(shù)選型的最大靈活性,甚至是編程語(yǔ)言的變化都可以進(jìn)行嘗試。
最后要提到的,就是系統(tǒng)穩(wěn)定性和可用性方面的考慮。在業(yè)務(wù)需求的持續(xù)推動(dòng)下,持續(xù)部署不可避免,在線系統(tǒng)隨時(shí)都需要進(jìn)行上線。隨著業(yè)務(wù)的增長(zhǎng)、系統(tǒng)的復(fù)雜,系統(tǒng)部署時(shí)造成問(wèn)題的潛在可能性會(huì)大大提高。而微服務(wù)在這方面極大的提高了系統(tǒng)的可靠性。由于微服務(wù)的劃分,故障天然被隔離,某個(gè)服務(wù)的故障,不會(huì)造成系統(tǒng)的整體癱瘓。而發(fā)布的時(shí)間由于只需要發(fā)布更新相關(guān)的服務(wù)而大大縮短,這也提高了整體系統(tǒng)的穩(wěn)定性。當(dāng)面臨問(wèn)題需要回滾時(shí),也只需要回滾更新相關(guān)服務(wù)即可,而這在一站式架構(gòu)中將會(huì)是一個(gè)災(zāi)難。
良好的架構(gòu)可以更好的支持快速迭代。高內(nèi)聚的設(shè)計(jì)將開發(fā)人員精力集中到相對(duì)集中的領(lǐng)域以設(shè)計(jì)更優(yōu)雅的代碼實(shí)現(xiàn)。隨著技術(shù)的演進(jìn),項(xiàng)目架構(gòu)也可以跟著一起迭代升級(jí)。也可以更好的支持持續(xù)集成、持續(xù)部署。總之,微服務(wù)可以滲透到開發(fā)中的每個(gè)領(lǐng)域?yàn)闃I(yè)務(wù)迭代提供更好的支持。微服務(wù)這方面建議可以參考Spring Cloud和Docker。
招法:流量控制解決方案
內(nèi)功的修煉固然重要,不過(guò)并非一朝一夕可成,是需要長(zhǎng)期的努力和不斷的沉淀。在武學(xué)中固然有高神內(nèi)力,同時(shí)也存在一些致勝招法,一旦練成即可功力猛進(jìn),下來(lái)就讓我們看一下支持秒殺業(yè)務(wù)中的一些致勝招法:流量控制解決方案。
流量控制解決總覽
如上圖所示,在項(xiàng)目的整個(gè)架構(gòu)中,流量要做到逐層減少。在每層中都可以使用一些方法來(lái)減少流量。
前端流量控制
前端流量控制,頁(yè)面可以設(shè)計(jì)為動(dòng)靜分離,將盡可能多的數(shù)據(jù)使用CDN進(jìn)行緩存,以減少到自己服務(wù)器上的流量。同時(shí)可以加入驗(yàn)證問(wèn)題,拉長(zhǎng)用戶下單時(shí)間并防止刷單。對(duì)較核心邏輯擔(dān)心用戶破譯驗(yàn)證方式,可以再增加服務(wù)器端的用戶ID訪問(wèn)限制,例如同一用戶5s內(nèi)只能觸發(fā)1次相關(guān)操作等。
反向代理流量控制
反向代理(Nginx)流量控制,很多頁(yè)面或者接口響應(yīng)數(shù)據(jù)都可以進(jìn)行靜態(tài)化處理,應(yīng)用側(cè)(Tomcat)可以定時(shí)生成這些資源,發(fā)到內(nèi)容分發(fā)服務(wù)上,內(nèi)容分發(fā)服務(wù)可以將這些靜態(tài)化資源分發(fā)到所有的反向代理上。這些數(shù)據(jù)可以根據(jù)需要按照一定時(shí)間間隔進(jìn)行更新。同時(shí),也可以利用Nginx中的緩存配置功能,對(duì)熱點(diǎn)接口進(jìn)行緩存。
借助Nginx中Nginx-lua插件的功能,一些簡(jiǎn)單邏輯在Nginx中直接實(shí)現(xiàn)會(huì)比較容易,使用恰當(dāng),能夠大幅減少到應(yīng)用服務(wù)器的請(qǐng)求。例如倒計(jì)時(shí),取系統(tǒng)當(dāng)前時(shí)間等邏輯就非常適合在Nginx中使用Lua實(shí)現(xiàn)。對(duì)于存在緩存中的商品數(shù)量等信息也可由Nginx直接訪問(wèn)緩存返回,而不將請(qǐng)求再轉(zhuǎn)發(fā)給應(yīng)用服務(wù)器。
訪問(wèn)數(shù)據(jù)分析流量控制
在秒殺中,令人頭疼的問(wèn)題不只是正常流量突增。由于秒殺活動(dòng)一般都帶有優(yōu)惠性質(zhì),惡意訪問(wèn)也會(huì)增多,對(duì)于惡意請(qǐng)求在Nginx層也可以做很多工作,進(jìn)行一次攔截。Nginx配置中有限制用戶訪問(wèn)頻率的配置可以根據(jù)需要進(jìn)行配置。同時(shí),也可以使用nginx-lua完成一些簡(jiǎn)單的封禁邏輯,例如調(diào)用接口可以封掉指定IP或者UA的訪問(wèn)請(qǐng)求。之后利用日志分析程序,對(duì)訪問(wèn)日志進(jìn)行分析,將需要封掉的IP或者UA等信息調(diào)用Nginx上提供的接口進(jìn)行封殺。
應(yīng)用服務(wù)器流量控制
經(jīng)過(guò)之前的處理,能夠到達(dá)應(yīng)用服務(wù)器的流量已經(jīng)少了很多。對(duì)于秒殺活動(dòng)這類的需求,可以準(zhǔn)備專門的活動(dòng)服務(wù)器,專門處理相關(guān)邏輯。可以使用不同域名進(jìn)行分流,或者按照一定URL規(guī)則在反向代理服務(wù)器上進(jìn)行分流。同時(shí),對(duì)于到數(shù)據(jù)庫(kù)進(jìn)行操作的請(qǐng)求可以使用阻塞隊(duì)減少到數(shù)據(jù)庫(kù)的訪問(wèn)以減少行鎖等。對(duì)于明顯超出處理范圍的請(qǐng)求可以直接返回秒殺已經(jīng)結(jié)束。例如商品總量300,剩余量100,每臺(tái)應(yīng)用服務(wù)器上待處理的值超過(guò)總量的值則可以直接返回秒殺結(jié)束。剩余量可以存入緩存服務(wù)中,剩余量可以不那么精確,確保緩存中的剩余量>=實(shí)際剩余量即可。超出剩余量的請(qǐng)求也可以直接返回秒殺結(jié)束。
緩存存儲(chǔ)多點(diǎn)部署以提高系統(tǒng)的整體可用性,避免緩存問(wèn)題導(dǎo)致系統(tǒng)出錯(cuò)的情況。Redis會(huì)是一個(gè)目前比較好的選擇,主從自動(dòng)切換等功能可以更好的增強(qiáng)系統(tǒng)整體可用性。對(duì)于使用單點(diǎn)Memcached等系統(tǒng),建議可以配置Keepalived,使得發(fā)生機(jī)器故障時(shí),IP可以自動(dòng)轉(zhuǎn)移到另外一臺(tái)健康Memcached服務(wù)器上,雖然數(shù)據(jù)不可恢復(fù),但是緩存組件依然可用。宕機(jī)的組件對(duì)系統(tǒng)造成的影響往往是不可預(yù)料的,尤其是在未良好設(shè)計(jì)的系統(tǒng)中,整體架構(gòu)中應(yīng)任一組件完全宕機(jī)的可能性。
對(duì)于秒殺活動(dòng)需求,可能是一系列的活動(dòng),相關(guān)邏輯可以判斷是否可以做到一個(gè)專門活動(dòng)庫(kù)中,并進(jìn)行讀寫分離設(shè)計(jì)。有條件的情況下,數(shù)據(jù)庫(kù)中間件會(huì)完成其中一部分工作。在沒有相關(guān)條件的時(shí)候,即使沒有數(shù)據(jù)庫(kù)中間件,相關(guān)邏輯也可以直接在代碼中實(shí)現(xiàn)。
對(duì)于數(shù)據(jù)庫(kù)行鎖問(wèn)題,如有需要可以進(jìn)一步優(yōu)化,例如上圖,將行鎖問(wèn)題通過(guò)拆分具體商品,增加分配ID標(biāo)志,去掉行鎖。這個(gè)變動(dòng)的缺點(diǎn)是可能對(duì)現(xiàn)有業(yè)務(wù)邏輯影響較大。不過(guò)優(yōu)點(diǎn)也很明顯,在數(shù)據(jù)庫(kù)層面消除了行鎖。
流量控制總結(jié)
一圖勝千言,以上討論的流量控制總結(jié)方案可以總結(jié)到一張圖上:
總結(jié)
結(jié)合微服務(wù)架構(gòu),我們最終的架構(gòu)圖可以是這樣的:
以上供大家參考。
技術(shù)選型簡(jiǎn)介
平臺(tái)應(yīng)用構(gòu)建技術(shù)選型如下,供大家參考:
- 反向代理層Nginx推薦使用阿里開源的Tengine,Tengine中增強(qiáng)了Nginx中的很多功能并簡(jiǎn)化了配置。
- 在虛擬化方面,可以按照物理機(jī)->虛擬機(jī)->Docker三層架構(gòu)來(lái)實(shí)現(xiàn)虛擬化,在物理機(jī)上按照應(yīng)用實(shí)例、緩存實(shí)例、消息隊(duì)列實(shí)例等建立虛擬機(jī),再分別在虛擬機(jī)上啟動(dòng)不同實(shí)例的Docker。
- 在應(yīng)用構(gòu)建方面,推薦使用Spring Cloud解決方案(由于歷史原因,目前還保留部分Dubbo接口)。
- 消息隊(duì)列選型目前比較廣泛,這里推薦一下阿里開源的RocketMQ,目前已經(jīng)捐贈(zèng)給Apache。我們內(nèi)部也針對(duì)RocketMQ開發(fā)了一套易用client,當(dāng)然也在開源計(jì)劃之中,相信不久就會(huì)和大家見面。目前我們系統(tǒng)每分鐘接口請(qǐng)求量高峰在幾十萬(wàn)左右,系統(tǒng)整體支撐再多的訪問(wèn)量相信也沒有問(wèn)題,各層、各服務(wù)根據(jù)需要都可以進(jìn)行橫向擴(kuò)容以支撐更高的訪問(wèn)量。
參考資料
- http://projects.spring.io/spring-cloud/
- http://projects.spring.io/spring-boot/
- http://nginx.org/en/docs/
- http://tengine.taobao.org/documentation_cn.html
- http://dubbo.io/User+Guide-zh.htm
- https://github.com/apache/incubator-rocketmq
- 崔力強(qiáng),張駿 譯. Sam Newman 著. 微服務(wù)設(shè)計(jì)
- 李兆海,劉斌,巨震 譯. 詹姆斯·特恩布爾(James Turnbull) 著. 第一本Docker書 修訂版
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/articles/8971026.html
總結(jié)
以上是生活随笔為你收集整理的秒杀系统的架构解决之道的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何设计一个小而美的秒杀系统?
- 下一篇: 乐视秒杀架构解读:从零开始搭建百万每秒订