公司有一個Web Service,訪問量不大, 但也不算小, 天天幾百萬的量級。正常狀況下, 平均每一個請求響應的時間在200毫秒左右。php
天天幾百萬的訪問量, 那麼程序每秒請求處理數量在幾十個左右, 高峯期也就上百, 而服務器上php處理請求的進程數是大於這個數的,所以, 服務器的處理能力勉強能知足當前量級的請求, 除了少數時候高峯期會出現不穩定的情況, 大多數時候也算是相安無事, 可是從服務器失敗請求的數量來看應該離服務器處理能力極限的臨界點不遠了。java
這個Web Service有一個特色, 它並非面向終端的 , 而是爲另外一套Web Service提供底層數據用, 那套Web Service會進行數據緩存,不會把全部數據請求轉發到咱們這裏,它替咱們擋掉了大部份壓力。然而, 天有不測風雲,某一天高峯期那套Web Service的緩存機制壞掉了, 全部數據請求全都轉發到咱們的Web Service上, 結果, 咱們Web Service訪問量成倍增加,服務器超出了承受能力的範圍而沒法正常響應,而後用戶各類投訴,領導各類不滿,壓力天然而然就到了個人身上。golang
我分析了一下問題的緣由,Web Service 每一個請求的響應時間爲200毫秒上下, 服務器的併發處理能力並非很高, 也就是說在每一個200毫秒內,服務器處理請求數量是有極限的, 當每200毫秒的請求量大於這個極限的時候, 後面進來的請求就不能被及時處理, 只能排隊等待,這就跟堵車一下,車的數量遠大於馬路的吞吐量時,天然是越堵越多。堵車沒有時間限制, 反正早晚能開走, 只是花點時間等待而已。 而服務器處理請求就不同了,若是指定的時間範圍內沒法及時處理請求,那麼這些請求就會壞掉, 也就是咱們一般看到的502或者504。咱們的服務器也是由於這個緣由而出現了大量的壞掉的請求,致使業務受到影響。數據庫
整個Web Service大約有百分之八十流量是流向其中五個接口(頁面)的,所以我只要集中優化這五個接口,將它們的響應時間降下來,那麼服務器併發請求的處理能力將會獲得提高。apache
這個Web Service是由php實現,近一年內也不斷的在優化其性能,但老是沒法完全解決問題, 雖然服務器的併發處理能力獲得了必定程度的提高, 可是, 每一個請求的響應時長老是降不下去。 被逼無奈, 我決定以換技術從新實現的方式嘗試着解決問題,畢竟高性能服務器的編寫並不是php所擅長的, 而golang彷佛更加適合作這件事。緩存
我仔細的看過這個Web Service的每一行php代碼, 發現存在如下影響性能的問題服務器
沒有數據庫鏈接池, 也沒有單例, 每一次讀寫數據庫都會簡單粗暴的執行openconnection和close connection網絡
使用memcached。我以爲memcached也影響性能,由於會有網絡開銷,若是不是多個程序共享內存須要, 根本沒有必要使用, 但在php中卻沒法避免,由於php沒法直接操做內存多線程
沒有多線程,沒有辦法並行處理問題, 如只能經過串行的方式從多個數據庫中讀取數據併發
編寫代碼時沒有考慮到時間複雜度問題, 各類無心義的foreach太多
除了代碼中存在的問題, php技術自己也有性能痛點存在, 如
解釋執行代碼, 但也沒有像java同樣的即時編譯機制
請求必須經過apache和phpfpm服務器中轉, 而後再交由php自身
而golang正好克服了這些問題
很是方便的使用數據庫鏈接池
直接操縱內存, 不使用第三方緩存軟件
goroutine, 多線程中的戰鬥機
純編譯型語言, 跟C相似編譯出來的就是最低層的機器碼
程序自己就有Web服務器的功能, 不依賴第三方Web服務器
所以, 從理論上來說, golang在性能方面完勝php。
由於只須要重寫Web Service中的5個接口, 工做量並不算太大, 總共大概只花了2天的工做量就徹底成了重寫的工做,而且將舊的php版本中存在的問題全都避免掉。
將程序部署至生產環境後,我對兩個版本的程序在性能上作了大體的對比
php
golang
php
golang
從圖中能夠看出,一樣的功能, 一樣的數據, 可是在請求的時間上卻確差了許多倍。
在併發量處理方面, 我寫了一段Java程序,開100個線程去請求測試環境下的接口, 代碼大概長這個樣子
php實現的版本, 在這段程序運行20秒左右的時間後,服務器就出現沒法響應的情況,大體狀況應該與以前線上服務事故緣由相同,車太多, 路過小, 堵住了。
而golang的版本, 無論程序開多久, 都一直穩定的運行着, 程序的進程對於服務器資源也沒有太大的消耗,所以能夠判定,在真實的生產環境下golang寫的版本的表現確定將優於php版本。
如今, 使用golang新實現的版本還在測試當中, 須要確保接口返回的數據與php版本接口的返回的數據沒有一毫誤差才能夠正式切換服務。
系統尚未真式使用, 重寫所帶來的效果也尚未體現, 可是我仍是義無反顧將這件事提早發在公衆號上, 這充分的說明了, 我對於此次重寫有足夠的自信,對golang的表現也有充足的信心,讓程序性能提高10是能夠實現的。