靓仔落泪,性能问题定位难倒我了
生活随笔
收集整理的這篇文章主要介紹了
靓仔落泪,性能问题定位难倒我了
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
戳藍字“CSDN云計算”關注我們哦!作者 |?popsuper1982責編 |?劉丹今天我的主題是在微服務場景下的一個性能問題的定位優化,那么今天會講一個我們其實出現的一個真實的一個場景,然后其實還是花了蠻長時間,然后把這個東西才定位到一個具體的問題。
現在云原生微服務架構特別的火,有非常多的優勢,比如說這里面寫的快速迭代,高并發,可維護,可擴展,灰度發布,高可用,這些詞大家都耳熟能詳,這些就不用細說了。但是微服務不是沒有成本的,如果說單體應用的復雜度大概是10的話,上了微服務可能是變成100,可能是十倍的復雜度提高,需要投入大量的人去做這個事兒,并且需要一定的支撐系統和工具鏈,才能將這些復雜性降下來。我這邊總結了一下微服務實施之后,會大概率出現以下的痛點:第一:服務依賴的管理。就是一個服務到底調用了哪些,被哪些服務調用,如果依賴管理比較混亂,就會比較痛苦,比如說你要發布一個應用,你可能不知道這個應用被誰依賴了,有沒有有一個特別關鍵的應用在依賴于我這個應用,會不會我升級了以后是否會引發關鍵業務的不穩定,是應該白天發布,還是凌晨發布,這個時候我們就特別需要希望有一個系統能夠看到任何一個服務都被哪些服務依賴以及依賴于哪些服務。第二:調用統計問題。對于調用記錄有一個統計和告警,例如有沒有接口突然調用失敗率增高,有沒有接口突然時延增長,都應該及早發現,而不能因為因為一次發布引入一個bug,導致時延變長但無人知曉,等到流量一來,直接就可能壓掛了。再就是有沒有接口再也沒有人調用,這個接口是否可以下線,這在接口升級的時候,常常采取先添加接口,再下線接口的方式,就需要這樣一個統計系統。第三:接口規范問題。各個團隊開發出來的各個服務的接口是否符合統一的接口規范,有沒有統一的地方去看接暴露出來的接口?如果說有的接口不遵守規范,那么是不是時候會在同一個地方能看到,然后去盡早的去發現這個問題。第四:安全管理。很多企業往往通過白名單通過配置中心配到各個服務里面去的,比如說支付這個服務不是所有服務都能調用的,只有部分服務可以調用他。這些配置原來都是散落在這個服務里面去的,各自為站,有可能一不小心就配置錯了或者漏了,應該能訪問的訪問不了,不該訪問的能夠訪問了,但是沒有人察覺。第五:熔斷限流降級這些服務治理能力。雖然有很多開源組件可以做這些事情,但是需要寫大量重復代碼去做,同樣是散落在各個地方。第六:接口測試問題。我們如何保證在不斷的拆合的過程中不會引入新的bug,這其實是比較頭疼的一個事情,所以需要一個比較大的一個測試集合,就需要一個測試平臺來保證。第七:灰度發布問題。很多公司做灰度發布,都是通過代碼里面寫if-else做的,當什么條件滿足的時候,走這個邏輯,當時什么條件滿足的時候,走那個邏輯,這個時候也是相對比較痛苦的。第八:壓力測試問題。這一般是實施微服務的后期,當需要面對大規模流量的時候,才會引入進來的。一開始線上大促的時候,基本處于這種一臉蒙,靠運氣的這種狀態,心里壓根都沒有譜,必須要通過壓力測試去做這個事兒。第九:調用鏈分析問題。一旦出現慢的時候,相對比較難以發現慢的點,尤其是當服務數目多,調用鏈長了之后。第十:測試環境治理。服務數目增多了,大家都用了容器,帶來的好處就是部署的特別方便,一個編排就能啟動一套系統,但是同時也帶來一個痛苦,其實我們從云的時候就有這個痛苦,一旦放給大家的權限讓大家可以隨時部署,對于資源的使用就控制不住了,大家誰都想啟動一個新的環境,自己的測試環境和別人都不在一塊。如果說只有幾個容器,那么每次都重新部署一個新環境,這沒有問題,但是如果服務特別多的時候,例如一百個容器的時候,這時候全量部署比較困難。為了解決這些問題,需要配備比較復雜的工具集合:容器平臺負責聲明式部署,持續集成和測試平臺負責灰度發布和測試集合的維護,API網關負責入口流量的接入,微服務框架負責微服務之間的相互調用,管理和治理,分布式事物負責拆分后的事務問題,APM性能管理負責調用鏈分析。我們后面也能看到這些組件在定位問題的過程中都起到了什么樣子的作用。微服務的拆分過程并不是一蹴而就的,我們發現很多公司開始計劃實施微服務的時候,往往第一個問題是微服務應該怎么拆,應該拆分到什么粒度?覺得是這是一個最重要的一個維度。后來我們發現其實并不是這個樣子的,微服務的拆分只是其中很小的一個方面,需要匹配一套工具鏈,并且經歷十二個過程,逐步完成。接下來,我們來解析一個微服務場景下的問題定位過程。為什么說在微服務場景下,我們發現定位問題的時候,我們會覺得它特別的復雜,往往需要架構師牽頭協調各個部門一塊去定位某個問題。首先第一個復雜度就是,從頂層到底層這個層次是實在是太多了,我們能想到就是任何一個比如說我們發現請求比較慢的時候,我們首先會想到整個層次中,最上面的應用是不是出了問題,應用這一層本身就比較復雜,圖中密密麻麻的線是double服務之間的一個調用關系,它的復雜度已經十分高了,然后中間一旦出現了慢請求,這時候其實很難定位到一哪一個點,哪個服務集群調用哪個服務集群。
應用層下面這就是容器層,容器下面其實是openstack的云網絡,我們采取方式是kubernetes和openstack整合的一個方式。因為kubernetes對于容器的發布,運行十分友好,對于網絡尤其是多機房高可用橫向擴展的vpc網絡特性相對弱一些,那么正好云在VPC這方面相對比較強一些,例如浮動ip,跨機房高科用,專線等。容器層或者云網絡層,都可能產生問題,例如容器網卡吞吐量受限制,或者ovs吞吐量受限制,都會造成性能問題。再往下是物理網絡,因為牽扯到多機房了,那么可能每機房還有多高可用區,那么整個機房的拓撲結構邏輯也會很復雜。這時候就可以想象說當一個服務的多個副本構成一個業務集群,當從一個業務集群到另一個業務集群時延高,每個層次都其實都有可能出現問題是吧?然后我們就需要層層的去排查這個事情。
另外一個相對比較頭疼的一個事,是從前端到后端的層級也是挺多的。問題往往是在壓測的時候會發現,那么壓測的時候,我們是在我們公有云上去壓真實線上的業務,所以其實是走公有網絡的。我們可以想象,從前端到后端經歷的環節實在是太多了,你比較難判斷他會慢在什么地方。一開始進入機房,有邊界路由器,然后有核心匯聚交換機,這是網管部去管的。接下來就進入了虛擬的云網絡網關,由云計算部門維護。云網關進來后,會有一層負載均衡,這個負載均衡是可以適配多機房的負載均衡,可以做跨機房浮動IP漂移。再往里面會有個API網關作為接入層,然后再往后就是服務層了。服務層分業務服務層和基礎服務層,之間會引入注冊發現機制,比如說用dubbo管理他們之間的相互調用。由于微服務規模比較大,就像剛才圖中展示的一樣,復雜度很高。業務之間調用完畢之后,最終肯定是要落庫的,這時候會涉及到緩存的訪問,緩存后面是數據庫。有時候還涉及到調用云外的系統,因而需要經過云網絡的網關。比如說外部的一些支付系統,安全檢測系統,包括大數據等,都是云外的。這兩次網關其實是不一樣的,前面網關是DNAT網關,后面網關是SNAT網關。可以想象一旦出現性能問題的時候,經過這么多環節就比較頭疼,經常會困惑,這個問題到底出現在哪個環節呢?一般來說,性能問題往往通過線上性能壓測發現的。一般大促之前,提前一段時間,就要開始進行壓測。壓的時候就會涉及到從前往后,從底到上的所有的系統和部門,都要派代表去參加,哪一塊出現了問題,哪一個環節出現了性能瓶頸,哪一塊就要改。線上壓力測試需要有一個性能測試的平臺,做多種形式的壓力測試。例如容量測試,通過梯度的加壓,看到什么時候實在不行。摸高測試,測試在最大的限度之上還能承受多大的量,有一定的余量會保險一些,心里相對比較有底。再就是穩定性測試,測試峰值的穩定性,看這個峰值能夠撐一分鐘,兩分鐘還是30分鐘。還有秒殺場景測試,限流降級演練測試等。有的時候壓測會遇到讓人崩潰的事情,例如可能前幾天壓測的時候,看著吞吐量在向好的方向發展,突然有一天一下子就降下來了,這個時候離大促時間越來越近,心態就會比較崩潰,需要大家一塊去看到底是什么問題。對于測試環境的管理,也是非常關鍵的。線上壓測的時候,為了讓數據和正式的線上數據實現隔離,常用的方法是對于消息隊列,緩存,數據庫,都是使用影子的方式。就需要流量染色的技術,帶一個tag進去,說明這個請求是測試數據,還是真實數據。流量染色的功能,除了壓測里面使用,還可以用于測試環境治理。在大規模微服務場景下,不可能每個部門部署一套完整的環境,因為耗費的資源量實在是太大了。這時候就需要合理規劃測試環境。測試環境是應該和持續集成的流程緊密協作的。我們使用分支開發的方式,每個功能的開發在分支上,上線的時候,合并到主分支上來,主分支對應線上環境。對于測試環境的規劃,也是采取類似的思路。我們會有一個基準測試環境,對應master分支,里面部署全量的應用。每一個分支,比如說你修改了五個工程,測試的時候,不需要部署全量的應用,只需要把這五個工程去創建一個Delta測試環境就可以了。當客戶端進行測試的時候,帶上一個此分支的tag,從API網關開始,微服務框架嵌入的jar會將這個tag一直帶下去。當這五個服務之內相互調用的時候,微服務框架就會選擇這五個服務的實例進行調研,如果需要調用五個服務之外的其他服務的時候,微服務框架會到master環境里面,選擇服務實例進行調用。有了流量染色的環境治理機制,測試環境數量就會小小特別多。
壓測中一旦出現了慢請求,最先從哪里能夠看出來呢。在微服務的接入層有API網關這一層。在API網關中,有一個調用統計功能,可以篩選出慢請求。在壓測的時候,每一輪都有一個壓測結果,是一個列表,按請求時間排序。通過這個列表,可以篩選出這次壓測的時候,最慢的接口都是哪一些,異常的接口(也即請求響應速度有巨大反差)有哪一些?我們就可以針對于這些接口進行特別的排查。在服務治理平臺中,服務之間的調用也有一個統計,也有個一個排名,同樣會列出來哪幾個應用需要改進,重構,或者排查。
和壓測匹配的一個重要的系統是全方位的性能監控。一般的監控平臺僅僅會監控第一項就是服務器的性能,比如cpu,內存,網卡等。其實監控應該是全方位的,對于應用方面的,應該監控堆的內存,GC,線程,cpu利用率等。業務指標應該監控下單數,支付數,購物車請求數等。調用鏈路監控應該包括RT值,TPS等。應用組件應該監控連接的狀態,消息積壓,zookeeper節點數等。還應該有一些異常監控,例如異常的流量,Exception,報警等。這些都是在統一的一個平臺上去做的。定位問題需要深度的依賴于這個平臺,一般先在這個平臺上去找到大概的問題點,如果不能找到真正原因的話,就可以更加細粒度的登到機器上去看。沒有統一的監控,會在大規模微服務場景下,有了問題,比較茫然,根本找不到地方。有了統一監控平臺,我們也在壓測的時候,在API網關上發現了慢請求,接下來就需要逐層定位了。高延遲的現象往往會先出現在應用層,外部的現象就是外部請求的時延高,如果順著調用鏈定位下來,往往會反應到內部從一個服務集群到另一個服務集群的RT值高或者出現大量超時異常。我們可以查看對于服務之間相互調用的監控,dubbo和hystrix我們做了集成,右下角的這個圖是熔斷的基本原理。通過監控我們可以發現有熔斷的情況出現,我們就知道這可能是出現了問題。
一旦出現了問題,架構部一步一步來分析分析這個問題。我們的排查思路是從上層往下層,從業務層往底層層層排查,因為如果讓物理網絡或者虛擬網絡直接去定位,會比較迷茫。第一步:先應用層初步定位。第一件事情,查看近期是否有新變更的發布上線,例如昨天壓測的時候還正常,這次突然出現超時,很可能是新的發布導致的。我們可以重點查看新發布的應用,甚至可以進行代碼review。
如果新發布的應用沒有發現問題,就需要在整條調用鏈路上定位問題了。這個時候應用性能監控APM可以幫上忙,他可以在整條調用鏈路里面,找到最耗時的那個環節,這是我們應該重點定位問題的地方。
在最耗時的環節上,如果我們發現TPS比較低,相應時間長,但是CPU使用率不高。
我們可以通過服務治理平臺,查看這兩個服務之間的調用是否開啟了足夠的線程池,當前的線程池是否已經被打滿,如果滿了,是否可以提高線程池的數目,這和集群所在的虛擬機和物理的核的分配是有關系的,因為核數用完了,再多的線程徒增調度成本,沒有收益。如果可以提供線程池的數目,可以通過配置中心進行統一的配置這個服務集群的線程池數目。很多情況下,性能的降低的原因在于數據庫層,這一點在APM上也能看的出來。這個時候應該DBA去查看問題,可以梳理一下SQL語句,通過慢SQL分析,查看慢的原因,例如索引問題,死鎖問題等,這些都可以通過Mysql或者DDB的日志找出來。
另外一個經常出現的問題就是TPS比較低,但是CPU使用率非常高。這時候我們需要通過監控系統查看線程的狀態,查看耗時的方法列表以及調用棧,看哪個線程耗時比較多,是否因為業務邏輯的Bug,是否在一直計算某個東西,或者出現業務層的死鎖。另外就是看是否頻繁的FullGC,一旦出現了FullGC就會出現一段時間的業務邏輯暫停,在大促本來壓力就很大,而且峰值時間比較短的情況下,一個線程hang就會使得調用鏈擁塞一片。我們要通過監控系統查看堆的信息,找出耗內存的對象,看是否內存一直往上漲,是否存在泄露。另外對于緩存的一個監控,應用層的緩存設計一般有多層。我們本來一開始設計的是有三層緩存的,localcache有兩層,然后分布式緩存有一層,localcache分主動刷新和被動刷新的兩層,被動刷新就是遇到請求了再刷新,主動刷新是主動的去過一段時間去刷新。后來我們又把三層緩存簡化成了兩層緩存,被動刷新的localcache的命中率已經足夠用了,再多一層反而會降低性能。我們之所以監控緩存,是因為我們發現有時候應用層Key使用的不對,或者是配置的不對,會導致緩存層失效,請求就會直接打到數據庫,導致請求相對比較的慢。對于緩存的監控,我們在緩存的客戶端的jar,會和配置中心進行聯動,監控某些我們認為相對比較重要的Key,當Key出現緩存丟失,寫頻繁,或者寫丟失等類似這種事件的時候,它就會上報到我們的監控系統。這個時候,就會發現導致緩存失效的程序Bug。
第二步:如果應用層沒有問題,則檢查異常流量。
如果我們確認應用層的確沒有問題,就需要開始往下層去進行懷疑了。首先第一個比較懷疑的是,是不是出現異常流量。比如說有外部的異常流量,可以問問網管和安全部是否網站被DDoS,另外入口網關是否接受到了大量的請求,例如有臨時的促銷或者臨時的事件。如果入口沒有問題,則查看集群的監控,要對照著兩個指標看,一個是服務端的請求數目的一個統計,看是否有集中的熱點,比如說一個集群有多個副本,其中某個副本收到的請求量特別的大,而其他副本收到的請求數相對比較低。二是在云主機里面的網卡虛擬網卡,也是能夠看到相應的監控的,看是不是網絡流量就集中到某幾臺機器上。這兩個會有一個對照,如果兩方面指標能夠對照起來,集中熱點比較容易定位,也即請求數上去了,同時云網絡的網卡流量也上去了。當出現了熱點的時候,就需要通過服務治理中心或者配置中心,將請求打散。如果兩個指標不匹配,這時候就有問題了,也即服務端請求的數目其實并沒有多,但是云網絡發現出現了問題,這時候就就可能是底層基礎設施的問題,我們這個例子遇到這個點就是相對比較詭異,還需要接著解析。
如果不是異常流量,就需要從前往后再來梳理這個事,比如說從核心交換機到VPC的網關區域這些是不是出了問題,這時候就要聯系機房的網管部門去定位,然后是VPC網關到云的負載均衡,然后是從負載均衡到應用的API網關,然后API網關到應用的Controller層,然后是中間的dubbo調用,然后緩存層到數據庫層。接下來要按照整個鏈路依次的去排查。
這里畫了一張經比較經典的機房的一個圖,其實任何一家公司機房的樣子要比這個圖可能要復雜得多,這就需要架構部門對機房的架構相對比較清楚。我們會分機房,分可用區,還會分二級可用區,他們會走不同的匯聚交換機,在監控系統里面也要標明某個服務器群和另一個服務集群之間的訪問到底是哪個物理機集群到哪個物理機集群之間的訪問,這時候你心里可能需要清楚他們是否在同一個機架里面,或者是在同一個二級可用區,還是在同一個一級可用區,是跨機房了,或者是甚至到異地了,這時候你要心里有個數,因為他們之間的時延都是不一樣的。
第二個就是對于VPC網絡的架構是要比較清楚。我們是通過OpenStack Neutron的vxlan去做的這個事情的。橫向流量是通過vxlan,基于OVS去做的,縱向的流量,出去的時候會有網關,我們不是用的物理網關,而是虛擬網關,在數據中心里面有一個虛擬網關的網關層,網關層有的時候是掛在匯聚交換機下面的,有的機房要求吞吐量比較大,網關層可以直接掛在核心交換機下面的,很可能網絡瓶頸點會發生在這些網關上。
我們的VPC網絡是有一定的改進的,因為我們要求一個VPC里面能承載的虛擬機的數量要比開源的OpenStack要多得多,能達到5萬臺的規模。限制網絡規模的一是廣播問題,我們可以事先把整個網絡拓撲下發到一個拓撲庫上去,每一個節點上的Agent會訂閱拓撲庫的更新事件,從而更新本地的OVS策略。每個Agent都會看到整個網絡的拓樸結構,則ARP的時候,本地就可以攔截來進行返回。另外的一個改進就是虛擬網絡,默認的虛擬網關只能做主備,橫向擴展能力沒有這么好,不能夠承載大的并發量,這其實需要有一排的虛擬網關,全部掛載到匯聚或者核心交換機上。接下來的問題是縱向的流量怎么從這一排網關里面去選擇,這里使用了一致性哈希的算法。
另外一個改進是Kubernetes和OpenStack的整合。左面的圖是Kubernetes默認創建一個Pod的流程,好在他是基于事件驅動的,使得我們可以定制化右面創建Pod的流程。我們開發了自己的Resource Controller和Scheduler,當發現容器的節點資源不足的情況下,Controller會調用IaaS的接口創建云主機,然后加到Kubernetes集群中。這種模式下,在應用層的角度,只能看到容器,不需要運維Kubernetes,更加看不到OpenStack的接口,使得應用層有統一的編排接口。
另外對于容器和Kubernetes層的整合,網絡層也需要整合,容器也要融合VPC網絡,只有適配了VPC網絡才能實現多機房的高可用性,跨機房的負載均衡,以及跨機房的浮動IP漂移和切換。比如說一個機房掛了,則掛在A機房的浮動IP地址要能夠切換到B機房的網關上去,并且和核心交換機有聯動,路由也要切過來,這些都只有VPC可以完成這個事情。我們開發了一個自己的CNI插件去做這個事兒,容器沒有使用單獨容器網絡方案,而是直接用了OVS的網絡,也即OpenStack的OVS是可以直接看到容器的IP地址的,容器的IP地址和虛擬機的IP是平的,是屬于同一個局域網。這樣其實還有另外一個好處,因為我們還有很多沒有容器化的應用,如果部分做容器化,是可以和容器內的應用無縫的打通的。一些有狀態的PaaS也是部署在虛擬機里面的,也可以實現在同一個局域網內的互通。
另外一個針對Kubernetes的優化就是規模問題,這是其中的一個優化的例子。重啟一個API server的時候會導致一些問題,尤其是在Pod的數目比較多的時候。通過監控圖可以看出,中間會重啟時間長達七分鐘,中間出現429錯誤并且飆升,是因為流控。為什么會流控?因為它重啟的時候,會有大量的請求重新再連上來,由于并發太多,有可能就把它再沖掛了。
那么應該如何改進呢?方法一就是多級流控,根據UserAgent, Resource, Verb幾個參數,對于不同的客戶端有不同的流控策略,比如說對于master上面的進程優先級相對高一點,對于kubelet結點上的進程,優先級就低一些。不會所有的kubelet節點一股腦上來進行注冊。方法二是擁塞控制,Retry-After參數也即多長時間再重試一次,這個原來是一個默認值,我們改成一個動態的值,根據系統的繁忙程度是調節到1秒到8秒之間,這樣不同的客戶端重試的時間會錯開。使得把整個恢復時間大幅度的降低了,這是我們做的規模化的一個例子。
來我們從接入層開始分析。我們在VPC的網關以及負載均衡層也是做了優化的。優化之一是基于BGP ECMP的等價路由,也即對于LB集群和前面的核心交換機之間配置等價路由,實現橫向擴展和負載均衡。如果使用LVS做這個網關的話,可以使用DPDK技術,也即基于DPVS的負載均衡。電商請求基本上都是基于HTTPS協議的,SSL往往通過offload的方式通過硬件進行加速,在壓力大的時候,優化明顯。
對于負載均衡這一層的問題,出問題的點往往在于虛擬網關和負載均衡,我們要中斷看這一層的網卡是不是丟包?另外就是DPDK的PMD進程的CPU占用率是不是特別的高,因為默認的網卡接收網絡包是通過中斷通知內核來接收包,但是DPDK進行了優化,它通過主動polling的模式減少中斷,它在用戶態有一個PMD的進程,他會不斷地從網卡里面去polling,會占用大量CPU,如果他CPU特別高就說明接收包的速度本身就很高了。這時候要注意觀察流量是否存在熱點,流量是否突破單臺瓶頸。對于虛擬網關來說,使用的是一致性哈希的方法選擇網關,隨著持續的浮動IP的創建和刪除,分布不一定均衡,就算IP分布均衡,這些IP對應的業務其實沒有那么均衡,例如多個熱點請求落到一個網關上。如果說是存在熱點,導致DPDK的PMD進程CPU過高,可以采取的策略是高流量的IP地址可以進一步地打散,重新調整哈希的策略。另外會觀察是否超過單臺的瓶頸,我們會測試每臺機器的IO的瓶頸,也會進行QoS限流,如果是超過了瓶頸,說明這一臺的確壓力過大,如果其他的節點網絡IO還相對比較低,基本上也是熱點問題。如果都高,則說明需要擴容。另外網關要注意區分走哪種類型的網關,通過測試,我們發現DNAT網關由于是一對一的,性能比較好。SNAT因為共享IP并且要計算哈希,還要做conntrack,吞吐量不太容易優化上去。對于功能需求走SNAT網關比較方便的應用,可以建議用戶換成DNAT網關,從而獲得高的吞吐量。
如果入口流量沒有問題,這時候就要看服務器之間的調用是不是有問題,因為我們的容器是套在虛擬機里面的,主要起編排和發布的作用,這時候就要看云主機的steal是不是特別的高,對于物理機上的cpu,多個虛擬機會競爭排隊,排隊不上就會等待,等待的時候就會出現CPU steal,網絡吞吐量肯定就上不去,甚至會出現丟包,因為收到的網絡包來不及處理。另外就是磁盤的IO utils是不是有異常,雖然容器中多部署無狀態服務,對于磁盤的依賴相對比較小,日志也是以異步的方式輸出的,但是有時候也會存在IO hang的情況,這時候就要看IO的監控。如果需要細致的分析,可以登錄到宿主機上看KVM,分析KVM的性能的瓶頸在哪里,在虛擬機里面進行網絡監控之外,在宿主機上可以對虛擬網絡的組件進行分析,測試兩個集群之間的虛擬網絡組件是否出現了問題。
分析完了網絡和存儲虛擬化,接下來看計算虛擬化KVM。可以做一些定制化的一些調優,比如說CPU的BIOS中會把C-States和P-States這種節能開關關掉,如果是核心業務集群,不需要打開這些開關。另外就是物理CPU和vCPU的綁定,這是為了解決steal的問題,如果把核綁到虛擬機上,基本上就不會存在VCPU在物理CPU之間切換的問題,就會把steal解決掉。另外是NUMA親和性的問題,在同一個NUMA Node中,CPU對內存的訪問就會快一些,跨NUMA node就會慢一點,分配的時候盡量是同樣CPU和同樣的內存放在同一個NUMA 節點。虛擬機網卡可以通過SR-IOV的方式來進行優化,云主機綁定核也是在grub中設定好,一臺機器上面能起多少個服務,給宿主肌留多少核,給監控留多少核,然后最后給應用留多少核,都是提前規劃好的,例如前幾個核是給宿主機自己去用的,然后幾個核是留給DPDK去用的,最后幾個核是留給監控去用的,中間的核留給服務。
對于限流策略問題,基礎設施層和業務層有一個配合的問題,底層的網絡有QoS流控的,業務其實也有限流的,這兩個值要匹配起來,否則會有問題,比如當業務層把線程數調大的時候,結果基礎設施層被限流了會出現丟包。
當我們從監控里面看到有丟包事件的時候,業務層會懷疑是虛擬網絡的問題,丟包了以后TCP會重傳,重傳會使得響應比較的慢。在沒有定位到到底哪個環節丟包的時候,可以先做如下的處理。為了使TCP的丟包重傳和流控策略不要用默認的策略,也即一旦出現了丟包,內核協議棧就認為網絡擁塞,從而減少擁塞窗口,這時候本來就想加速重傳,結果窗口下來了,想加速也加不上去。如果切換成BBR,出現丟包的時候就會好很多。但是我們還是就要看底層的網絡,網絡包會丟在什么地方。
最后實在沒有辦法,就需要登到物理機上去debug整條鏈路。從集群A到集群B中間抽出兩臺機器進行測試。測試完畢后通過tcpdump進行分析虛擬機和虛擬機之間的情況,通過ovs-tcpdump可以分析兩臺物理機上的OVS之間的情況,物理機之間的鏈路可需要進行分析。如果包的數目比較多,需要寫程序比對時間戳序列號。抓包分析之后,我們發現兩個集群之間并不是任何兩兩個服務之間都會丟包,而是發生在兩個集群全部在某一批匯聚交換機出現。原來從來沒有懷疑過是物理硬件的問題,物理交換機的監控網粒度往往不會非常細,而且有堆疊這種高可用策略,在監控調整到分鐘級別的時候,看流量根本就沒有達到上限。但是一旦我們發現出問題的兩個集群總是要過某一臺匯聚交換機的時候,我們就建議網管,你能不能把那臺的監控配置到秒級,然后就發現問題了,就是分鐘級監控沒有超過它的瓶頸,但是秒級的監控就會發現它瞬時流量是超過了瓶頸的,因而會丟包。原因是部署緩存集群的時候,實例過于集中了,兩個集群之間的交互基本上都集中在同一個匯聚交換機上,導致出了問題,接下來的方式就是把網絡優化型的實例打散了以后,只要流量瞬時不會超過物理交換機峰值,基本上就沒有問題了。這個例子最后有一點狗血,其實這是一個分析思路,從應用層逐漸的去分析,架構部就要協調各個層次,最后才把這個事情定位到好,我今天的分享就到這里。
福利掃描添加小編微信,備注“姓名+公司職位”,入駐【CSDN博客】,加入【云計算學習交流群】,和志同道合的朋友們共同打卡學習!
推薦閱讀:
現在云原生微服務架構特別的火,有非常多的優勢,比如說這里面寫的快速迭代,高并發,可維護,可擴展,灰度發布,高可用,這些詞大家都耳熟能詳,這些就不用細說了。但是微服務不是沒有成本的,如果說單體應用的復雜度大概是10的話,上了微服務可能是變成100,可能是十倍的復雜度提高,需要投入大量的人去做這個事兒,并且需要一定的支撐系統和工具鏈,才能將這些復雜性降下來。我這邊總結了一下微服務實施之后,會大概率出現以下的痛點:第一:服務依賴的管理。就是一個服務到底調用了哪些,被哪些服務調用,如果依賴管理比較混亂,就會比較痛苦,比如說你要發布一個應用,你可能不知道這個應用被誰依賴了,有沒有有一個特別關鍵的應用在依賴于我這個應用,會不會我升級了以后是否會引發關鍵業務的不穩定,是應該白天發布,還是凌晨發布,這個時候我們就特別需要希望有一個系統能夠看到任何一個服務都被哪些服務依賴以及依賴于哪些服務。第二:調用統計問題。對于調用記錄有一個統計和告警,例如有沒有接口突然調用失敗率增高,有沒有接口突然時延增長,都應該及早發現,而不能因為因為一次發布引入一個bug,導致時延變長但無人知曉,等到流量一來,直接就可能壓掛了。再就是有沒有接口再也沒有人調用,這個接口是否可以下線,這在接口升級的時候,常常采取先添加接口,再下線接口的方式,就需要這樣一個統計系統。第三:接口規范問題。各個團隊開發出來的各個服務的接口是否符合統一的接口規范,有沒有統一的地方去看接暴露出來的接口?如果說有的接口不遵守規范,那么是不是時候會在同一個地方能看到,然后去盡早的去發現這個問題。第四:安全管理。很多企業往往通過白名單通過配置中心配到各個服務里面去的,比如說支付這個服務不是所有服務都能調用的,只有部分服務可以調用他。這些配置原來都是散落在這個服務里面去的,各自為站,有可能一不小心就配置錯了或者漏了,應該能訪問的訪問不了,不該訪問的能夠訪問了,但是沒有人察覺。第五:熔斷限流降級這些服務治理能力。雖然有很多開源組件可以做這些事情,但是需要寫大量重復代碼去做,同樣是散落在各個地方。第六:接口測試問題。我們如何保證在不斷的拆合的過程中不會引入新的bug,這其實是比較頭疼的一個事情,所以需要一個比較大的一個測試集合,就需要一個測試平臺來保證。第七:灰度發布問題。很多公司做灰度發布,都是通過代碼里面寫if-else做的,當什么條件滿足的時候,走這個邏輯,當時什么條件滿足的時候,走那個邏輯,這個時候也是相對比較痛苦的。第八:壓力測試問題。這一般是實施微服務的后期,當需要面對大規模流量的時候,才會引入進來的。一開始線上大促的時候,基本處于這種一臉蒙,靠運氣的這種狀態,心里壓根都沒有譜,必須要通過壓力測試去做這個事兒。第九:調用鏈分析問題。一旦出現慢的時候,相對比較難以發現慢的點,尤其是當服務數目多,調用鏈長了之后。第十:測試環境治理。服務數目增多了,大家都用了容器,帶來的好處就是部署的特別方便,一個編排就能啟動一套系統,但是同時也帶來一個痛苦,其實我們從云的時候就有這個痛苦,一旦放給大家的權限讓大家可以隨時部署,對于資源的使用就控制不住了,大家誰都想啟動一個新的環境,自己的測試環境和別人都不在一塊。如果說只有幾個容器,那么每次都重新部署一個新環境,這沒有問題,但是如果服務特別多的時候,例如一百個容器的時候,這時候全量部署比較困難。為了解決這些問題,需要配備比較復雜的工具集合:容器平臺負責聲明式部署,持續集成和測試平臺負責灰度發布和測試集合的維護,API網關負責入口流量的接入,微服務框架負責微服務之間的相互調用,管理和治理,分布式事物負責拆分后的事務問題,APM性能管理負責調用鏈分析。我們后面也能看到這些組件在定位問題的過程中都起到了什么樣子的作用。微服務的拆分過程并不是一蹴而就的,我們發現很多公司開始計劃實施微服務的時候,往往第一個問題是微服務應該怎么拆,應該拆分到什么粒度?覺得是這是一個最重要的一個維度。后來我們發現其實并不是這個樣子的,微服務的拆分只是其中很小的一個方面,需要匹配一套工具鏈,并且經歷十二個過程,逐步完成。接下來,我們來解析一個微服務場景下的問題定位過程。為什么說在微服務場景下,我們發現定位問題的時候,我們會覺得它特別的復雜,往往需要架構師牽頭協調各個部門一塊去定位某個問題。首先第一個復雜度就是,從頂層到底層這個層次是實在是太多了,我們能想到就是任何一個比如說我們發現請求比較慢的時候,我們首先會想到整個層次中,最上面的應用是不是出了問題,應用這一層本身就比較復雜,圖中密密麻麻的線是double服務之間的一個調用關系,它的復雜度已經十分高了,然后中間一旦出現了慢請求,這時候其實很難定位到一哪一個點,哪個服務集群調用哪個服務集群。
應用層下面這就是容器層,容器下面其實是openstack的云網絡,我們采取方式是kubernetes和openstack整合的一個方式。因為kubernetes對于容器的發布,運行十分友好,對于網絡尤其是多機房高可用橫向擴展的vpc網絡特性相對弱一些,那么正好云在VPC這方面相對比較強一些,例如浮動ip,跨機房高科用,專線等。容器層或者云網絡層,都可能產生問題,例如容器網卡吞吐量受限制,或者ovs吞吐量受限制,都會造成性能問題。再往下是物理網絡,因為牽扯到多機房了,那么可能每機房還有多高可用區,那么整個機房的拓撲結構邏輯也會很復雜。這時候就可以想象說當一個服務的多個副本構成一個業務集群,當從一個業務集群到另一個業務集群時延高,每個層次都其實都有可能出現問題是吧?然后我們就需要層層的去排查這個事情。
另外一個相對比較頭疼的一個事,是從前端到后端的層級也是挺多的。問題往往是在壓測的時候會發現,那么壓測的時候,我們是在我們公有云上去壓真實線上的業務,所以其實是走公有網絡的。我們可以想象,從前端到后端經歷的環節實在是太多了,你比較難判斷他會慢在什么地方。一開始進入機房,有邊界路由器,然后有核心匯聚交換機,這是網管部去管的。接下來就進入了虛擬的云網絡網關,由云計算部門維護。云網關進來后,會有一層負載均衡,這個負載均衡是可以適配多機房的負載均衡,可以做跨機房浮動IP漂移。再往里面會有個API網關作為接入層,然后再往后就是服務層了。服務層分業務服務層和基礎服務層,之間會引入注冊發現機制,比如說用dubbo管理他們之間的相互調用。由于微服務規模比較大,就像剛才圖中展示的一樣,復雜度很高。業務之間調用完畢之后,最終肯定是要落庫的,這時候會涉及到緩存的訪問,緩存后面是數據庫。有時候還涉及到調用云外的系統,因而需要經過云網絡的網關。比如說外部的一些支付系統,安全檢測系統,包括大數據等,都是云外的。這兩次網關其實是不一樣的,前面網關是DNAT網關,后面網關是SNAT網關。可以想象一旦出現性能問題的時候,經過這么多環節就比較頭疼,經常會困惑,這個問題到底出現在哪個環節呢?一般來說,性能問題往往通過線上性能壓測發現的。一般大促之前,提前一段時間,就要開始進行壓測。壓的時候就會涉及到從前往后,從底到上的所有的系統和部門,都要派代表去參加,哪一塊出現了問題,哪一個環節出現了性能瓶頸,哪一塊就要改。線上壓力測試需要有一個性能測試的平臺,做多種形式的壓力測試。例如容量測試,通過梯度的加壓,看到什么時候實在不行。摸高測試,測試在最大的限度之上還能承受多大的量,有一定的余量會保險一些,心里相對比較有底。再就是穩定性測試,測試峰值的穩定性,看這個峰值能夠撐一分鐘,兩分鐘還是30分鐘。還有秒殺場景測試,限流降級演練測試等。有的時候壓測會遇到讓人崩潰的事情,例如可能前幾天壓測的時候,看著吞吐量在向好的方向發展,突然有一天一下子就降下來了,這個時候離大促時間越來越近,心態就會比較崩潰,需要大家一塊去看到底是什么問題。對于測試環境的管理,也是非常關鍵的。線上壓測的時候,為了讓數據和正式的線上數據實現隔離,常用的方法是對于消息隊列,緩存,數據庫,都是使用影子的方式。就需要流量染色的技術,帶一個tag進去,說明這個請求是測試數據,還是真實數據。流量染色的功能,除了壓測里面使用,還可以用于測試環境治理。在大規模微服務場景下,不可能每個部門部署一套完整的環境,因為耗費的資源量實在是太大了。這時候就需要合理規劃測試環境。測試環境是應該和持續集成的流程緊密協作的。我們使用分支開發的方式,每個功能的開發在分支上,上線的時候,合并到主分支上來,主分支對應線上環境。對于測試環境的規劃,也是采取類似的思路。我們會有一個基準測試環境,對應master分支,里面部署全量的應用。每一個分支,比如說你修改了五個工程,測試的時候,不需要部署全量的應用,只需要把這五個工程去創建一個Delta測試環境就可以了。當客戶端進行測試的時候,帶上一個此分支的tag,從API網關開始,微服務框架嵌入的jar會將這個tag一直帶下去。當這五個服務之內相互調用的時候,微服務框架就會選擇這五個服務的實例進行調研,如果需要調用五個服務之外的其他服務的時候,微服務框架會到master環境里面,選擇服務實例進行調用。有了流量染色的環境治理機制,測試環境數量就會小小特別多。
壓測中一旦出現了慢請求,最先從哪里能夠看出來呢。在微服務的接入層有API網關這一層。在API網關中,有一個調用統計功能,可以篩選出慢請求。在壓測的時候,每一輪都有一個壓測結果,是一個列表,按請求時間排序。通過這個列表,可以篩選出這次壓測的時候,最慢的接口都是哪一些,異常的接口(也即請求響應速度有巨大反差)有哪一些?我們就可以針對于這些接口進行特別的排查。在服務治理平臺中,服務之間的調用也有一個統計,也有個一個排名,同樣會列出來哪幾個應用需要改進,重構,或者排查。
和壓測匹配的一個重要的系統是全方位的性能監控。一般的監控平臺僅僅會監控第一項就是服務器的性能,比如cpu,內存,網卡等。其實監控應該是全方位的,對于應用方面的,應該監控堆的內存,GC,線程,cpu利用率等。業務指標應該監控下單數,支付數,購物車請求數等。調用鏈路監控應該包括RT值,TPS等。應用組件應該監控連接的狀態,消息積壓,zookeeper節點數等。還應該有一些異常監控,例如異常的流量,Exception,報警等。這些都是在統一的一個平臺上去做的。定位問題需要深度的依賴于這個平臺,一般先在這個平臺上去找到大概的問題點,如果不能找到真正原因的話,就可以更加細粒度的登到機器上去看。沒有統一的監控,會在大規模微服務場景下,有了問題,比較茫然,根本找不到地方。有了統一監控平臺,我們也在壓測的時候,在API網關上發現了慢請求,接下來就需要逐層定位了。高延遲的現象往往會先出現在應用層,外部的現象就是外部請求的時延高,如果順著調用鏈定位下來,往往會反應到內部從一個服務集群到另一個服務集群的RT值高或者出現大量超時異常。我們可以查看對于服務之間相互調用的監控,dubbo和hystrix我們做了集成,右下角的這個圖是熔斷的基本原理。通過監控我們可以發現有熔斷的情況出現,我們就知道這可能是出現了問題。
一旦出現了問題,架構部一步一步來分析分析這個問題。我們的排查思路是從上層往下層,從業務層往底層層層排查,因為如果讓物理網絡或者虛擬網絡直接去定位,會比較迷茫。第一步:先應用層初步定位。第一件事情,查看近期是否有新變更的發布上線,例如昨天壓測的時候還正常,這次突然出現超時,很可能是新的發布導致的。我們可以重點查看新發布的應用,甚至可以進行代碼review。
如果新發布的應用沒有發現問題,就需要在整條調用鏈路上定位問題了。這個時候應用性能監控APM可以幫上忙,他可以在整條調用鏈路里面,找到最耗時的那個環節,這是我們應該重點定位問題的地方。
在最耗時的環節上,如果我們發現TPS比較低,相應時間長,但是CPU使用率不高。
我們可以通過服務治理平臺,查看這兩個服務之間的調用是否開啟了足夠的線程池,當前的線程池是否已經被打滿,如果滿了,是否可以提高線程池的數目,這和集群所在的虛擬機和物理的核的分配是有關系的,因為核數用完了,再多的線程徒增調度成本,沒有收益。如果可以提供線程池的數目,可以通過配置中心進行統一的配置這個服務集群的線程池數目。很多情況下,性能的降低的原因在于數據庫層,這一點在APM上也能看的出來。這個時候應該DBA去查看問題,可以梳理一下SQL語句,通過慢SQL分析,查看慢的原因,例如索引問題,死鎖問題等,這些都可以通過Mysql或者DDB的日志找出來。
另外一個經常出現的問題就是TPS比較低,但是CPU使用率非常高。這時候我們需要通過監控系統查看線程的狀態,查看耗時的方法列表以及調用棧,看哪個線程耗時比較多,是否因為業務邏輯的Bug,是否在一直計算某個東西,或者出現業務層的死鎖。另外就是看是否頻繁的FullGC,一旦出現了FullGC就會出現一段時間的業務邏輯暫停,在大促本來壓力就很大,而且峰值時間比較短的情況下,一個線程hang就會使得調用鏈擁塞一片。我們要通過監控系統查看堆的信息,找出耗內存的對象,看是否內存一直往上漲,是否存在泄露。另外對于緩存的一個監控,應用層的緩存設計一般有多層。我們本來一開始設計的是有三層緩存的,localcache有兩層,然后分布式緩存有一層,localcache分主動刷新和被動刷新的兩層,被動刷新就是遇到請求了再刷新,主動刷新是主動的去過一段時間去刷新。后來我們又把三層緩存簡化成了兩層緩存,被動刷新的localcache的命中率已經足夠用了,再多一層反而會降低性能。我們之所以監控緩存,是因為我們發現有時候應用層Key使用的不對,或者是配置的不對,會導致緩存層失效,請求就會直接打到數據庫,導致請求相對比較的慢。對于緩存的監控,我們在緩存的客戶端的jar,會和配置中心進行聯動,監控某些我們認為相對比較重要的Key,當Key出現緩存丟失,寫頻繁,或者寫丟失等類似這種事件的時候,它就會上報到我們的監控系統。這個時候,就會發現導致緩存失效的程序Bug。
第二步:如果應用層沒有問題,則檢查異常流量。
如果我們確認應用層的確沒有問題,就需要開始往下層去進行懷疑了。首先第一個比較懷疑的是,是不是出現異常流量。比如說有外部的異常流量,可以問問網管和安全部是否網站被DDoS,另外入口網關是否接受到了大量的請求,例如有臨時的促銷或者臨時的事件。如果入口沒有問題,則查看集群的監控,要對照著兩個指標看,一個是服務端的請求數目的一個統計,看是否有集中的熱點,比如說一個集群有多個副本,其中某個副本收到的請求量特別的大,而其他副本收到的請求數相對比較低。二是在云主機里面的網卡虛擬網卡,也是能夠看到相應的監控的,看是不是網絡流量就集中到某幾臺機器上。這兩個會有一個對照,如果兩方面指標能夠對照起來,集中熱點比較容易定位,也即請求數上去了,同時云網絡的網卡流量也上去了。當出現了熱點的時候,就需要通過服務治理中心或者配置中心,將請求打散。如果兩個指標不匹配,這時候就有問題了,也即服務端請求的數目其實并沒有多,但是云網絡發現出現了問題,這時候就就可能是底層基礎設施的問題,我們這個例子遇到這個點就是相對比較詭異,還需要接著解析。
如果不是異常流量,就需要從前往后再來梳理這個事,比如說從核心交換機到VPC的網關區域這些是不是出了問題,這時候就要聯系機房的網管部門去定位,然后是VPC網關到云的負載均衡,然后是從負載均衡到應用的API網關,然后API網關到應用的Controller層,然后是中間的dubbo調用,然后緩存層到數據庫層。接下來要按照整個鏈路依次的去排查。
這里畫了一張經比較經典的機房的一個圖,其實任何一家公司機房的樣子要比這個圖可能要復雜得多,這就需要架構部門對機房的架構相對比較清楚。我們會分機房,分可用區,還會分二級可用區,他們會走不同的匯聚交換機,在監控系統里面也要標明某個服務器群和另一個服務集群之間的訪問到底是哪個物理機集群到哪個物理機集群之間的訪問,這時候你心里可能需要清楚他們是否在同一個機架里面,或者是在同一個二級可用區,還是在同一個一級可用區,是跨機房了,或者是甚至到異地了,這時候你要心里有個數,因為他們之間的時延都是不一樣的。
第二個就是對于VPC網絡的架構是要比較清楚。我們是通過OpenStack Neutron的vxlan去做的這個事情的。橫向流量是通過vxlan,基于OVS去做的,縱向的流量,出去的時候會有網關,我們不是用的物理網關,而是虛擬網關,在數據中心里面有一個虛擬網關的網關層,網關層有的時候是掛在匯聚交換機下面的,有的機房要求吞吐量比較大,網關層可以直接掛在核心交換機下面的,很可能網絡瓶頸點會發生在這些網關上。
我們的VPC網絡是有一定的改進的,因為我們要求一個VPC里面能承載的虛擬機的數量要比開源的OpenStack要多得多,能達到5萬臺的規模。限制網絡規模的一是廣播問題,我們可以事先把整個網絡拓撲下發到一個拓撲庫上去,每一個節點上的Agent會訂閱拓撲庫的更新事件,從而更新本地的OVS策略。每個Agent都會看到整個網絡的拓樸結構,則ARP的時候,本地就可以攔截來進行返回。另外的一個改進就是虛擬網絡,默認的虛擬網關只能做主備,橫向擴展能力沒有這么好,不能夠承載大的并發量,這其實需要有一排的虛擬網關,全部掛載到匯聚或者核心交換機上。接下來的問題是縱向的流量怎么從這一排網關里面去選擇,這里使用了一致性哈希的算法。
另外一個改進是Kubernetes和OpenStack的整合。左面的圖是Kubernetes默認創建一個Pod的流程,好在他是基于事件驅動的,使得我們可以定制化右面創建Pod的流程。我們開發了自己的Resource Controller和Scheduler,當發現容器的節點資源不足的情況下,Controller會調用IaaS的接口創建云主機,然后加到Kubernetes集群中。這種模式下,在應用層的角度,只能看到容器,不需要運維Kubernetes,更加看不到OpenStack的接口,使得應用層有統一的編排接口。
另外對于容器和Kubernetes層的整合,網絡層也需要整合,容器也要融合VPC網絡,只有適配了VPC網絡才能實現多機房的高可用性,跨機房的負載均衡,以及跨機房的浮動IP漂移和切換。比如說一個機房掛了,則掛在A機房的浮動IP地址要能夠切換到B機房的網關上去,并且和核心交換機有聯動,路由也要切過來,這些都只有VPC可以完成這個事情。我們開發了一個自己的CNI插件去做這個事兒,容器沒有使用單獨容器網絡方案,而是直接用了OVS的網絡,也即OpenStack的OVS是可以直接看到容器的IP地址的,容器的IP地址和虛擬機的IP是平的,是屬于同一個局域網。這樣其實還有另外一個好處,因為我們還有很多沒有容器化的應用,如果部分做容器化,是可以和容器內的應用無縫的打通的。一些有狀態的PaaS也是部署在虛擬機里面的,也可以實現在同一個局域網內的互通。
另外一個針對Kubernetes的優化就是規模問題,這是其中的一個優化的例子。重啟一個API server的時候會導致一些問題,尤其是在Pod的數目比較多的時候。通過監控圖可以看出,中間會重啟時間長達七分鐘,中間出現429錯誤并且飆升,是因為流控。為什么會流控?因為它重啟的時候,會有大量的請求重新再連上來,由于并發太多,有可能就把它再沖掛了。
那么應該如何改進呢?方法一就是多級流控,根據UserAgent, Resource, Verb幾個參數,對于不同的客戶端有不同的流控策略,比如說對于master上面的進程優先級相對高一點,對于kubelet結點上的進程,優先級就低一些。不會所有的kubelet節點一股腦上來進行注冊。方法二是擁塞控制,Retry-After參數也即多長時間再重試一次,這個原來是一個默認值,我們改成一個動態的值,根據系統的繁忙程度是調節到1秒到8秒之間,這樣不同的客戶端重試的時間會錯開。使得把整個恢復時間大幅度的降低了,這是我們做的規模化的一個例子。
來我們從接入層開始分析。我們在VPC的網關以及負載均衡層也是做了優化的。優化之一是基于BGP ECMP的等價路由,也即對于LB集群和前面的核心交換機之間配置等價路由,實現橫向擴展和負載均衡。如果使用LVS做這個網關的話,可以使用DPDK技術,也即基于DPVS的負載均衡。電商請求基本上都是基于HTTPS協議的,SSL往往通過offload的方式通過硬件進行加速,在壓力大的時候,優化明顯。
對于負載均衡這一層的問題,出問題的點往往在于虛擬網關和負載均衡,我們要中斷看這一層的網卡是不是丟包?另外就是DPDK的PMD進程的CPU占用率是不是特別的高,因為默認的網卡接收網絡包是通過中斷通知內核來接收包,但是DPDK進行了優化,它通過主動polling的模式減少中斷,它在用戶態有一個PMD的進程,他會不斷地從網卡里面去polling,會占用大量CPU,如果他CPU特別高就說明接收包的速度本身就很高了。這時候要注意觀察流量是否存在熱點,流量是否突破單臺瓶頸。對于虛擬網關來說,使用的是一致性哈希的方法選擇網關,隨著持續的浮動IP的創建和刪除,分布不一定均衡,就算IP分布均衡,這些IP對應的業務其實沒有那么均衡,例如多個熱點請求落到一個網關上。如果說是存在熱點,導致DPDK的PMD進程CPU過高,可以采取的策略是高流量的IP地址可以進一步地打散,重新調整哈希的策略。另外會觀察是否超過單臺的瓶頸,我們會測試每臺機器的IO的瓶頸,也會進行QoS限流,如果是超過了瓶頸,說明這一臺的確壓力過大,如果其他的節點網絡IO還相對比較低,基本上也是熱點問題。如果都高,則說明需要擴容。另外網關要注意區分走哪種類型的網關,通過測試,我們發現DNAT網關由于是一對一的,性能比較好。SNAT因為共享IP并且要計算哈希,還要做conntrack,吞吐量不太容易優化上去。對于功能需求走SNAT網關比較方便的應用,可以建議用戶換成DNAT網關,從而獲得高的吞吐量。
如果入口流量沒有問題,這時候就要看服務器之間的調用是不是有問題,因為我們的容器是套在虛擬機里面的,主要起編排和發布的作用,這時候就要看云主機的steal是不是特別的高,對于物理機上的cpu,多個虛擬機會競爭排隊,排隊不上就會等待,等待的時候就會出現CPU steal,網絡吞吐量肯定就上不去,甚至會出現丟包,因為收到的網絡包來不及處理。另外就是磁盤的IO utils是不是有異常,雖然容器中多部署無狀態服務,對于磁盤的依賴相對比較小,日志也是以異步的方式輸出的,但是有時候也會存在IO hang的情況,這時候就要看IO的監控。如果需要細致的分析,可以登錄到宿主機上看KVM,分析KVM的性能的瓶頸在哪里,在虛擬機里面進行網絡監控之外,在宿主機上可以對虛擬網絡的組件進行分析,測試兩個集群之間的虛擬網絡組件是否出現了問題。
分析完了網絡和存儲虛擬化,接下來看計算虛擬化KVM。可以做一些定制化的一些調優,比如說CPU的BIOS中會把C-States和P-States這種節能開關關掉,如果是核心業務集群,不需要打開這些開關。另外就是物理CPU和vCPU的綁定,這是為了解決steal的問題,如果把核綁到虛擬機上,基本上就不會存在VCPU在物理CPU之間切換的問題,就會把steal解決掉。另外是NUMA親和性的問題,在同一個NUMA Node中,CPU對內存的訪問就會快一些,跨NUMA node就會慢一點,分配的時候盡量是同樣CPU和同樣的內存放在同一個NUMA 節點。虛擬機網卡可以通過SR-IOV的方式來進行優化,云主機綁定核也是在grub中設定好,一臺機器上面能起多少個服務,給宿主肌留多少核,給監控留多少核,然后最后給應用留多少核,都是提前規劃好的,例如前幾個核是給宿主機自己去用的,然后幾個核是留給DPDK去用的,最后幾個核是留給監控去用的,中間的核留給服務。
對于限流策略問題,基礎設施層和業務層有一個配合的問題,底層的網絡有QoS流控的,業務其實也有限流的,這兩個值要匹配起來,否則會有問題,比如當業務層把線程數調大的時候,結果基礎設施層被限流了會出現丟包。
當我們從監控里面看到有丟包事件的時候,業務層會懷疑是虛擬網絡的問題,丟包了以后TCP會重傳,重傳會使得響應比較的慢。在沒有定位到到底哪個環節丟包的時候,可以先做如下的處理。為了使TCP的丟包重傳和流控策略不要用默認的策略,也即一旦出現了丟包,內核協議棧就認為網絡擁塞,從而減少擁塞窗口,這時候本來就想加速重傳,結果窗口下來了,想加速也加不上去。如果切換成BBR,出現丟包的時候就會好很多。但是我們還是就要看底層的網絡,網絡包會丟在什么地方。
最后實在沒有辦法,就需要登到物理機上去debug整條鏈路。從集群A到集群B中間抽出兩臺機器進行測試。測試完畢后通過tcpdump進行分析虛擬機和虛擬機之間的情況,通過ovs-tcpdump可以分析兩臺物理機上的OVS之間的情況,物理機之間的鏈路可需要進行分析。如果包的數目比較多,需要寫程序比對時間戳序列號。抓包分析之后,我們發現兩個集群之間并不是任何兩兩個服務之間都會丟包,而是發生在兩個集群全部在某一批匯聚交換機出現。原來從來沒有懷疑過是物理硬件的問題,物理交換機的監控網粒度往往不會非常細,而且有堆疊這種高可用策略,在監控調整到分鐘級別的時候,看流量根本就沒有達到上限。但是一旦我們發現出問題的兩個集群總是要過某一臺匯聚交換機的時候,我們就建議網管,你能不能把那臺的監控配置到秒級,然后就發現問題了,就是分鐘級監控沒有超過它的瓶頸,但是秒級的監控就會發現它瞬時流量是超過了瓶頸的,因而會丟包。原因是部署緩存集群的時候,實例過于集中了,兩個集群之間的交互基本上都集中在同一個匯聚交換機上,導致出了問題,接下來的方式就是把網絡優化型的實例打散了以后,只要流量瞬時不會超過物理交換機峰值,基本上就沒有問題了。這個例子最后有一點狗血,其實這是一個分析思路,從應用層逐漸的去分析,架構部就要協調各個層次,最后才把這個事情定位到好,我今天的分享就到這里。
福利掃描添加小編微信,備注“姓名+公司職位”,入駐【CSDN博客】,加入【云計算學習交流群】,和志同道合的朋友們共同打卡學習!
推薦閱讀:
- 漫畫:什么是希爾排序?
- 一次失敗的面試,復習一次一致性哈希算法
Pandas中第二好用的函數 | 優雅的Apply
- 程序員因接外包坐牢 456 天!兩萬字揭露心酸經歷
限時早鳥票 | 2019 中國大數據技術大會(BDTC)超豪華盛宴搶先看
阿里開源物聯網操作系統 AliOS Things 3.0 發布,集成平頭哥 AI 芯片架構!
- 雷聲大雨點小:Bakkt「見光死」了嗎?
總結
以上是生活随笔為你收集整理的靓仔落泪,性能问题定位难倒我了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Boost:align down向下对齐
- 下一篇: 大数据从哪里来?| 技术头条