覆盤一次小公司遇突發流量的撲火搶救

今天雙十一,木有節目!!!靜靜寫個文章吧 :-Dphp

2018 年元旦前夕,公司業務系統流量忽然增長 5~6 倍,然而並沒有相關預演或準備,因而乎系統癱瘓了,錢也再也不進帳了,對於小公司來講,痛並快樂着!html

通過這次撲火搶救,我的總結了一些小經驗,大廠用不上,但對總共就幾我的的小微公司而言可能有些幫助。mysql

PHP 技術棧,然而道理是相通的!沒必要糾結世界上最好的語言是哪一個 :)nginx

簡略版

  • 升級至 PHP7
  • 啓用 OPcache
  • 借日誌識別隱患和瓶頸
  • 清理數據庫慢查詢
  • 關閉 Debug 及 Log
  • 增長緩存時間

補充版

  • 還沒升級到 PHP7 的,若是能夠,建議升級。我的認爲,無關性能,這一種擁抱變化、勇於挑戰的追求,萬年 CentOS 6.x 甚至 5.x 式的穩定就小公司而言不太好。小公司的穩定應該是花最少的錢,作最多的事,讓產品迅速上線、高效運轉,源源不斷的正向現金流。技術債必須欠,但不該該欠太多啊!簡單地說,產品技術棧不肯升級的壞處就是沒法充分享受開源的好處,造輪子並不是小公司的強項,固然若是是錢多得沒地花的話就忽略我吧。

並不是有意針對CentOS。不過本科的時候折騰過CentOS、Fedora、openSUSE、Mandriva Linux、Elementary OS、Debian、Ubuntu, Ultimate Edition、紅旗 Linux、Ylmf OS(雨林木風OS,並不是Ghost版啊,哈哈哈。現名StartOS)、Linux Deepin(深度OS,一樣並不是Ghost版!)……各類我能接觸到的 Linux 發行版,最終仍是認爲 Ubuntu 更友好,適合我這樣的小白用戶,畢業後遇到了 Linux Mint,至今已用 5 年+。最開始作 iOS 開發的時候還用的虛擬機(當時個人筆記本 i7+16G+SSD,虛擬機還行),後來同事離職騰出一臺 MBP,用了一年左右吧,再後來就不用了,一方面是再也不從事 iOS 開發,另外一方面是我省吃儉用換了一臺 i7+GTX1070+64G+SSD+4K屏幕的筆記本(第一件事情依然是格盤裝上 Linux Mint)。。。web

  • 啓用 OPcache,鳥哥博客文章 《讓PHP7達到最高性能的幾個Tips》 第一條。redis

  • 日誌建議重點關注兩點:sql

    • php-fpm 的 slow log (如代碼中是否出現 sleep 一類的函數?實在有必要嗎?)
    • 數據庫的慢查詢日誌 (索引、觸發器、存儲過程等可能形成慢查詢甚至鎖表)
  • 清理數據庫慢查詢數據庫

我的認爲,就通常互聯網小公司而言,系統瓶頸通常先出如今數據庫。可能平時業務量小,硬件資源充足,問題不顯現,估計都不過重視這問題。數據庫鏈接池的問題並非瓶頸,面對大量的慢查詢再多的鏈接池也無論用啊,先把慢查詢處掉就行了,查詢慢甚至鎖表可能只是個索引的問題。。。後端

  • 關閉 Debug 這個沒啥好說的,但就怕忘記了!!!至於 Log 嘛,看狀況吧,要注意非異步的、可能引發阻塞的 Log (好比說直接在每個 request 裏同步寫日誌就不合適)

太長不看版 (覆盤)

2018 年元旦前夕,系統流量瞬間猛增 5~6 倍,可近期並沒有廣告推廣投入啊,當時第一反應是遭到攻擊了,但冷靜一想,哪一個閒着沒事盯上個小公司,多大仇啊。查看各類數據推斷這次爲天然流量。緩存

因爲無相關演練和應急預案,系統癱瘓了,公司收入也基本停了,痛並快樂着!

我當時首先建議升級 PHP。將其中一臺服務器升級後發現內存和CPU消耗減半 (注:其實並未真正解決問題)。

接着其它服務器也升級了,可尷尬的是,沒過多就,系統又癱瘓了,並且多了不少錯誤日誌。我司用的PHP框架是 ThinkPHP 3.x,疊加歷史遺留問題,根本不可能平滑升級。因而乎降級回到 5.6 的版本。

回到原點,並且問題沒有解決!!!

因而乎,下一個嘗試是,增長服務器數量、提升數據庫鏈接數上限(阿里雲的數據庫)。然而都加倍了,壓力仍是沒有緩解!沒有緩解!換句話說,關鍵不在此,再加就是花冤枉錢。

接着我拿到了一臺服務器的 SSH 帳戶。

注:我我的負責的工做相對雜亂,從 Android 到 iOS,到 Java web 再到 PHP web……,但卻沒管過公司服務器的維護工做,固然我我的負責的外包項目的話就是從服務器選購、系統環境配置到項目開發、部署、維護……,從 0 到 1 全包了。

我首先啓用Opcache,而後調整了 nginx 和 php-fpm 的一些參數,起到了必定的做用,但並未解決問題。

而後我順手把 PHP 的慢執行日誌 slow log 打開了。因爲系統堵得厲害,一大堆的 log,沒能抓到關鍵,當天無果。

推薦個好用的工具 mosh,關鍵時候不掉線哦

畢竟用戶也是要休息的,慢慢流量下去了,系統恢復正常。不過晚上也沒夢到解決方案 :-D

次日,繼續排查,各類調參無果。中午吃過飯後,媽給我來了個電話,問我是否是在加班。這。。。

掛電話後,我犀利的眼睛注意到了一條不起眼的日誌,順着日誌指示的行數,我翻看了一下代碼,發現該行調用了個 usleep 函數,5 秒鐘,個人天,不必吧,因而乎我直接把它註釋掉,重啓 php-fpm,奇蹟出現了,該臺服務器瞬間暢通!接着排查了全部代碼中出現的 usleep 函數,通通註釋掉,重啓 php-fpm。

系統恢復正常服務,錢也開始進來了。。。

然而故事到了這裏還沒結束!

下午流量又逐漸增長,到傍晚飯點的時候,系統又響應緩慢了,但當時我在外吃飯,沒帶電腦,一時也趕不回去,沒辦法,我只好掏出手機試試了。還好下午有先見之明,準備了個批量重啓服務器 php-fpm 的工具,一重啓它就恢復正常了,過段時間堵了就再重啓,原本是有效的,可流量還在增長,慢慢地就無論用了,不過這時我已經吃完飯回到家。立刻電腦打開,繼續奮戰!

再推薦個小工具 PSSH (Parallel SSH)

最後同事定位到的緣由是,另外一個子系統的數據庫的 session 數據表沒添加索引,致使 session 過時的時批量刪除的時間過長,估計是鎖表了。

主系統還可能出問題的地方我都檢查過了(其實我是不清楚還有個老系統在跑☺),並且 session 的驅動也從 mysql 換到了 redis,沒想到的是拖後腿的是個子系統,一款已上線多年的App (這次流量全是它引來的),把數據庫拖垮了。

session 表添加索引後,系統又恢復正常了。

回顧整個撲火過程,關鍵點有兩個,一是 usleep 函數,二是數據庫索引,啓用 OPcache 是有些做用的,而關閉數據庫觸發器啥的也起到了不小的做用,而增長接口緩存時間的操做其實治標不治本,沒有從根本上解決問題,並且此次連表面上解決問題的做用也沒起到。

這次撲救的突破口在於日誌,一是 php-fpm 的慢執行日誌,二是 mysql 的慢查詢日誌。經過排查致使 php-fpm 進程排長隊的緣由就能順藤摸瓜解決問題。

在服務器資源必定的狀況下,php-fpm 的進程數一樣有限,若是出現進程休眠(例如 usleep )或數據庫鏈接數達上限(慢查詢致使)的話,服務器資源充足的狀況下沒問題,但 php-fpm 的進程一旦排長隊,接下來極可能就是雪崩效應,系統就癱瘓了。

以上是本人的一點經驗總結,可能存在很多錯誤和不足,歡迎各位小夥伴來指正和討論,謝謝!

本人普通 985 工科院校,工商管理類專業,雙學位。創業小公司工做 5 年+,全包工程師,因離家太遠,近期在尋求珠三角地區的新坑,偏後端方向,求介紹啊(已換坑)!

相關文章
相關標籤/搜索