面試被問到秒殺系統,這個點你一定得答到,輕鬆征服面試官

2019-07-13     IT技術分享
\t本文來源:搜雲庫\t

概述

在面試被問到系統設計這塊時候,秒殺系統經常是一個熱門考點。 今天我們就討論一下其中的重要一點: 如何進行秒殺系統的流量銷鋒?

如果你看過秒殺系統的流量監控圖的話,你會發現它是一條直線,就在秒殺開始那一秒是一條很直很直的線,這是因為秒殺請求在時間上高度集中於某一特定的時間點。

這樣一來,就會導致一個特別高的流量峰值,它對資源的消耗是瞬時的。

但是對秒殺這個場景來說,最終能夠搶到商品的人數是固定的,也就是說100人和10000人發起請求的結果都是一樣的,並發度越高,無效請求也越多。

但是從業務上來說,秒殺活動是希望更多的人來參與的,也就是開始之前希望有更多的人來刷頁面,但是真正開始下單時,秒殺請求並不是越多越好。

因此我們可以設計一些規則,讓並發的請求更多地延緩,而且我們甚至可以過濾掉一些無效請求。

為什麼要削峰?

為什麼要削峰呢?或者說峰值會帶來哪些壞處?

我們知道伺服器的處理資源是恆定的,你用或者不用它的處理能力都是一樣的,所以出現峰值的話,很容易導致忙到處理不過來,閒的時候卻又沒有什麼要處理。

但是由於要保證服務質量,我們的很多處理資源只能按照忙的時候來預估,而這會導致資源的一個浪費。

這就好比因為存在早高峰和晚高峰的問題,所以有了錯峰限行的解決方案。

削峰的存在,一是可以讓服務端處理變得更加平穩,二是可以節省伺服器的資源成本。

針對秒殺這一場景,削峰從本質上來說就是更多地延緩用戶請求的發出,以便減少和過濾掉一些無效請求,它遵從「請求數要儘量少」的原則。

今天,我就來介紹一下流量削峰的一些操作思路: 排隊、答題、分層過濾

這幾種方式都是無損(即不會損失用戶的發出請求)的實現方案,當然還有些有損的實現方案,包括我們後面要介紹的關於穩定性的一些辦法

比如限流和機器負載保護等一些強制措施也能達到削峰保護的目的,當然這都是不得已的一些措施,因此就不歸類到這裡了。

排隊

要對流量進行削峰,最容易想到的解決方案就是用消息隊列來緩衝瞬時流量,把同步的直接調用轉換成異步的間接推送,中間通過一個隊列在一端承接瞬時的流量洪峰,在另一端平滑地將消息推送出去。

在這裡,消息隊列就像「水庫」一樣,攔蓄上游的洪水,削減進入下遊河道的洪峰流量,從而達到減免洪水災害的目的。

用消息隊列來緩衝瞬時流量的方案,如下圖所示:

用消息隊列來緩衝瞬時流量

但是,如果流量峰值持續一段時間達到了消息隊列的處理上限,例如本機的消息積壓達到了存儲空間的上限,消息隊列同樣也會被壓垮

這樣雖然保護了下游的系統,但是和直接把請求丟棄也沒多大的區別。就像遇到洪水爆發時,即使是有水庫恐怕也無濟於事。

除了消息隊列,類似的排隊方式還有很多,例如:

  1. 利用線程池加鎖等待也是一種常用的排隊方式;
  2. 先進先出、先進後出等常用的內存排隊算法的實現方式;
  3. 把請求序列化到文件中,然後再順序地讀文件(例如基於MySQL binlog的同步機制)來恢復請求等方式。

可以看到,這些方式都有一個共同特徵,就是把「 一步的操作 」變成「 兩步的操作 」,其中增加的一步操作用來起到緩衝的作用。

說到這裡你可能會說,這樣一來增加了訪問請求的路徑啊,並不符合我們介紹的「4要1不要」原則。

沒錯,的確看起來不太合理,但是如果不增加一個緩衝步驟,那麼在一些場景下系統很可能會直接崩潰,所以最終還是需要你做出妥協和平衡。

答題

你是否還記得,最早期的秒殺只是純粹地刷新頁面和點擊購買按鈕,它是後來才增加了答題功能的。

那麼,為什麼要增加答題功能呢?

這主要是為了增加購買的複雜度,從而達到兩個目的。

第一個目的是防止部分買家使用秒殺器在參加秒殺時作弊。2011年秒殺非常火的時候,秒殺器也比較猖獗,因而沒有達到全民參與和營銷的目的

所以系統增加了答題來限制秒殺器,增加答題後,下單的時間基本控制在2s後,秒殺器的下單比例也大大下降。答題頁面如下圖所示。

答題頁面

第二個目的其實就是延緩請求,起到對請求流量進行削峰的作用,從而讓系統能夠更好地支持瞬時的流量高峰。

這個重要的功能就是把峰值的下單請求拉長,從以前的1s之內延長到2s~10s。

這樣一來,請求峰值基於時間分片了。這個時間的分片對服務端處理並發非常重要,會大大減輕壓力。

而且,由於請求具有先後順序,靠後的請求到來時自然也就沒有庫存了,因此根本到不了最後的下單步驟,所以真正的並發寫就非常有限了。

這種設計思路目前用得非常普遍,如當年支付寶的「咻一咻」、微信的「搖一搖」都是類似的方式。

這裡,我重點說一下 秒殺答題的設計思路

秒殺答題

如上圖所示,整個秒殺答題的邏輯主要分為3部分。

  1. 題庫生成模塊
  2. 這個部分主要就是生成一個個問題和答案,其實題目和答案本身並不需要很複雜,重要的是能夠防止由機器來算出結果,即防止秒殺器來答題。
  3. 題庫的推送模塊
  4. 用於在秒殺答題前,把題目提前推送給詳情系統和交易系統。題庫的推送主要是為了保證每次用戶請求的題目是唯一的,目的也是防止答題作弊。
  5. 題目的圖片生成模塊
  6. 用於把題目生成為圖片格式,並且在圖片里增加一些干擾因素。這也同樣是為防止機器直接來答題,它要求只有人才能理解題目本身的含義。
  7. 這裡還要注意一點,由於答題時網絡比較擁擠,我們應該把題目的圖片提前推送到CDN上並且要進行預熱,不然的話當用戶真正請求題目時,圖片可能加載比較慢,從而影響答題的體驗。

其實真正答題的邏輯比較簡單,很好理解:當用戶提交的答案和題目對應的答案做比較,如果通過了就繼續進行下一步的下單邏輯,否則就失敗。

我們可以把問題和答案用下面這樣的key來進行MD5加密:

問題key:

userId+itemId+question_Id+time+PK

答案key:

userId+itemId+answer+PK

驗證的邏輯如下圖所示:

答題的驗證邏輯

注意,這裡面的驗證邏輯,除了驗證問題的答案以外,還包括用戶本身身份的驗證,例如是否已經登錄、用戶的Cookie是否完整、用戶是否重複頻繁提交等。

除了做正確性驗證,我們還可以對提交答案的時間做些限制,例如從開始答題到接受答案要超過1s,因為小於1s是人為操作的可能性很小,這樣也能防止機器答題的情況。

分層過濾

前面介紹的排隊和答題要麼是少發請求,要麼對發出來的請求進行緩衝

而針對秒殺場景還有一種方法,就是對請求進行分層過濾,從而過濾掉一些無效的請求。分層過濾其實就是採用「漏斗」式設計來處理請求的

如下圖所示

分層過濾

假如請求分別經過CDN、前台讀系統(如商品詳情系統)、後台系統(如交易系統)和資料庫這幾層,那麼:

  1. 大部分數據和流量在用戶瀏覽器或者CDN上獲取,這一層可以攔截大部分數據的讀取;
  2. 經過第二層(即前台系統)時數據(包括強一致性的數據)儘量得走Cache,過濾一些無效的請求;
  3. 再到第三層後台系統,主要做數據的二次檢驗,對系統做好保護和限流,這樣數據量和請求就進一步減少;
  4. 最後在數據層完成數據的強一致性校驗。

這樣就像漏斗一樣,儘量把數據量和請求量一層一層地過濾和減少了。

分層過濾的 核心思想 :在不同的層次儘可能地過濾掉無效請求,讓「漏斗」最末端的才是有效請求。而要達到這種效果,我們就必須對數據做分層的校驗。

分層校驗的基本原則是:

  1. 將動態請求的讀數據緩存(Cache)在Web端,過濾掉無效的數據讀;
  2. 對讀數據不做強一致性校驗,減少因為一致性校驗產生瓶頸的問題;
  3. 對寫數據進行基於時間的合理分片,過濾掉過期的失效請求;
  4. 對寫請求做限流保護,將超出系統承載能力的請求過濾掉;
  5. 對寫數據進行強一致性校驗,只保留最後有效的數據。

分層校驗的目的是:

在讀系統中,儘量減少由於一致性校驗帶來的系統瓶頸,但是儘量將不影響性能的檢查條件提前

如用戶是否具有秒殺資格、商品狀態是否正常、用戶答題是否正確、秒殺是否已經結束、是否非法請求、營銷等價物是否充足等;

在寫數據系統中,主要對寫的數據(如「庫存」)做一致性檢查,最後在資料庫層保證數據的最終準確性(如「庫存」不能減為負數)。

總結一下

今天,我介紹了如何在網站面臨大流量衝擊時進行請求的削峰,並主要介紹了削峰的3種處理方式:

  1. 一個是通過隊列來緩衝請求,即控制請求的發出;
  2. 一個是通過答題來延長請求發出的時間,在請求發出後承接請求時進行控制,最後再對不符合條件的請求進行過濾;
  3. 最後一種是對請求進行分層過濾。

其中,隊列緩衝方式更加通用,它適用於內部上下游系統之間調用請求不平緩的場景,由於內部系統的服務質量要求不能隨意丟棄請求,所以使用消息隊列能起到很好的削峰和緩衝作用。

而答題更適用於秒殺或者營銷活動等應用場景,在請求發起端就控制發起請求的速度,因為越到後面無效請求也會越多,所以配合後面介紹的分層攔截的方式,可以更進一步減少無效請求對系統資源的消耗。

分層過濾非常適合交易性的寫請求,比如減庫存或者拼車這種場景,在讀的時候需要知道還有沒有庫存或者是否還有剩餘空座位。但是由於庫存和座位又是不停變化的,所以讀的數據是否一定要非常準確呢?

其實不一定,你可以放一些請求過去,然後在真正減的時候再做強一致性保證,這樣既過濾一些請求又解決了強一致性讀的瓶頸。

不過,在削峰的處理方式上除了採用技術手段,其實還可以採用業務手段來達到一定效果

例如在零點開啟大促的時候由於流量太大導致支付系統阻塞,這個時候可以採用發放優惠券、發起抽獎活動等方式,將一部分流量分散到其他地方,這樣也能起到緩衝流量的作用。

需要的Java架構師方面的資料可以關注之後私信哈,回復「資料」領取免費架構視頻資料,記得要點贊轉發噢!!!

文章來源: https://twgreatdaily.com/zh-tw/cAiLf20BMH2_cNUgmMqA.html