10+倍性能提升全過程--優酷賬號綁定淘寶賬號的TPS從500到5400的優化歷程

10+倍性能提升全過程--優酷賬號綁定淘寶賬號的TPS從500到5400的優化歷程

摘要: # 10+倍性能提升全過程--優酷賬號綁定淘寶賬號的TPS從500到5400的優化歷程 ## 背景說明 > 2016年的雙11在淘寶上買買買的時候,天貓和優酷土豆一起做了聯合促銷,在天貓雙11當天購物滿XXX元就贈送優酷會員,這個過程需要用戶在優酷側綁定淘寶賬號(登錄優酷、提供淘寶賬號,優酷調用淘寶API實現兩個賬號綁定)和贈送會員並讓會員權益生效(看收費影片、免廣告等等) >

10+倍性能提升全過程--優酷賬號綁定淘寶賬號的TPS從500到5400的優化歷程

背景說明

2016年的雙11在淘寶上買買買的時候,天貓和優酷土豆一起做了聯合促銷,在天貓雙11當天購物滿XXX元就贈送優酷會員,這個過程需要用戶在優酷側綁定淘寶賬號(登錄優酷、提供淘寶賬號,優酷調用淘寶API實現兩個賬號綁定)和贈送會員並讓會員權益生效(看收費影片、免廣告等等)

這裏涉及到優酷的兩個部門:Passport(在上海,負責登錄、綁定賬號,下文中的優化過程主要是Passport部分);會員(在北京,負責贈送會員,保證權益生效)

在雙11活動之前,Passport的綁定賬號功能一直在運行,只是沒有碰到過大促銷帶來的挑戰


會員部分的架構改造

  • 接入中間件DRDS,讓優酷的數據庫支持拆分,分解MySQL壓力
  • 接入中間件vipserver來支持負載均衡
  • 接入集團DRC來保障數據的高可用
  • 對業務進行改造支持Amazon的全鏈路壓測

主要的壓測過程

screenshot.png

上圖是壓測過程中主要的階段中問題和改進,主要的問題和優化過程如下:

- docker bridge網絡性能問題和網絡中斷si不均衡    (優化後:500->1000TPS)
- 短連接導致的local port不夠                   (優化後:1000-3000TPS)
- 生產環境snat單核導致的網絡延時增大             (優化後能達到測試環境的3000TPS)
- Spring MVC Path帶來的過高的CPU消耗           (優化後:3000->4200TPS)
- 其他業務代碼的優化(比如異常、agent等)         (優化後:4200->5400TPS)

優化過程中碰到的比如淘寶api調用次數限流等一些業務問題就不列出來了


Passport部分的壓力

由於用戶進來後先要登錄並且綁定賬號,實際壓力先到Passport部分,在這個過程中最開始單機TPS只能到500,經過N輪優化後基本能達到5400 TPS,下面主要是闡述這個優化過程

Passport 核心服務分兩個:

  • Login 主要處理登錄請求
  • userservice 處理登錄後的業務邏輯,比如將優酷賬號和淘寶賬號綁定

爲了更好地利用資源每臺物理加上部署三個docker 容器,跑在不同的端口上(8081、8082、8083),通過bridge網絡來互相通訊

Passport機器大致結構

screenshot.png

說明:這裏的500 TPS到5400 TPS是指登錄和將優酷賬號和淘寶賬號綁定的TPS,也是促銷活動主要的瓶頸

userservice服務網絡相關的各種問題


太多SocketConnect異常(如上圖)

在userservice機器上通過netstat也能看到大量的SYN_SENT狀態,如下圖:

因爲docker bridge通過nat來實現,嘗試去掉docker,讓tomcat直接跑在物理機上

這時SocketConnect異常不再出現

從新梳理一下網絡流程

docker(bridge)----短連接--->訪問淘寶API(淘寶open api只能短連接訪問),性能差,cpu都花在si上;

如果 docker(bridge)----長連接到宿主機的某個代理上(比如haproxy)-----短連接--->訪問淘寶API, 性能就能好一點。問題可能是短連接放大了Docker bridge網絡的性能損耗

當時看到的cpu si非常高,截圖如下:

去掉Docker後,性能有所提升,繼續通過perf top看到內核態尋找可用的Local Port消耗了比較多的CPU,gif動態截圖如下(可以點擊看高清大圖):

注意圖中ipv6_rcv_saddr_equal和inet_csk_get_port 總共佔了30%的CPU

一般來說一臺機器可用Local Port 3萬多個,如果是短連接的話,一個連接釋放後默認需要60秒回收,30000/60 =500 這是大概的理論TPS值

同時觀察這個時候CPU的主要花在sy上,最理想肯定是希望CPU主要用在us上,截圖如下:

sy佔用了30-50%的CPU,這太不科學了,同時通過 netstat 分析連接狀態,確實看到很多TIME_WAIT:

於是讓PE修改了tcp相關參數:降低 tcp_max_tw_buckets和開啓tcp_tw_reuse,這個時候TPS能從1000提升到3000

優化到3000 TPS後上線繼續壓測

居然性能又回到了500,太沮喪了,其實最開始賬號綁定慢,Passport這邊就懷疑taobao api是不是在大壓力下不穩定,程序員一般都是認爲自己沒問題,有問題的一定是對方 :) ,taobao api那邊給出調用數據都是1ms以內就返回了(alimonitor監控圖表)。

於是懷疑從優酷的機器到淘寶的機器中間鏈路上有瓶頸,但是需要設計方案來證明這個問題在鏈路上,要不各個環節都會認爲自己沒有問題的,當時Passport的開發也只能拿到Login和Userservice這兩組機器的權限,中間的負載均衡、交換機都沒有權限接觸到。

在嘗試過tcpdump抓包、ping等各種手段分析後,設計了場景證明問題在中間鏈路上。

設計如下三個場景證明問題在中間鏈路上:

  1. 壓測的時候在userservice ping 淘寶的機器;
  2. 將一臺userservice機器從負載均衡上拿下來(沒有壓力),ping 淘寶的機器;
  3. 從公網上非優酷的機器 ping 淘寶的機器;

這個時候奇怪的事情發現了,壓力一上來場景1、2的兩臺機器ping淘寶的rt都從30ms上升到100-150ms,場景1 的rt上升可以理解,但是場景2的rt上升不應該,同時場景3中ping淘寶在壓力測試的情況下rt一直很穩定(說明壓力下淘寶的機器沒有問題),到此確認問題在優酷到淘寶機房的鏈路上有瓶頸,而且問題在優酷機房出口扛不住這麼大的壓力。於是從上海Passport的團隊找到北京Passport的PE團隊,確認在優酷調用taobao api的出口上使用了snat,PE到snat機器上看到snat只能使用單核,而且對應的核早就100%的CPU了,因爲之前一直沒有這麼大的壓力所以這個問題一直存在只是沒有被發現。

於是PE去掉snat,再壓的話 TPS穩定在3000左右


到這裏結束了嗎? 從3000到5400TPS

優化到3000TPS的整個過程沒有修改業務代碼,只是通過修改系統配置、結構非常有效地把TPS提升了6倍,對於優化來說這個過程是最輕鬆,性價比也是非常高的。實際到這個時候也臨近雙11封網了,最終通過計算(機器數量*單機TPS)完全可以抗住雙11的壓力,所以最終雙11運行的版本就是這樣的。 但是有工匠精神的工程師是不會輕易放過這麼好的優化場景和環境的(基線、機器、代碼、工具都具備配套好了)

優化完環境問題後,3000TPS能把CPU US跑上去,於是再對業務代碼進行優化也是可行的了

進一步挖掘代碼中的優化空間

雙11前的這段封網其實是比較無聊的,於是和Passport的開發同學們一起挖掘代碼中的可以優化的部分。這個過程中使用到的主要工具是這三個:火焰圖、perf、perf-map-java。相關鏈接:http://www.brendangregg.com/perf.html ; https://github.com/jrudolph/perf-map-agent

通過Perf發現的一個SpringMVC 的性能問題

這個問題具體參考我之前發表的優化文章http://www.atatech.org/articles/65232 。 主要是通過火焰圖發現spring mapping path消耗了過多CPU的性能問題,CPU熱點都在methodMapping相關部分,於是修改代碼去掉spring中的methodMapping解析後性能提升了40%,TPS能從3000提升到4200.

著名的fillInStackTrace導致的性能問題

代碼中的第二個問題是我們程序中很多異常(fillInStackTrace),實際業務上沒有這麼多錯誤,應該是一些不重要的異常,不會影響結果,但是異常頻率很高,對這種我們可以找到觸發的地方,catch住,然後不要拋出去(也就是別觸發fillInStackTrace),打印一行error日誌就行,這塊也能省出10%的CPU,對應到TPS也有幾百的提升。

screenshot.png

部分觸發fillInStackTrace的場景和具體代碼行(點擊看高清大圖):
screenshot.png

對應的火焰圖(點擊看高清大圖):
screenshot.png

screenshot.png

解析useragent 代碼部分的性能問題

整個useragent調用堆棧和cpu佔用情況,做了個彙總(useragent不啓用TPS能從4700提升到5400)
screenshot.png

實際火焰圖中比較分散:
screenshot.png

最終通過對代碼的優化勉勉強強將TPS從3000提升到了5400(太不容易了,改代碼過程太辛苦,不如改配置來錢快)

優化代碼後壓測tps可以跑到5400,截圖:

最後再次總結整個壓測過程的問題和優化歷程

- docker bridge網絡性能問題和網絡中斷si不均衡    (優化後:500->1000TPS)
- 短連接導致的local port不夠                   (優化後:1000-3000TPS)
- 生產環境snat單核導致的網絡延時增大             (優化後能達到測試環境的3000TPS)
- Spring MVC Path帶來的過高的CPU消耗           (優化後:3000->4200TPS)
- 其他業務代碼的優化(比如異常、agent等)         (優化後:4200->5400TPS)

整個過程得到了淘寶API、優酷會員、優酷Passport、網絡、螞蟻等衆多同學的幫助,本來是計劃去上海跟Passport的同學一起復盤然後再寫這篇文章的,結果一直未能成行,請原諒我拖延到現在才把大家一起辛苦工作的結果整理出來,可能過程中的數據會有一些記憶上的小錯誤。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章