天天看點

Docker應用問題診斷與性能調優指南(一)- 先談談容器化性能調優

性能調優是一個老生常談的話題,通常情況下,一個應用在上線之前會進行容量規劃、壓力測試并進行驗證,而性能調優則是在容量規劃與驗證結果之間出現差異時會進行的必然手段。從某種角度來講,性能調優是一個非常需要經驗的領域,需要調優人員對應用的架構、調用的鍊路、使用的語言、作業系統的差異、核心的參數表現等等都有完整的了解。大部分情況下,系統性能調優都是通過各種各樣的工具監聽、跟蹤、分析、檢測來檢查解決的。是以通常情況下,性能調優的老手都有一套自己的診斷工具集以及相應的診斷方式。但是當性能調優遇到Docker的時候,很多事情發生了轉變甚至惡化。

經常有客戶抱怨說應用進入Docker後,應用的QPS無法和ECS進行媲美,并且時常會出現DNS查詢逾時、短連接配接TIME_OUT、網絡丢包等等,這極大打擊了客戶對使用容器技術的信心與決心。誠然,容器化的方式根據網絡模型的不同,會在傳輸效率上面略有差異,但遠遠達不到客戶回報的性能損耗,而在容器中進行調優與診斷的效果因為安裝工具的複雜度大大折扣。

那麼到底該如何針對容器的場景進行調優呢?

在讨論容器化場景的性能調優之前,想先和大家談一下性能調優中的“望聞問切”的問題。對于性能問題,大部分人第一個想到的是CPU使用率高,但是得到CPU使用率高這個現象後,我們改如何解決呢?從某種意義來講,這個隻是現象,并不是症狀。為了友善大家了解,在此我打一個比方:感冒的時候我們去醫院看病,病人跟大夫描述的是現象,包括頭部發熱、流鼻涕等等;而大夫通過探查、化驗,得到的醫學症狀是病人的白細胞較多,喉嚨有紅腫等等,然後大夫确診是細菌性感冒,給你開了999感冒靈。診斷病情的過程和性能調優是一樣的,也需要找到現象、症狀和解法。我們回到剛才CPU使用率高的例子:我們已知的現象是CPU的使用率高,然後我們通過strace進行檢查,發現futex_wait系統調用占用了80%的CPU時間,而這才是真正的症狀,根據這個症狀,我們業務邏輯代碼降低了線程切換,CPU使用率降低。

大部分的性能調優問題都可以通過發現現象、探測症狀、解決問題這三個步驟來進行,而這在容器的性能調優中就更為重要的,因為在主機的性能調優過程中,我們有很多的經驗可以快速找到症狀,但是在容器的場景中,很多客戶隻能告訴我們的是現象。從某種角度來講是由于客戶并不了解使用的容器引擎的工作原理以及容器化架構的實作方式。那麼接下來我們來看下容器化場景中性能調優面對的挑戰。

VM級别的調優方式在容器中實作難度較大

在VM級别我們看到的即是所有,網絡棧是完整暴漏在我們面前的,CPU、記憶體、磁盤等也是完全沒有限制的。性能調優老司機的工具箱安個遍,診斷流程走一趟基本問題就查個八九不離十了,但是在容器中,很多時候,都是預設不自帶診斷、調優工具的,很多時候連ping或者telnet等等基礎指令都沒有,這導緻大部分情況下我們需要以黑盒的方式看待一個容器,所有的症狀隻能從VM層的鍊路來看。但是我們知道容器通過namespace的隔離,具備完整網絡棧,CPU、記憶體等通過隔離,隻能使用limit的資源,如果将容器當做黑盒會導緻很多時候問題症狀難以快速發現。排查問題的方式變難了。

容器化後應用的鍊路邊長導緻排查問題成本變大

容器的場景帶來很多酷炫的功能和技術,比如故障自動恢複,彈性伸縮,跨主機排程等等,但是這一切的代價是需要依賴容器化的架構,比如Kubernetes網絡中需要FullNat的方式完成兩層網絡的轉發等等,這會給排查問題帶來更複雜的問題,當你不清楚編排引擎的架構實作原理的時候,很難将問題指向這些平時不會遇到的場景。例如上面這個例子中,FullNat的好處是降低了網絡整體方案的複雜性,但是也引入了一些NAT場景下的常見問題,比如短連接配接場景中的SNAT五元組重合導緻包重傳的問題等等。排查問題的方位變大了。

不完整隔離帶來的調優複雜性

容器技術本質是一種虛拟化技術,提到虛拟化技術就離不開隔離性,雖然我們平時并不需要去考慮隔離的安全性問題,但是當遇到性能調優的時候,我們發現核心的共享使我們不得不面對的是一個更複雜的場景。舉個,由于核心的共享, 系統的proc是以隻讀的方式進行挂載的,這就意味着系統核心參數的調整會帶來的主控端級别的變更。在性能調優領域經常有人提到C10K或者C100K等等類似的問題,這些問題難免涉及到核心參數的調整,但是越特定的場景調優的參數越不同,有時會有彼之蜜糖,我之毒藥的效果。是以同一個節點上的不同容器會出現非常離奇的現象。

不同語言對cgroup的支援

這個問題其實大多數場景下我們是不去考慮的,但是在此我們把他列在第四位的原因是期望能夠引起大家的重視。一次在和Oracel Java基礎庫的負責同學聊天中了解到Java針對與Cgroup的場景做了大量的優化,而且時至今日,在Java的标準庫中對于Cgroup的支援還是不完全的,好在這點在大多數的場景中是沒有任何影響,也就不過多的讨論。排查問題的腦洞更大了。

網絡方案不同帶來的特定場景的先天缺欠

提到容器架構我們逃不掉的話題是網絡、存儲和排程,網絡往往是一個容器架構好壞的最根本的評判标準,不同的網絡方案也會有不同的實作方式與問題。比如在阿裡雲的Kubernetes中我們使用了Flannel的CNI插件實作的網絡方案,标準Flannel支援的Vxlan的網絡方案,Docker的Overlay的macVlan,ipvlan的方案等等。這些不同的網絡方案無一例外都是分布式的網絡方案而存儲的資料都會存放在一個中心存儲中,是以越大型的叢集對網絡中心存儲的壓力也就越大,出錯的可能性就越大。此外跨主控端的二層網絡很多都會通過一些封包解包的方式來進行資料傳輸,這種方式難免會增加額外的系能損耗,這是一種先天的缺欠,并不是調優能夠解決的問題。有的時候排查出問題也隻能繞過而不是調優。

鏡像化的系統環境、語言版本的差異

這篇文章中我們主要讨論了基礎的性能調優的方式以及容器化場景中性能調優的難點,在下篇文章中我們會來套路下不同的性能瓶頸現象對應的診斷和調優方法。