做秒殺活動的時候,最難應付的應該是在開始秒殺的那一瞬間,如何解決成千上萬個用戶同時造成的高並發問題。只有較好地解決這些問題,才能讓你的程序 在這么多秒殺用戶中,找到真正的秒殺得主。雖然之前做的秒殺活動最多的並發數也就在幾十個,不過,還是積累了一些經驗,在此記錄並分享出來,希望對其他開 發秒殺產品的開發者有所幫助。
一、mysql連接數
最開始,我沒有對mysql的並發連接數做調整,結果某一次秒殺用戶多的時候,就提示mysql連接數過多,拒絕連接的提示。原來,mysql默認 的並發連接數是100,這對於秒殺瞬間來說,是遠遠不夠的。可以通過在/etc/my.cnf文件中設置max_connections參數即可。比 如:max_connections = 800。
二、php-cgi進程數
后來,在之后的某一次秒殺中,在點擊開始秒殺出現驗證圖片的時候,整個頁面需要卡上10s左右才出來,我認為是php-cgi進程處理不過來,所以將其由最開始的100提高到256,這對於內存足夠大的服務器來說,能盡快響應等待的請求,讓用戶盡快地得到響應。
三、session數目
不過,第二步在后來的進一步跟蹤中,發現還並不是導致頁面變慢的主要問題——真正的罪魁禍首是session。原來的session過期時間設定的 是30天,在session表中,存儲了超過40萬條的記錄,在驗證圖片顯示的頁面,就需要利用到session來存儲驗證碼,對一個40萬的 session表操作,讓mysql要索表0.5s,因此頁面響應的速度急劇下降。后來通過刪除無用的session信息,將session表記錄減低到 7000,並將session有效時間調整為7天,就將頁面的響應速度很快地降低下來了。
四、驗證圖片
驗證圖片用到session也增加了數據庫操作次數,因此我考慮將驗證圖片從session剝離開來,直接利用memcached來存儲用戶的驗證 碼信息。用戶請求的時候,分配一個唯一的sessionkey,用戶請求驗證圖片時,需要通過sessionkey來請求,同時,系統存儲一個鍵值對 (sessionkey=>validcode)到memcached,這樣的話,將請求驗證碼圖片的數據庫操作次數將為0,對於秒殺系統的響應速 度也提供了極大的方便。
五、秒殺得主的決策
最開始,我們采取了如下的秒殺得主判定策略:秒殺者檢查秒殺產品的秒殺得主是否為空,如果為空,則認定自己是秒殺得主,並將秒殺產品的秒殺得主設置為自己。(如下圖所示)
秒殺者自己判定似乎否為秒殺得主
圖一、秒殺者自己判定似乎否為秒殺得主
在內部測試期間,人數比較少,這種策略一直都沒有出問題。不過到正式上線的時候,這種策略在高並發的情形下,則變得不堪一擊:因為,在用戶A檢查自 己是否是秒殺得主的時候,已經有用戶B,設置用戶C、用戶D也在進行這項檢查,而這個時候,用戶A還沒有將自己是秒殺得主的消息寫入秒殺產品的記錄中,所 以,用戶B、C、D都會認為自己也是秒殺得主。
我們曾經想過,將相關的數據操作用memcached緩存起來,不過,其實,雖然memcached在響應速度上雖然比mysql要快,但在高並發的情況下,它也依然無能為力,依然會遭遇到同樣的問題。
后來,我們決定改變策略:用戶秒殺的時候只讓其插入秒殺記錄,並不去判斷自己是不是秒殺得主;判斷得主的事情交給裁判——定時任務完成。定時任務根據各個用戶秒殺時間的先后順序,很容易就可以知道誰是秒殺得主,並將秒殺產品的秒殺得主設置為這個用戶。(如下圖所示)
由定時程序判定誰是秒殺得主
圖二、由定時程序判定誰是秒殺得主
我想,我們在各種比賽中,都需要由裁判來主持公道,也是同樣的道理吧。
通過做好如上所述的步驟,相信您的秒殺活動一定能更加完好地運行。