日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

12306 的技术扒光在你面前,100 万人如何抢 1 万张票

發布時間:2024/8/23 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 12306 的技术扒光在你面前,100 万人如何抢 1 万张票 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
戳藍字“CSDN云計算”關注我們哦!
作者 |? ?IT牧場
責編 | 阿禿

12306 搶票,極限并發帶來的思考

每到節假日期間,一二線城市返鄉、外出游玩的人們幾乎都面臨著一個問題:搶火車票!雖然現在大多數情況下都能訂到票,但是放票瞬間即無票的場景,相信大家都深有體會。

尤其是春節期間,大家不僅使用 12306,還會考慮“智行”和其他的搶票軟件,全國上下幾億人在這段時間都在搶票。“12306 服務”承受著這個世界上任何秒殺系統都無法超越的 QPS,上百萬的并發再正常不過了!

筆者專門研究了一下“12306”的服務端架構,學習到了其系統設計上很多亮點,在這里和大家分享一下并模擬一個例子:如何在 100 萬人同時搶 1 萬張火車票時,系統提供正常、穩定的服務。

Github代碼地址:

1. 大型高并發系統架構

高并發的系統架構都會采用分布式集群部署,服務上層有著層層負載均衡,并提供各種容災手段(雙火機房、節點容錯、服務器災備等)保證系統的高可用,流量也會根據不同的負載能力和配置策略均衡到不同的服務器上。下邊是一個簡單的示意圖:

1.1 負載均衡簡介


上圖中描述了用戶請求到服務器經歷了三層的負載均衡,下邊分別簡單介紹一下這三種負載均衡。
①OSPF(開放式最短鏈路優先)是一個內部網關協議(Interior Gateway Protocol,簡稱?IGP)

OSPF 通過路由器之間通告網絡接口的狀態來建立鏈路狀態數據庫,生成最短路徑樹,OSPF 會自動計算路由接口上的 Cost 值,但也可以通過手工指定該接口的 Cost 值,手工指定的優先于自動計算的值。OSPF 計算的 Cost,同樣是和接口帶寬成反比,帶寬越高,Cost 值越小。到達目標相同 Cost 值的路徑,可以執行負載均衡,最多 6 條鏈路同時執行負載均衡。

②LVS (Linux Virtual Server)

它是一種集群(Cluster)技術,采用 IP 負載均衡技術和基于內容請求分發技術。調度器具有很好的吞吐率,將請求均衡地轉移到不同的服務器上執行,且調度器自動屏蔽掉服務器的故障,從而將一組服務器構成一個高性能的、高可用的虛擬服務器。

③Nginx

想必大家都很熟悉了,是一款非常高性能的 HTTP 代理/反向代理服務器,服務開發中也經常使用它來做負載均衡。Nginx 實現負載均衡的方式主要有三種:輪詢、加權輪詢、IP Hash 輪詢。

下面我們就針對 Nginx 的加權輪詢做專門的配置和測試。

1.2 Nginx 加權輪詢的演示


Nginx 實現負載均衡通過 Upstream 模塊實現,其中加權輪詢的配置是可以給相關的服務加上一個權重值,配置的時候可能根據服務器的性能、負載能力設置相應的負載。
下面是一個加權輪詢負載的配置,我將在本地的監聽 3001-3004 端口,分別配置 1,2,3,4 的權重:

我在本地?/etc/hosts 目錄下配置了 www.load_balance.com 的虛擬域名地址。 接下來使用 Go 語言開啟四個 HTTP 端口監聽服務,下面是監聽在 3001 端口的 Go 程序,其他幾個只需要修改端口即可:

我將請求的端口日志信息寫到了 ./stat.log 文件當中,然后使用 AB 壓測工具做壓測:

統計日志中的結果,3001-3004 端口分別得到了 100、200、300、400?的請求量。這和我在 Nginx 中配置的權重占比很好的吻合在了一起,并且負載后的流量非常的均勻、隨機。
具體的實現大家可以參考 Nginx 的 Upsteam 模塊實現源碼,這里推薦一篇文章《Nginx 中 Upstream 機制的負載均衡》:


2. 秒殺搶購系統選型


回到我們最初提到的問題中來:火車票秒殺系統如何在高并發情況下提供正常、穩定的服務呢?
從上面的介紹我們知道用戶秒殺流量通過層層的負載均衡,均勻到了不同的服務器上,即使如此,集群中的單機所承受的 QPS 也是非常高的。如何將單機性能優化到極致呢?
要解決這個問題,我們就要想明白一件事:通常訂票系統要處理生成訂單、減扣庫存、用戶支付這三個基本的階段。我們系統要做的事情是要保證火車票訂單不超賣、不少賣,每張售賣的車票都必須支付才有效,還要保證系統承受極高的并發。

這三個階段的先后順序該怎么分配才更加合理呢?我們來分析一下:

2.1 下單減庫存



當用戶并發請求到達服務端時,首先創建訂單,然后扣除庫存,等待用戶支付。這種順序是我們一般人首先會想到的解決方案,這種情況下也能保證訂單不會超賣,因為創建訂單之后就會減庫存,這是一個原子操作。
但是這樣也會產生一些問題:

  • 在極限并發情況下,任何一個內存操作的細節都至關影響性能,尤其像創建訂單這種邏輯,一般都需要存儲到磁盤數據庫的,對數據庫的壓力是可想而知的。

  • 如果用戶存在惡意下單的情況,只下單不支付這樣庫存就會變少,會少賣很多訂單,雖然服務端可以限制 IP 和用戶的購買訂單數量,這也不算是一個好方法。

2.2 支付減庫存


如果等待用戶支付了訂單在減庫存,第一感覺就是不會少賣。但是這是并發架構的大忌,因為在極限并發情況下,用戶可能會創建很多訂單。

當庫存減為零的時候很多用戶發現搶到的訂單支付不了了,這也就是所謂的“超賣”。也不能避免并發操作數據庫磁盤 IO。

2.3 預扣庫存

從上邊兩種方案的考慮,我們可以得出結論:只要創建訂單,就要頻繁操作數據庫 IO。
那么有沒有一種不需要直接操作數據庫 IO 的方案呢,這就是預扣庫存。先扣除了庫存,保證不超賣,然后異步生成用戶訂單,這樣響應給用戶的速度就會快很多;那么怎么保證不少賣呢?用戶拿到了訂單,不支付怎么辦?我們都知道現在訂單都有有效期,比如說用戶五分鐘內不支付,訂單就失效了,訂單一旦失效,就會加入新的庫存,這也是現在很多網上零售企業保證商品不少賣采用的方案。
訂單的生成是異步的,一般都會放到 MQ、Kafka 這樣的即時消費隊列中處理,訂單量比較少的情況下,生成訂單非???#xff0c;用戶幾乎不用排隊。

3. 扣庫存的藝術


從上面的分析可知,顯然預扣庫存的方案最合理。我們進一步分析扣庫存的細節,這里還有很大的優化空間,庫存存在哪里?怎樣保證高并發下,正確的扣庫存,還能快速的響應用戶請求?
在單機低并發情況下,我們實現扣庫存通常是這樣的:

為了保證扣庫存和生成訂單的原子性,需要采用事務處理,然后取庫存判斷、減庫存,最后提交事務,整個流程有很多 IO,對數據庫的操作又是阻塞的。這種方式根本不適合高并發的秒殺系統。

接下來我們對單機扣庫存的方案做優化:本地扣庫存。我們把一定的庫存量分配到本地機器,直接在內存中減庫存,然后按照之前的邏輯異步創建訂單。改進過之后的單機系統是這樣的:

這樣就避免了對數據庫頻繁的 IO 操作,只在內存中做運算,極大的提高了單機抗并發的能力。
但是百萬的用戶請求量單機是無論如何也抗不住的,雖然 Nginx 處理網絡請求使用 Epoll 模型,c10k 的問題在業界早已得到了解決。但是 Linux 系統下,一切資源皆文件,網絡請求也是這樣,大量的文件描述符會使操作系統瞬間失去響應。
上面我們提到了 Nginx 的加權均衡策略,我們不妨假設將 100W 的用戶請求量平均均衡到 100 臺服務器上,這樣單機所承受的并發量就小了很多。然后我們每臺機器本地庫存 100 張火車票,100?臺服務器上的總庫存還是?1 萬,這樣保證了庫存訂單不超賣,下面是我們描述的集群架構:


問題接踵而至,在高并發情況下,現在我們還無法保證系統的高可用,假如這 100?臺服務器上有兩三臺機器因為扛不住并發的流量或者其他的原因宕機了。那么這些服務器上的訂單就賣不出去了,這就造成了訂單的少賣。
要解決這個問題,我們需要對總訂單量做統一的管理,這就是接下來的容錯方案。服務器不僅要在本地減庫存,另外要遠程統一減庫存。有了遠程統一減庫存的操作,我們就可以根據機器負載情況,為每臺機器分配一些多余的“Buffer 庫存”用來防止機器中有機器宕機的情況。我們結合下面架構圖具體分析一下:

我們采用 Redis 存儲統一庫存,因為 Redis 的性能非常高,號稱單機 QPS 能抗 10W 的并發。在本地減庫存以后,如果本地有訂單,我們再去請求 Redis 遠程減庫存,本地減庫存和遠程減庫存都成功了,才返回給用戶搶票成功的提示,這樣也能有效的保證訂單不會超賣。當機器中有機器宕機時,因為每個機器上有預留的 Buffer 余票,所以宕機機器上的余票依然能夠在其他機器上得到彌補,保證了不少賣。
Buffer 余票設置多少合適呢,理論上 Buffer 設置的越多,系統容忍宕機的機器數量就越多,但是 Buffer 設置的太大也會對 Redis 造成一定的影響。雖然 Redis 內存數據庫抗并發能力非常高,請求依然會走一次網絡 IO,其實搶票過程中對 Redis 的請求次數是本地庫存和 Buffer 庫存的總量。因為當本地庫存不足時,系統直接返回用戶“已售罄”的信息提示,就不會再走統一扣庫存的邏輯。這在一定程度上也避免了巨大的網絡請求量把 Redis 壓跨,所以 Buffer 值設置多少,需要架構師對系統的負載能力做認真的考量。

4. 代碼演示


Go 語言原生為并發設計,我采用 Go 語言給大家演示一下單機搶票的具體流程。

4.1 初始化工作


Go 包中的 Init 函數先于 Main 函數執行,在這個階段主要做一些準備性工作。
我們系統需要做的準備工作有:初始化本地庫存、初始化遠程 Redis 存儲統一庫存的 Hash 鍵值、初始化 Redis 連接池。另外還需要初始化一個大小為 1 的 Int 類型 Chan,目的是實現分布式鎖的功能。也可以直接使用讀寫鎖或者使用 Redis 等其他的方式避免資源競爭,但使用 Channel 更加高效,這就是 Go 語言的哲學:不要通過共享內存來通信,而要通過通信來共享內存。
Redis 庫使用的是 Redigo,下面是代碼實現:

4.2 本地扣庫存和統一扣庫存


本地扣庫存邏輯非常簡單,用戶請求過來,添加銷量,然后對比銷量是否大于本地庫存,返回 Bool 值:

注意這里對共享數據 LocalSalesVolume 的操作是要使用鎖來實現的,但是因為本地扣庫存和統一扣庫存是一個原子性操作,所以在最上層使用 Channel 來實現,這塊后邊會講。
統一扣庫存操作 Redis,因為 Redis 是單線程的,而我們要實現從中取數據,寫數據并計算一些列步驟,我們要配合 Lua 腳本打包命令,保證操作的原子性:

我們使用 Hash 結構存儲總庫存和總銷量的信息,用戶請求過來時,判斷總銷量是否大于庫存,然后返回相關的 Bool 值。

在啟動服務之前,我們需要初始化 Redis 的初始庫存信息:

4.3 響應用戶信息


我們開啟一個 HTTP 服務,監聽在一個端口上:

上面我們做完了所有的初始化工作,接下來 handleReq 的邏輯非常清晰,判斷是否搶票成功,返回給用戶信息就可以了。

前邊提到我們扣庫存時要考慮競態條件,我們這里是使用 Channel 避免并發的讀寫,保證了請求的高效順序執行。我們將接口的返回信息寫入到了 ./stat.log 文件方便做壓測統計。

4.4 單機服務壓測

開啟服務,我們使用 AB 壓測工具進行測試:

下面是我本地低配 Mac 的壓測信息:

根據指標顯示,我單機每秒就能處理 4000+ 的請求,正常服務器都是多核配置,處理 1W+ 的請求根本沒有問題。
而且查看日志發現整個服務過程中,請求都很正常,流量均勻,Redis 也很正常:

總結回顧


總體來說,秒殺系統是非常復雜的。我們這里只是簡單介紹模擬了一下單機如何優化到高性能,集群如何避免單點故障,保證訂單不超賣、不少賣的一些策略,完整的訂單系統還有訂單進度的查看,每臺服務器上都有一個任務,定時的從總庫存同步余票和庫存信息展示給用戶,還有用戶在訂單有效期內不支付,釋放訂單,補充到庫存等等。
我們實現了高并發搶票的核心邏輯,可以說系統設計的非常的巧妙,巧妙的避開了對 DB 數據庫 IO 的操作。對 Redis 網絡 IO 的高并發請求,幾乎所有的計算都是在內存中完成的,而且有效的保證了不超賣、不少賣,還能夠容忍部分機器的宕機。
我覺得其中有兩點特別值得學習總結:
①負載均衡,分而治之

通過負載均衡,將不同的流量劃分到不同的機器上,每臺機器處理好自己的請求,將自己的性能發揮到極致。這樣系統的整體也就能承受極高的并發了,就像工作的一個團隊,每個人都將自己的價值發揮到了極致,團隊成長自然是很大的。

②合理的使用并發和異步
自 Epoll 網絡架構模型解決了 c10k 問題以來,異步越來越被服務端開發人員所接受,能夠用異步來做的工作,就用異步來做,在功能拆解上能達到意想不到的效果。這點在 Nginx、Node.JS、Redis 上都能體現,他們處理網絡請求使用的 Epoll 模型,用實踐告訴了我們單線程依然可以發揮強大的威力。服務器已經進入了多核時代,Go 語言這種天生為并發而生的語言,完美的發揮了服務器多核優勢,很多可以并發處理的任務都可以使用并發來解決,比如 Go 處理 HTTP 請求時每個請求都會在一個 Goroutine 中執行??傊?#xff0c;怎樣合理的壓榨 CPU,讓其發揮出應有的價值,是我們一直需要探索學習的方向。




福利 掃描添加小編微信,備注“姓名+公司職位”,入駐【CSDN博客】,加入【云計算學習交流群】,和志同道合的朋友們共同打卡學習!


推薦閱讀:

總結

以上是生活随笔為你收集整理的12306 的技术扒光在你面前,100 万人如何抢 1 万张票的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 在线观看麻豆 | 国产日韩一区二区三免费高清 | 日日夜夜天天干 | 爱情岛论坛成人av | 国产高潮国产高潮久久久91 | 久久免费看少妇高潮 | 欧美一区二区三区粗大 | 国产欧美视频在线观看 | 爱爱小视频网站 | 成人亚洲天堂 | 国产成人精品一区二区三区无码熬 | 天天天干干干 | 欧美另类z0zx974| 久久久精品免费视频 | 午夜在线观看视频 | 少妇被又大又粗又爽毛片久久黑人 | 麻豆精品国产传媒av | 激情成人av | 免费一级特黄3大片视频 | 亚洲吧 | 精品人妻久久久久久888不卡 | 黄网地址 | 日本黄色片一级 | 色爱五月天 | 中文字幕人成乱码熟女香港 | 欧美日韩视频免费 | 天天高潮夜夜爽 | 天天摸夜夜添狠狠添婷婷 | 亚洲一区中文 | 亚洲精品成人网 | 特黄色一级片 | 日韩在线影院 | 亚洲精品人妻无码 | 国产黄色免费看 | 成人羞羞网站 | 性久久久久久 | 精品少妇人妻av一区二区三区 | 亚洲春色av | 欧美视频a | 国产男女啪啪 | 国产91在线亚洲 | 911亚洲精选 | 午夜视频免费看 | 国产一av| 久久无毛| 狠狠操女人 | 亚洲一二三不卡 | 亚洲精品不卡 | 久久综合成人网 | 亚洲乱码日产精品bd在线观看 | 婷婷亚洲综合 | 免费色播 | 午夜视频免费看 | 国产成人免费在线 | 手机在线亚洲 | 91搞| 国产sm主人调教女m视频 | 丝袜淫脚 | 亚洲国产第一 | 在线观看黄色网 | 亚洲午夜精品一区二区三区 | 98视频在线| 国产视频手机在线播放 | 夜色一区| 白白色在线观看 | 成人午夜精品 | 日韩123| 91极品身材尤物theporn | 青青草激情 | 久久精品国产精品 | 国产成人av在线播放 | 成人做爰黄 | 日批视频网站 | aaa一区二区 | 青青草偷拍视频 | 一区二区三区高清不卡 | 黄色片高清| 大度亲吻原声视频在线观看 | 国产九色sp调教91 | 艳妇乳肉豪妇荡乳av无码福利 | 亚洲a中文字幕 | 男人日女人逼 | 久久久久精彩视频 | 一区视频 | 国产福利视频在线观看 | 国产9区 | 日韩成人无码 | 免费v片在线观看 | 国模小黎自慰gogo人体 | 亚洲性欧美 | 亚洲精品成人a | 欧美 日韩 国产在线 | 国产精品美女网站 | 日韩精品四区 | 日韩在线免费看 | 久久精品视频9 | 欧美视频xxx | 日本午夜电影网站 | 国产日韩一区二区在线观看 |