今日看到一位大佬所寫的文章,感覺思路很清晰,所以記錄下來,以作後看。
一、秒殺帶來了什麼?
秒殺或搶購活動一般會經過【預約】【搶訂單】【支付】這3個大環節,而其中【搶訂單】這個環節是最考驗業務提供方的抗壓能力的。
搶訂單環節一般會帶來2個問題:
2、超賣 任何商品都會有數量上限,如何避免成功下訂單買到商品的人數不超過商品數量的上限,這是每個搶購活動都要面臨的難題。
二、如何解決?
首先,產品解決方案我們就不予討論了。我們只討論技術解決方案
1、前端 面對高併發的搶購活動,前端常用的三板斧是【擴容】【靜態化】【限流】
a:擴容 加機器,這是最簡單的方法,通過增加前端池的整體承載量來抗峰值。
b:靜態化 將活動頁面上的所有可以靜態的元素全部靜態化,並儘量減少動態元素。通過cdn來抗峰值。
c:限流 一般都會採用ip級別的限流,即針對某乙個ip,限制單位時間內發起請求數量。 或者活動入口的時候增加遊戲或者問題環節進行消峰操作。
d:有損服務 最後一招,在接近前端池承載能力的水位上限的時候,隨機拒絕部分請求來保護活動整體的可用性。
2、後端 那麼後端的資料庫在高併發和超賣下會遇到什麼問題呢?
主要會有如下3個問題:(主要討論寫的問題,讀的問題通過增加cache可以很容易的解決)
i: 首先mysql自身對於高併發的處理效能就會出現問題,一般來說,mysql的處理效能會隨著併發thread上公升而上公升,但是到了一定的併發度之後會出現明顯的拐點,之後一路下降,最終甚至會比單thread的效能還要差。
ii: 其次,超賣的根結在於減庫存操作是乙個事務操作,需要先select,然後insert,最後update -1。最後這個-1操作是不能出現負數的,但是當多使用者在有庫存的情況下併發操作,出現負數這是無法避免的。
iii:最後,當減庫存和高併發碰到一起的時候,由於操作的庫存數目在同一行,就會出現爭搶innodb行鎖的問題,導致出現互相等待甚至死鎖,從而大大降低mysql的處理效能,最終導致前端頁面出現超時異常。
針對上述問題,如何解決呢? 我們先看眼**的高大上解決方案:
i: 關閉死鎖檢測,提高併發處理效能。
ii:修改源**,將排隊提到進入引擎層前,降低引擎層面的併發度。
iii:組提交,降低server和引擎的互動次數,降低io消耗。
以上內容可以參考丁奇在dtcc2013上分享的《秒殺場景下mysql的低效》一文。在文中所有優化都使用後,tps在高併發下,從原始的150飆公升到8.5w,提公升近566倍,非常嚇人!!! 不過結合我們的實際,改原始碼這種高大上的解決方案顯然有那麼一點不切實際。於是小夥伴們需要討論出一種適合我們實際情況的解決方案。
以下就是我們討論的解決方案:
首先設定乙個前提,為了防止超賣現象,所有減庫存操作都需要進行一次減後檢查,保證減完不能等於負數。(由於mysql事務的特性,這種方法只能降低超賣的數量,但是不可能完全避免超賣)update number set x=x-1 where (x -1 ) >= 0;
解決方案1: 將存庫從mysql前移到redis中,所有的寫操作放到記憶體中,由於redis中不存在鎖故不會出現互相等待,並且由於redis的寫效能和讀效能都遠高於mysql,這就解決了高併發下的效能問題。然後通過佇列等非同步手段,將變化的資料非同步寫入到db中。 優點:解決效能問題 缺點:沒有解決超賣問題,同時由於非同步寫入db,存在某一時刻db和redis中資料不一致的風險。
解決方案2: 引入佇列,然後將所有寫db操作在單佇列中排隊,完全序列處理。當達到庫存閥值的時候就不在消費佇列,並關閉購買功能。這就解決了超賣問題。 優點:解決超賣問題,略微提公升效能。 缺點:效能受限於佇列處理機處理效能和db的寫入效能中最短的那個,另外多商品同時搶購的時候需要準備多條佇列。
解決方案3: 將寫操作前移到memcached中,同時利用memcached的輕量級的鎖機制cas來實現減庫存操作。 優點:讀寫在記憶體中,操作效能快,引入輕量級鎖之後可以保證同一時刻只有乙個寫入成功,解決減庫存問題。 缺點:沒有實測,基於cas的特性不知道高併發下是否會出現大量更新失敗?不過加鎖之後肯定對併發效能會有影響。
解決方案4: 將提交操作變成兩段式,先申請後確認。然後利用redis的原子自增操作(相比較mysql的自增來說沒有空洞),同時利用redis的事務特性來發號,保證拿到小於等於庫存閥值的號的人都可以成功提交訂單。然後資料非同步更新到db中。 優點:解決超賣問題,庫存讀寫都在記憶體中,故同時解決效能問題。 缺點:由於非同步寫入db,可能存在資料不一致。另可能存在少買,也就是如果拿到號的人不真正下訂單,可能庫存減為0,但是訂單數並沒有達到庫存閥值。
三、總結
1、前端三板斧【擴容】【限流】【靜態化】
2、後端兩條路【記憶體】+【排隊】
併發與高併發(二十)高併發 應用拆分思路
這一章節我們將講解高併發解決方案中的應用拆分思路,也可以稱之為系統拆分。單個伺服器再優化,它的處理都是有上限的,因此我們採用擴容 快取 訊息佇列等對程式進行優化,這些手段都可行,但還不是全部。隨著專案的需求要求越來越多,應用自然會跟著越來越大,因此呢,架構師設計出了特別容易擴充套件的方案,從整體將乙...
處理高併發的思路整理
1.垂直分層 dns分層 跨機房部署lvs nginx負載均衡,vanish 共享儲存實現動靜分離,nginx後掛載n態伺服器集群,伺服器集群後掛載服務化,微服務後掛載資料庫分庫分表 訊息佇列 任務排程,最後端掛載資料集群負責資料的統一歸檔 流計算 非同步批量處理 2.水平分割槽 根據業務劃分業務線...
關於php 高併發解決的一點思路
涉及搶購 秒殺 搶票等活動時,為了避免超賣,那麼庫存數量是有限的,但是如果同時下單人數超過了庫存數量,就會導致商品超賣問題。那麼我們怎麼來解決這個問題呢,我的思路如下 偽 sql1 查詢商品庫存 if 庫存數量 0 當沒有併發時,上面的流程看起來是再正常不過了,假設同時兩個人下單,而庫存只有1個了,...