k8s環境下由predis初始化連線緩慢引起的一次問題排查
背景
最近業務上在做同城雙中心。原本的機房使用的是swarm叢集,新機房使用的是k8s叢集。業務遷移到新機房的主要工作集中在:
- 庫、redis、es等底層服務的遷移;
- redis由原來的vip單點模式,切換為redis-cluster,由於phpredis1官方版本暫時不支援帶auth的cluster模式,所以選擇了predis連結redis;
- 將之前的swarm叢集,遷移到k8s叢集;
現象
部署完成之後發現,首頁載入很慢,開啟network,發現ajax請求普遍比老機房慢2-3秒。業務已經上了redis快取,仍是如此。
排查思路
瀏覽器併發數
首先考慮瀏覽器同域下請求併發數問題,由於瀏覽器對於同域的併發數有限制,當同域的請求過多是,後續的請求會出現stock情況。通過network中的waterfall基本排除了該種可能:
服務端profiling
基本排除了客戶端問題之後,開始服務端profiling(效能剖析)。專案使用的是php的CodeIgniter框架,之前自己動手寫過一個profiling的框架。所以引入框架後開始分析,以下是首頁眾多ajax請求中的一個:
然而單獨除錯這個介面的時候,結果卻是這樣:
對比兩個結果,可以看出幾點:
- 多處耗時較長,包括初始化框架、sql查詢和redis初始化;
- 單獨請求介面時,比在首頁眾多請求中請求介面,效能有很大提升;
此時,我進入了一個誤區。我嘗試針對各個耗時的操作逐一排查。於是就開始從初始化redis(因為我覺得這裡最蹊蹺)開始,開始除錯predis原始碼,各種優化連線引數。然而折騰了很久,只是發現除錯的過程中一切執行都正常,但是就隨著程式碼執行,耗時出奇的高。
直到,我意識到一個問題:是不是併發越高,相應越慢?
併發情況下資源等待
我依次在本機使用ab,測試了100次請求下,不同併發下介面的響應情況:
-
併發1的情況:
-
併發10的情況:
緊接著,我又測試了在有無壓測的情況下,在瀏覽器上profiling單個介面,結果果然如我所料,在壓測情況下,介面耗時慢很多。
其實到這裡,原因基本可以猜到了,就是k8s中container的資源限制。由於資源limit配置不當(cpu設定limit:200m),導致隨著併發請求的處理,很多操作在等待cpu資源,所以最終表現的情況就是,併發越大,請求越慢。
在我移除cpu限制之後,請求基本正常。
結論
這個問題的排查過程,給了一類介面請求慢問題的排查思路:當發現程式執行基本正常,而大部分整體耗時較長的情況下,可以考慮是否是機器/作業系統的資源限制造成的。
就是php的redis擴充套件,以前的名字叫phpredis,最近好像更名為redis了,估計是為了防止歧義吧,連結在:http://pecl.php.net/package/redis ↩︎