文章網址:秒杀系统架构优化思路
前些日子有許多買票秒殺的案例,此文章為了解如何解決掉這類問題。以搶五月天搶票或連續假日搶車票為例,往往一開賣就馬上賣光,慘一點甚至系統直接掛掉。 文中提出的第一個關鍵點是把Request卡在最上游,第二是增加緩存,緩存最常見於讀多寫少的狀況,賣票系統便是一個常見的例子。 以常見的系統架構為例: Browser>站點>服務層>Database
Browser(Client): 能在瀏覽器的HTML Button寫入按一次就把它default(灰階)掉,第二個是在Java Script寫入每按一次經過N秒才能再執行該Function,但這是一個防君子不防小人的做法,遇到不乖的Programmer只要透過程式寫無窮迴圈,不走你Browser你也擋不住。
站點: 上述提到如果遇到Programmer就無法解,因此能在Web Server端增加一個暫存,記錄使用者的UID和它的請求次數來去除重複,更簡單一點的做法是設定一個UID每幾秒(5秒)能請求一次。第二個做法是善用頁面緩存,如在幾秒內到達站點的均返回同一個頁面(用時間間隔),只要不丟404的話對使用者都是良好的用戶體驗,又能增加系統的可用性。缺點是如果是多台Server可能會有頁面不一致的狀況,優化方法能在nginx上做七層均衡,讓UID盡量落在同一台機器上。不過從這整套架構來說,最大的Loading在這層,但可以透過增加服務機器,或乾脆直接拋棄那些過多的請求。原則就是保護系統,不能讓所有用戶失敗。另外如果駭客手中有N台肉雞,那要怎麼解決呢?
服務層: 對整個架構來說,Web Service是最接近Database的一層,它能了解業務的上限,舉車票來說,它知道該列火車只有200個座位,那就把它限制在我能賣兩百個座位就好,做法很簡單,那就是用一個請求對列,我把對列限制在數量的上限,每次就開放那麼多個Connection去對資料庫做寫入的動作就好,如果都成功在放下一批去寫,而讀的請求則用Cache,將Cache裡的資料先回傳給上層,不然就是做業務上的優化,例如每幾分鐘僅開放幾個Request訂票,問題是在於說東西只要正確的賣出去(沒有超賣,沒有少賣),另外如有多台機器想用同一個隊列會造成複雜度!然後是業務邏輯的異步,像是支付與訂票系統分離,以上這些步驟,關鍵是不要讓它到Database!降低Database的Loading!
Database: 其實到這邊該擋的都能擋住了,綜上所敘,最害怕的就是DB掛掉而已,回想到業務面,假設有一百萬個請求,而這一百萬個成功率全為零,和兩千個請求兩千個都成功,想當然爾,後者較有意義。另外是回倉,如果訂票之後使用者還沒支付錢可將數量恢復(如45分鐘內)。
額外補充: 1.有一設計要點是Fail Fast,如果不是重要的數據,就讓他直接失敗吧! 2.如果是大型系統,可善用垂直分拆(業務分割)。 3.用戶層面必須要做到同步,但Web Service依業務需求可做異步就好。