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