- 秒殺系統部署
- 高併發項目整體架構部署(500萬日活項目部署)
- 大體先梳理項目中的技術點(結合實驗樓分析項目整體架構和技術點)
1, 秒殺系統架構
1.超賣問題
- 1000件商品
- 第一步查詢商品數量
- 查詢商品:A 讀 商品 1000 B 讀 商品 1000
- 扣減庫存:A : 1000-1 =999寫入數據庫,B:1000-1=999
- 賣了兩件商品,商品數量:999
2.樂觀鎖和悲觀鎖如何解決超賣問題的
- 悲觀鎖解決的原理
- A讀商品數量是1000,如果要是悲觀鎖,A讀完數量後商品就加鎖(排它鎖)了
- B過來商品數量,A加的鎖還沒有釋放,所以B要等待
- 只有當A賣完商品,商品數量減一,把商品數量爲 999重新寫入到數據庫才釋放鎖
- B獲得商品時商品數據量是999而不是1000
- 樂觀鎖解決的原理
- A讀商品數量是1000,如果要是樂觀鎖這一刻樂觀鎖沒有加鎖
- A進行商品扣減的時候會校驗,現在的商品數量是否和開始數量一致
- A扣減(排它鎖)之後要不999寫入到mysql中時會校驗商品數量是否是1000
- 和A剛開始讀的數據一致就寫入,不一致重試
2, 各層解決方案
1.網絡層 CDN
- 特點:CDN服務器不需安裝部署,不是一個真實的後端服務器,僅僅緩存了前端數據
- 作用:減輕源站的服務器壓力,對於國外訪問,可以更快速
- CDN不是把我們的服務部署在全世界各地(成本太高)
- CDN是靜態資源的緩存(JS,Html、Css、圖片、視頻),不會變
- 網站提供是一個後端API接口
- 你從沒過打開的商家的商品圖片來美國的一臺CDN服務器
- 但是請求的API接口,後端服務可能還是部署在中國
- 需要和數據庫動態交互的,CDN沒有任何作用
2.負載層(高可用)
-
問題:只能解決高併發,不能解決高可用
-
keepalive和lvs、haproxy有了解(解決高可用問題)
-
解決了單點故障
3, 五百萬日活整體架構
1.高併發常用的
-
PV(訪問量): 頁面訪問量,頁面刷新一次算一次。
-
UV(獨立訪客): 即Unique Visitor,一個客戶端(電腦,手機)爲一個訪客;
-
DAU(日活躍用戶數):登錄或使用了某個產品的用戶數,這與流量統計工具裏的訪客(UV)概念相似。
-
峯值QPS:
原理:每天80%的訪問集中在20%的時間裏,這20%時間叫做峯值時間
公式:( 總PV數 * 80% ) / ( 每天秒數 * 20% ) = 峯值時間每秒請求數(QPS)
- QPS/TPS(每秒查詢率):每秒能夠查詢次數(QPS/TPS= 併發數 / 平均響應時間)
併發數:併發數是指系統同時能處理的請求數量,這個也是反應了系統的負載能力。
吐吞量:吞吐量是指系統在單位時間內處理請求的數量
響應時間(RT):響應時間是指系統對請求作出響應的時間,一般取平均響應時間
2.django性能
- 4核8G的機器,正常每秒能處理200多請求(不能超過500)
- 每秒能處理的請求數量
4, 架構分析
1.QPS分析
四核8G機器部署django+uwsgi
開啓的進程數等於或略大約核數(最多不要超過1.5倍)
線程:每個洗衣機每次最多能洗的數量
處理一個需要1s,0.2
4*2= 8個/秒
processes = 4 # 開啓5個進程
threads = 50 # 每個進程最多開啓2個線程
200個線程,
1萬 兩萬
8÷0.2=40
2.SLB阿里雲
- SLB相當於一個keepalive多活集羣
3.500萬日活流量
- 如果直接讀mysql,流量會直接崩潰
- 把熱點數據先預加載到redis緩存中,先讀緩存,如果沒有就查詢數據庫,把查詢的數據加入緩存
- 頁面靜態化
- 大量的寫數據,寫入mysql(流量消峯)
- 延時,第二mysql沒有辦法一次處理這麼多併發連接
- 先寫數據庫的請求加入RabbitMQ,然後通過異步任務,一點點取出RabbitMQ的任務往mysql寫入
5, 高併發架構各層能做的事情
- 應用層
- 瀏覽器本地緩存:緩存靜態頁面、緩存加入購物車的數據
- 網絡層
- CDN緩存靜態資源:html/css/js/圖片
- 負載層(高併發、高可用)
- keepalive(haproxy)+nginx反向代理(騰訊雲LB、阿里雲的SLB)
- 服務層
- 動態頁面靜態化(比如Django的cache服務),減少查詢數據庫的次數
- 藉助redis緩存解決大量的mysql查詢壓力
- RabbitMQ+異步解決mysql的大量寫入問題
- 限流:
- 搶購:nginx設置了保護功能,當流量過大自動丟棄(負載層就丟棄了)(nginx過載保護)
- 同一個設備、賬號、出接口ip 一秒鐘最多訪問次數
- 數據庫層
- 解決超賣問題:樂觀鎖、悲觀鎖解決數據安全
- mysql一主多從,讀寫分離:寫主庫,讀從庫(所有數據庫的數據一樣)
- 數據一樣的,那麼當數據量太大的時候查詢還是很慢
- 分庫(根據用戶id分庫)
- 所有數據庫的表結構一樣,存儲的數據完全不一樣
- 真實環境以用戶id進行分庫,每一個庫的數據都很小,查詢起來就快了
- 無法解決問題:當一個數據庫中表中量過大的時候,查詢依然會慢
- 分表(根據時間分表)
- 當一個表中數據過大的時候,我們必須要對錶拆分
- 購物清單表中有兩千萬數據
- 最近半年的購物數據時 一百萬
- 半年到一年的數據有五百萬
- 一年以前的數據有一千萬