PHP秒殺系統全方位設計分析(二)

OldBoy~發表於2018-01-08

商品頁面開發
靜態化展示頁面[效率要比動態PHP高很多,PHP程式需要解析等步驟,本身就需要很多流程,整個下來PHP的處理花的時間和資源要多]
商品狀態的控制
開始前、進行中、庫存不足、結束
資料邏輯處理
大致流程:驗證使用者是否登入、驗證引數是否合法、驗證活動資訊狀態、驗證商品資訊狀態是否正常、驗證問題回答是否正確、驗證使用者是否已經購買、驗證使用者購買的商品數量是否在限制的範圍內、驗證商品庫存是否充足、扣除商品購買數量、建立訂單、返回提示資訊
保證資料一致性、高效處理

秒殺商品型別

單商品秒殺特點
簡單,沒有選擇、獨立
沒有關聯關係、容易
驗證邏輯更少

組合商品秒殺特點
支援多商品選擇
多商品庫存、限購數量
驗證和處理的邏輯多

秒殺級別

萬次秒殺
就是幾萬次請求,活動就結束,請求比較少,併發低,實現基本功能就可以滿足
不太需要考慮效能優化方面,這樣伺服器資源時間等成本節省
單機,比如PHP+Mysql資料庫放在一起,並且動態訪問,單臺就可以支援

百萬次秒殺
請求量和併發量都開始有明顯提升,需要做部分優化,系統架構、程式碼邏輯、伺服器等
WEB伺服器叢集,多臺伺服器
引入Redis快取,不能僅僅Mysql來應對更多的查詢
不能有嚴重的介面漏洞問題等低階錯誤
壓力測試,把所有介面高併發測試

過億次秒殺
所有問題都要極端化考慮,不管是在邏輯運算,及運算次數,多一次記憶體的分配,等等,哪些能優化,哪些能避免
沒遇到過的問題很可能發生,比如想象中極不可能發生的問題,伺服器當機,記憶體不夠等,我們也需要思考避免
需要能臨時調配大量的伺服器資源,平時準備大量的不現實也不合理,因為併發可能很短就結束。比如購買雲主機,在時間階段內利用,快速克隆部署執行,不需要的時候再釋放掉,在成本方面可以減少伺服器和資源型的依賴
引入中控伺服器(控制伺服器的伺服器)
多機房多資料中心 

 大概秒殺流程

在使用者在點選購買的時候,需要做一些安全性的引數驗證,大致包括活動標識、商品標識、要購買的商品數量、安全加密串、再比如問答驗證。在完成這些資訊的提交後,程式流程的大概驗證順序為:
驗證使用者是否登入->驗證加密簽名是否合理->驗證規定時間段內IP和使用者保持不變(如五分鐘,加密簽名裡包含使用者登入的時間還有IP,在使用者購買的時候提交和當前時間以及IP對比)->驗證問題回答是否正確->統一格式化一下購買的商品資訊(比如轉化為容易處理的陣列格式)->配合redis快取,驗證一下訂單是否已經購買過,防止重複購買->驗證活動、商品的狀態是否正常(比如是否賣完,是否還在賣等)->先更新快取中剩餘的商品數量,再更新資料庫扣除商品的數量->扣除成功後建立訂單資訊->建立完成訂單後設定快取用於已經購買

優化單機效能

 提高頁面訪問速度

減少頁面大小,啟用gzip壓縮
減少資源請求數量,合併和壓縮css、js
設定瀏覽器快取,利用CDN加速

 提高秒殺介面速度

因為效能方面幾個瓶頸,無非就是通過網路請求資料,網路速度是比較大的問題;另外通過磁碟讀寫檔案效能也比較低,那麼我們程式的時候,我們儘可能少用這種效能比較低的儲存裝置,比如記憶體,記憶體的速度要比磁碟快很多。當然還有更多方法....
介面靜態化
如果介面是PHP編寫的動態程式,效率肯定比靜態化的低很多,比如我們的首頁、商品展示頁面 ,是動態頁面的話,動態的效率再高,裡面包括很多效率高的處理方法,比如快取,就算再快,也會有開銷,也不如直接靜態化效率高。如果我們把頁面靜態化,效率會提高很多,Nginx對這種靜態檔案的訪問極其高的,一秒鐘一兩萬次不會存在很大的瓶頸,對於伺服器壓力來說,一秒鐘一兩萬次伺服器負載也是沒多大問題;但是我們用PHP寫的動態結果,一秒鐘一兩萬次肯定是不可以的,效能再好一秒鐘五六百次一千次效率也是很高的了。所以可以把介面做靜態化處理很快。比如,把首頁靜態化,生成靜態的index.html檔案就可以了,剩下只需要處理的一個地方就是登陸,基於cookie的方式儲存登陸狀態,cookie的解析是通過服務端來解析,而我們在這個環節需要改一下,頁面展示的登入狀態判斷不能通過伺服器端了,因為已經是一個靜態頁面了,這裡我們需要通過js來讀取cookie資訊,把這個狀態資訊通過js輸出出來就可以了。當然還有其他的介面,比如最重要的秒殺介面,我們肯定會想,這個介面肯定是一個動態的,如果是一個靜態的大家看到的結果是一樣的,那麼還怎麼進行秒殺?沒錯,秒殺介面肯定是一個動態的,按功能來講,如果是靜態的就是假的了,欺騙使用者。比如釋出了一款產品,整體下來大約是1000000次併發請求訪問,我們的實際要賣出的商品數量為1000個,那麼我們有必要全部的訪問都是動態的麼,有沒有想過前面1000個是動態訪問,後面的多餘訪問次數是靜態的1000000-1000次,那麼這樣多放幾臺伺服器,或者部署CDN,頻寬充足就好了。
快速終止的邏輯放在前面,先判斷條件,再執行後面的程式(比如面對一千萬個訪問,商品庫存有5000件,那麼商品賣完[10000000-5000個訪問不走程式邏輯]或者活動沒有進行等狀態直接訪問靜態檔案,和上一個差不多)
增加冗餘的定製化資料,保證程式更快捷。以空間換時間,比如增加新的資料結構,增加陣列,在儲存空間啊,記憶體啊,程式編寫的複雜度要求高一點,讓使用者更快速的訪問我們的介面。

提高資料處理速度

資料量大的時候,資料庫索引不能少,更不能亂。(資料量大的時候,效率差別會很明顯。索引儘量的少,更不能亂,需要的時候就建立它,如果需要的時候沒有索引,那會非常不好。如在訂單表裡,使用者在秒殺的時候,需要判斷使用者之前有沒有參加過活動,那麼我們在表裡會查詢響應使用者和活動id兩個欄位進行建立符合索引,效率會更高,同時還可以用前面欄位索引查詢,利用率高了;還比如商品相關的訂單,給商品建立訂單;還比如時間範圍內的,給時間加索引;建立索引後,資料每次的更改和插入也會對索引操作,這樣對資料寫操作增加開銷。要遵循索引的建立原則。再比如我們對訂單狀態做了索引,因為欄位節點上有幾個狀態節點,節點特別少,如果表裡了有1000萬的資料量,發現每個節點裡有100萬個資料,雖然對符合狀態的查詢很快,但是每個節點下符合條件的都有100萬的資料量,但是後續的處理很困難。這也是不符合的,還不如多幾次查詢。我們儘量把索引建到比較分散的列上,比如uid,活動id雖然現在不多,可能慢慢的規模會增多)
減少資料規模(如果要檢索的符合條件的資料很多,那麼效率也不會體現出來,比如查詢出符合條件的資料太多,而節點型別並不多的欄位。比如一個資料表有1000萬條資料,另一個表裡有10萬,那很明顯我們在這1000萬條資料裡做操作及時有索引,但是他的更新查詢等寫操作比只有10萬條資料的要差,這就是規模的影響。如何減少呢?比如預計訂單表會很大,訂單表相應的欄位有活動欄位,那麼我們可以通過不同的活動建立不同的表來儲存響應活動的訂單資訊。這樣規模就減少了)
將資料放到redis快取中(存記憶體、結構簡單、效能好,可以每秒做到一萬次甚至幾萬次的操作,減少Mysql資料庫壓力)
程式碼邏輯方面的優化
比如在引數校驗方面,可以把較為簡單的校驗放在前面;再比如資料結構的合理利用;合理地簡化程式流程

 分散式方案

多個接入層伺服器
如果效率要說高的話,其實單個伺服器最高的,所有的請求傳輸都在一臺伺服器完成,如果都在同一個伺服器,整個業務的流程會更短。單機自己接收自己處理,資料庫、快取,都在同一臺伺服器可以避免網路傳輸這種問題。但是要考慮更大的訪問量,隨著訪問量越大,單機的服務是沒辦法滿足需求的,當達到更高的訪問級別,那麼不得不考慮分散式方案。如果規模比較小的話,像是面向企業內部的這種產品,使用者量不大,所以單機就可以完成,最多的是就是資料庫獨立,保證安全穩定,處理伺服器就那麼一臺,這樣規模比較小。關於分散式的方案無非就是不是一個伺服器,多個伺服器就可以理解為分散式。有的產品很難做到分散式,原因呢就是有些業務邏輯很難分開,比如session分散式儲存和檔案,分流訪問導致session丟失,當然也可以配置到快取裡解決這個問題。所以我們在開發的時候一定要注意減少伺服器的差異,每一臺伺服器最好是一樣的,就算隨時去掉一臺伺服器或者加入一批伺服器不會有太大影響,這樣就可以很容易實現分散式。比如一個叢集,就一個接入的伺服器,一般來說訪問量在百萬級或者千萬級左右,我構建一個叢集規模可大可小,也就可以提供這種服務。但是秒殺系統可能規模更大,過億的話,叢集小的話,可能就無法正常提供服務了。因為我們就一個叢集,網路的話可能訪問就比較慢,還有距離問題,比如跨南北城市,因為就一個接入的終端。另外一個接入的話,自身處理的能力也是有瓶頸的。所以我們在做秒殺的時候,儘可能考慮更大的規模,更多的接入層伺服器。
多個機房,每個機房部署一個叢集,每個叢集一個LVS作為接入層伺服器做請求轉發,不做業務處理,效能穩定性會更好,也就是部署多個叢集。一般一個LVS伺服器每天提供上億個訪問轉發是有壓力的,如果我們的訪問量是十億,做十個叢集,LVS是可以應付的。我們可以做多個機房,分為華北、華南等區域劃分,這麼做的目的還是希望離使用者更近一點,當然還是希望能同城訪問,這樣訪問更好。
智慧DNS為不同網路不同地域的使用者解析到不同的LVS,就好比使用者來自北京,當然就希望使用者訪問北京的接入層服務;比如我用的電信寬頻,當然還是希望訪問的是電信。整體而言智慧DNS就可以保障效率。
部分靜態檔案、介面引入CDN,因為CND是兩三百個機房,CDN本身也有快取,這樣處理的速度會提高,減輕我們自己伺服器的壓力,硬體就不要考慮了,只需要考慮頻寬等因素

多WEB伺服器單資料中心
LVS後端掛載多個WEB伺服器,規模在2~10不等,不建議規模做特別大,不如多做幾個叢集,因為管理不太方便。
單資料中心,開發更簡單,資料一致性有保證。如果就一個資料庫,那麼開發在請求配置的時候,就當做本地請求就可以了,不用考慮一次操作寫多少次,需不需要同步。部署多個服務的話,代價就大,維護起來就有成本,單個的話還是比較方便的,百萬級的話還是可以的。不過如果太大,還是要花費大量人力物力。
跨機房時網路問題比較突出,要有光線專線寬頻保障。比如同機房的網路延遲是幾毫米,跨機房的話可能幾十毫秒,就跟跨城市差不多。一定要保障跨機房的時候,保障速度。當然資料呼叫也要考慮網路時間開銷。

 多WEB伺服器多資料中心

在多資料中心就可以避免單資料中心的一些問題,一個是單資料中心的瓶頸,另一個是網路問題。我們在每一組伺服器都有自己獨立的資料中心,那麼所有的資料處理在本地區域網就完成這些問題,就不會出現這種跨機房延遲問題。因為我們有多個資料中心,它的處理能力也會提升,所以在處理瓶頸這塊就不是問題了。
每個資料中心都是一個獨立的伺服器叢集,因為每個資料中心都是和一個叢集在一起的,這一組伺服器在處理資料的讀寫等操作,都在區域網完成,所以效率高了。不足的地方是,資料一致性的難度就會有所提高,那麼我們可以引入中控伺服器來調配多資料中心的資料,保證使用者與庫存的均衡(管理資料中心,調配資料中心的資料,他不會處理業務,只處理多個資料中心的資料變化),那麼資料同步嗎、資料一致性也就不會有問題出現了。
伺服器規模預估
資料量:訂單量、使用者量分析
訪問量:全程的請求數量,每次請求的速度
資源量:CDN頻寬(請求數量和檔案資源大小來算),伺服器頻寬,WEB伺服器,Mysql,redis數量

防止黃牛

問答、互動式驗證碼等機制、使用者訪問頁面路徑校驗、頁面停留時間和點選位置和時間、使用者基本資訊和IP還有瀏覽資訊等

相關文章