
前言
?最近,被推送了不少秒殺架構(gòu)的文章,忙里偷閑自己也總結(jié)了一下互聯(lián)網(wǎng)平臺(tái)秒殺架構(gòu)設(shè)計(jì),當(dāng)然也借鑒了不少同學(xué)的思路。俗話說(shuō),脫離案例講架構(gòu)都是耍流氓,最終使用SpringBoot模擬實(shí)現(xiàn)了部分秒殺場(chǎng)景,同時(shí)跟大家分享交流一下。
秒殺場(chǎng)景
秒殺場(chǎng)景無(wú)非就是多個(gè)用戶在同時(shí)搶購(gòu)一件或者多件商品,專用詞匯就是所謂的高并發(fā)?,F(xiàn)實(shí)中經(jīng)常被大家喜聞樂(lè)見(jiàn)的場(chǎng)景,一群大媽搶購(gòu)打折雞蛋的畫(huà)面一定不會(huì)陌生,如此場(chǎng)面讓服務(wù)員大姐很無(wú)奈,趕上不要錢(qián)了。

業(yè)務(wù)特點(diǎn)
- 瞬間高并發(fā)、電腦旁邊的小哥哥、小姐姐們?nèi)绯泻鍝尩拇髬屢话?,瘋狂的點(diǎn)著鼠標(biāo)
- 庫(kù)存少、便宜、稀缺限量,值得大家去搶購(gòu),如蘋(píng)果腎,小米粉,錘子粉(理解萬(wàn)歲)
用戶規(guī)模
用戶規(guī)??纱罂尚?,幾百或者上千人的活動(dòng)單體架構(gòu)足以可以應(yīng)付,簡(jiǎn)單的加鎖、進(jìn)程內(nèi)隊(duì)列就可以輕松搞定。一旦上升到百萬(wàn)、千萬(wàn)級(jí)別的規(guī)模就要考慮分布式集群來(lái)應(yīng)對(duì)瞬時(shí)高并發(fā)。
秒殺架構(gòu)

架構(gòu)層級(jí)
一般商家在做活動(dòng)的時(shí)候,經(jīng)常會(huì)遇到各種不懷好意的DDOS攻擊(利用無(wú)辜的吃瓜群眾奪取資源),導(dǎo)致真正的我們無(wú)法獲得服務(wù)!所以說(shuō)高防IP還是很有必要的。
搞活動(dòng)就意味著人多,接入SLB,對(duì)多臺(tái)云服務(wù)器進(jìn)行流量分發(fā),可以通過(guò)流量分發(fā)擴(kuò)展應(yīng)用系統(tǒng)對(duì)外的服務(wù)能力,通過(guò)消除單點(diǎn)故障提升應(yīng)用系統(tǒng)的可用性。
基于SLB價(jià)格以及靈活性考慮后面我們接入Nginx做限流分發(fā),來(lái)保障后端服務(wù)的正常運(yùn)行。
后端秒殺業(yè)務(wù)邏輯,基于Redis 或者 Zookeeper 分布式鎖,Kafka 或者 Redis 做消息隊(duì)列,DRDS數(shù)據(jù)庫(kù)中間件實(shí)現(xiàn)數(shù)據(jù)的讀寫(xiě)分離。
優(yōu)化思路
分流、分流、分流,重要的事情說(shuō)三遍,再牛逼的機(jī)器也抵擋不住高級(jí)別的并發(fā)。
限流、限流、限流,畢竟秒殺商品有限,防刷的前提下沒(méi)有絕對(duì)的公平,根據(jù)每個(gè)服務(wù)的負(fù)載能力,設(shè)定流量極限。
緩存、緩存、緩存、盡量不要讓大量請(qǐng)求穿透到DB層,活動(dòng)開(kāi)始前商品信息可以推送至分布式緩存。
異步、異步、異步,分析并識(shí)別出可以異步處理的邏輯,比如日志,縮短系統(tǒng)響應(yīng)時(shí)間。
主備、主備、主備,如果有條件做好主備容災(zāi)方案也是非常有必要的(參考某年錘子的活動(dòng)被攻擊)。
最后,為了支撐更高的并發(fā),追求更好的性能,可以對(duì)服務(wù)器的部署模型進(jìn)行優(yōu)化,部分請(qǐng)求走正常的秒殺流程,部分請(qǐng)求直接返回秒殺失敗,缺點(diǎn)是開(kāi)發(fā)部署時(shí)需要維護(hù)兩套邏輯。
分層優(yōu)化
- 前端優(yōu)化:活動(dòng)開(kāi)始前生成靜態(tài)商品頁(yè)面推送緩存和CDN,靜態(tài)文件(JS/CSS)請(qǐng)求推送至文件服務(wù)器和CDN。
- 網(wǎng)絡(luò)優(yōu)化:如果是全國(guó)用戶,最好是BGP多線機(jī)房,減少網(wǎng)絡(luò)延遲。
- 應(yīng)用服務(wù)優(yōu)化:Nginx最佳配置、Tomcat連接池優(yōu)化、數(shù)據(jù)庫(kù)配置優(yōu)化、數(shù)據(jù)庫(kù)連接池優(yōu)化。
全鏈路壓測(cè)
- 分析需壓測(cè)業(yè)務(wù)場(chǎng)景涉及系統(tǒng)
- 協(xié)調(diào)各個(gè)壓測(cè)系統(tǒng)資源并搭建壓測(cè)環(huán)境
- 壓測(cè)數(shù)據(jù)隔離以及監(jiān)控(響應(yīng)時(shí)間、吞吐量、錯(cuò)誤率等數(shù)據(jù)以圖表形式實(shí)時(shí)顯示)
- 壓測(cè)結(jié)果統(tǒng)計(jì)(平均響應(yīng)時(shí)間、平均吞吐量等數(shù)據(jù)以圖表形式在測(cè)試結(jié)束后顯示)
- 優(yōu)化單個(gè)系統(tǒng)性能、關(guān)聯(lián)流程以及整個(gè)業(yè)務(wù)流程
整個(gè)壓測(cè)優(yōu)化過(guò)程就是一個(gè)不斷優(yōu)化不斷改進(jìn)的過(guò)程,事先通過(guò)測(cè)試不斷發(fā)現(xiàn)問(wèn)題,優(yōu)化系統(tǒng),避免問(wèn)題,指定應(yīng)急方案,才能讓系統(tǒng)的穩(wěn)定性和性能都得到質(zhì)的提升。
代碼案例
可能秒殺架構(gòu)原理大家都懂,網(wǎng)上也有不少實(shí)現(xiàn)方式,但大多都是文字的描述,告訴你如何如何,什么加鎖、緩存、隊(duì)列之類。但很少全面有的案例告訴你如何去做,既然是從0到1,希望以下代碼案例可以幫助到你。當(dāng)然最終落實(shí)到生產(chǎn),還有很長(zhǎng)的路要走,要根據(jù)自己的業(yè)務(wù)進(jìn)行編碼,實(shí)施并部署。
你將會(huì)在代碼案例中學(xué)到以下知識(shí)(不定期補(bǔ)充):
- 如何大家SpringBoot微服務(wù)
- ThreadPoolExecutor線程池的使用
- ReentrantLock和Synchronized的使用場(chǎng)景
- 數(shù)據(jù)庫(kù)鎖機(jī)制(悲觀鎖、樂(lè)觀鎖)
- 分布式鎖(RedissLock、Zookeeper)
- 進(jìn)程內(nèi)消息隊(duì)列(LinkedBlockingQueue、ArrayBlockingQueue、ConcurrentLinkedQueue)
- 分布式消息隊(duì)列(Redis、Kafka)
代碼結(jié)構(gòu):
├─src
│ ├─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─itstyle
│ │ │ └─seckill
│ │ │ │ Application.java
│ │ │ │
│ │ │ ├─common
│ │ │ │ ├─api
│ │ │ │ │ SwaggerConfig.java
│ │ │ │ │
│ │ │ │ ├─config
│ │ │ │ │ IndexController.java
│ │ │ │ │
│ │ │ │ ├─dynamicquery
│ │ │ │ │ DynamicQuery.java
│ │ │ │ │ DynamicQueryImpl.java
│ │ │ │ │ NativeQueryResultEntity.java
│ │ │ │ │
│ │ │ │ ├─entity
│ │ │ │ │ Result.java
│ │ │ │ │ Seckill.java
│ │ │ │ │ SuccessKilled.java
│ │ │ │ │
│ │ │ │ ├─enums
│ │ │ │ │ SeckillStatEnum.java
│ │ │ │ │
│ │ │ │ ├─interceptor
│ │ │ │ │ MyAdapter.java
│ │ │ │ │
│ │ │ │ └─redis
│ │ │ │ RedisConfig.java
│ │ │ │ RedisUtil.java
│ │ │ │
│ │ │ ├─distributedlock
│ │ │ │ ├─redis
│ │ │ │ │ RedissLockDemo.java
│ │ │ │ │ RedissLockUtil.java
│ │ │ │ │ RedissonAutoConfiguration.java
│ │ │ │ │ RedissonProperties.java
│ │ │ │ │
│ │ │ │ └─zookeeper
│ │ │ │ ZkLockUtil.java
│ │ │ │
│ │ │ ├─queue
│ │ │ │ ├─jvm
│ │ │ │ │ SeckillQueue.java
│ │ │ │ │ TaskRunner.java
│ │ │ │ │
│ │ │ │ ├─kafka
│ │ │ │ │ KafkaConsumer.java
│ │ │ │ │ KafkaSender.java
│ │ │ │ │
│ │ │ │ └─redis
│ │ │ │ RedisConsumer.java
│ │ │ │ RedisSender.java
│ │ │ │ RedisSubListenerConfig.java
│ │ │ │
│ │ │ ├─repository
│ │ │ │ SeckillRepository.java
│ │ │ │
│ │ │ ├─service
│ │ │ │ │ ISeckillDistributedService.java
│ │ │ │ │ ISeckillService.java
│ │ │ │ │
│ │ │ │ └─impl
│ │ │ │ SeckillDistributedServiceImpl.java
│ │ │ │ SeckillServiceImpl.java
│ │ │ │
│ │ │ └─web
│ │ │ SeckillController.java
│ │ │ SeckillDistributedController.java
│ │ │
│ │ ├─resources
│ │ │ │ application.properties
│ │ │ │ logback-spring.xml
│ │ │ │
│ │ │ ├─sql
│ │ │ │ seckill.sql
│ │ │ │
│ │ │ ├─static
│ │ │ └─templates
│ │ └─webapp
思考改進(jìn)
- 如何防止單個(gè)用戶重復(fù)秒殺下單?
- 如何防止惡意調(diào)用秒殺接口?
- 如果用戶秒殺成功,一直不支付該怎么辦?
- 消息隊(duì)列處理完成后,如果異步通知給用戶秒殺成功?
- 如何保障 Redis、Zookeeper 、Kafka 服務(wù)的正常運(yùn)行(高可用)?
- 高并發(fā)下秒殺業(yè)務(wù)如何做到不影響其他業(yè)務(wù)(隔離性)?
碼云下載:從0到1構(gòu)建分布式秒殺系統(tǒng),脫離案例講架構(gòu)都是耍流氓