如何設(shè)計一個秒殺系統(tǒng)--讀后感

前言

最近一段時間,在極客時間專欄看了許令波大佬的《如何設(shè)計一個秒殺系統(tǒng)》,感受良多,今天記錄一下自己的收獲。大佬還有一本書《深入分析java web技術(shù)內(nèi)幕》,寫的很不錯,有興趣的可以去看一下。

正文

秒殺系統(tǒng)我沒寫過,公司也沒有業(yè)務(wù)場景去給我實現(xiàn),所以我就談一談收獲。知道方向在哪,真正有需要開發(fā)秒殺場景的那一天,才不會慌不擇路,游刃有余。

一. 動靜分離

秒殺提到的動靜分離,從最近幾年前后端分離發(fā)展的趨勢來看,動靜分離已經(jīng)是常態(tài)了,前端頁面部署CDN也是很常見的事情?,F(xiàn)在的頁面,異步請求已經(jīng)是標配,后端開發(fā)人員也不需要去關(guān)心前端頁面的資源占用問題,用戶在使用的時候,也不會頻繁的刷新整個頁面,可以說這是一個行業(yè)的進步。

當然,動靜分離之后也很考驗后端開發(fā)人員的接口設(shè)計能力,在開發(fā)之前定義頁面接口的時候,需要知道這個頁面的接口需要定義幾個,哪些數(shù)據(jù)和哪些數(shù)據(jù)需要隔離開,哪些數(shù)據(jù)需要合并到一個接口里去處理。我覺得這是一個開發(fā)人員在獨立開發(fā)一個模塊必須具備的能力。優(yōu)秀的接口設(shè)計會讓整個模塊更加的健壯,代碼更加具備可讀性,在需求迭代的時候也會減少二次開發(fā)的工作量。

二.緩存

緩存是個好東西,說的直白一點就是為了減輕數(shù)據(jù)庫的壓力,提高用戶的響應(yīng)效率。數(shù)據(jù)庫連接資源是很寶貴的,比如一些更新不頻繁的信息,放在緩存里,能大幅度提高系統(tǒng)的并發(fā)量。

但是我們都清楚一點,中間件固然給我們解決了一部分問題,但是也給我們帶來了一部分問題。關(guān)于緩存,我們大多數(shù)情況只需要考慮一點,就是緩存一致性的問題。

曾經(jīng)思考過一個問題,比如更新一個商品信息的時候,怎么保證緩存的一致性是最簡單,方便,有效的方法。

2.1更新的時候保證緩存的數(shù)據(jù)同步更新,這里有兩種方案:

  • 先更新數(shù)據(jù)庫,再更新緩存,如果緩存更新失敗,數(shù)據(jù)就不一致了。

  • 先更新緩存,再更新數(shù)據(jù)庫,如果更新數(shù)據(jù)庫失敗,數(shù)據(jù)還是不一致。

所以這種方案一般不建議采用

2.2更新數(shù)據(jù)庫并刪除緩存,這里有兩種方案:

  • 先更新數(shù)據(jù)庫,再刪除緩存,如果緩存刪除失敗,數(shù)據(jù)就不一致了。

  • 先刪除緩存,再更新數(shù)據(jù)庫,更新數(shù)據(jù)庫失敗,這種就沒啥問題了,只是多了一次cache miss。

其實上述方案還是有問題的,在高并發(fā)場景下,假如一個線程A刪除了緩存之后,線程B觸發(fā)了一次cache miss,往緩存寫入了舊值,線程A再更新,還是會有不一致的問題。如果你的系統(tǒng)并發(fā)量不是很大,可以先刪除緩存,再更新數(shù)據(jù)庫,再刪除緩存,也就是刪除兩次緩存,這么基本就沒什么問題了。但是高并發(fā)場景下還是會有緩存不一致的場景,大家可以自己思考一下。

其實一般的業(yè)務(wù)系統(tǒng),做到這一步就沒啥問題了,我們要根據(jù)業(yè)務(wù)場景,在系統(tǒng)健壯性和開發(fā)工作量和難度中間做一個權(quán)衡。為了彌補千分之一甚至萬分之一的出錯概率,花十倍的人力物力去維護,就看業(yè)務(wù)上有沒有必要了。

2.3如果需要確保強一致性:

如果需要確保強一致性,可以參考阿里的做法,用canal監(jiān)控mysql的binlog,然后解析update,delete語句,再通知緩存去刪除相應(yīng)的key。當然,刪除就可能失敗,為了這個可能,需要設(shè)計一個消息隊列,刪除失敗的放入消息隊列里。直到刪除成功。假如你們的數(shù)據(jù)庫有主從分離,還會帶來一系列的問題,你這個binlog監(jiān)控的是主庫的還是從庫的,如果是從庫,從庫有好幾個,你到底用哪個從庫的。那么這么方案怎么來優(yōu)化,這里我就不說答案了,大家可以自己去尋找一下解決方案。

2.4緩存高可用

緩存高可用分為水平擴展和垂直擴展,水平擴展優(yōu)于垂直擴展,具體的自行百度吧。

三。系統(tǒng)高可用

這里我就直接copy許令波大佬的總結(jié),總結(jié)的很詳細。

具體來說,系統(tǒng)的高可用建設(shè)涉及架構(gòu)階段、編碼階段、測試階段、發(fā)布階段、運行階段,以及故障發(fā)生時。接下來,我們分別看一下。

  1. 架構(gòu)階段:架構(gòu)階段主要考慮系統(tǒng)的可擴展性和容錯性,要避免系統(tǒng)出現(xiàn)單點問題。例如多機房單元化部署,即使某個城市的某個機房出現(xiàn)整體故障,仍然不會影響整體網(wǎng)站的運轉(zhuǎn)。

  2. 編碼階段:編碼最重要的是保證代碼的健壯性,例如涉及遠程調(diào)用問題時,要設(shè)置合理的超時退出機制,防止被其他系統(tǒng)拖垮,也要對調(diào)用的返回結(jié)果集有預(yù)期,防止返回的結(jié)果超出程序處理范圍,最常見的做法就是對錯誤異常進行捕獲,對無法預(yù)料的錯誤要有默認處理結(jié)果。

  3. 測試階段:測試主要是保證測試用例的覆蓋度,保證最壞情況發(fā)生時,我們也有相應(yīng)的處理流程。

  4. 發(fā)布階段:發(fā)布時也有一些地方需要注意,因為發(fā)布時最容易出現(xiàn)錯誤,因此要有緊急的回滾機制。

  5. 運行階段:運行時是系統(tǒng)的常態(tài),系統(tǒng)大部分時間都會處于運行態(tài),運行態(tài)最重要的是對系統(tǒng)的監(jiān)控要準確及時,發(fā)現(xiàn)問題能夠準確報警并且報警數(shù)據(jù)要準確詳細,以便于排查問題。

  6. 故障發(fā)生:故障發(fā)生時首先最重要的就是及時止損,例如由于程序問題導致商品價格錯誤,那就要及時下架商品或者關(guān)閉購買鏈接,防止造成重大資產(chǎn)損失。然后就是要能夠及時恢復(fù)服務(wù),并定位原因解決問題。

這些都是思想,我們可以不會搞,但是一定要知道,當前系統(tǒng)瓶頸以后,我們下一步的發(fā)展方向是什么。

總結(jié)

看似是一個秒殺系統(tǒng)的專欄。其實處處是學問。我覺得秒殺基本上是高并發(fā)的巔峰了。一個系統(tǒng)在走向巔峰的路上,會有一系列的改造方案,高樓大廈也是平地起。我們需要學習的是了解系統(tǒng)優(yōu)化的一個方向,當我們自己的系統(tǒng)需要優(yōu)化的時候,我們可以用最少的工作量,最少的時間成本和物力成本去實現(xiàn)優(yōu)化最大化。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容