摘要: # 10+倍性能提高全過程--優酷帳號綁定淘寶帳號的TPS從500到5400的優化歷程 ## 背景說明 > 2016年的雙11在淘寶上買買買的時候,天貓和優酷土豆一塊兒作了聯合促銷,在天貓雙11當天購物滿XXX元就贈送優酷會員,這個過程須要用戶在優酷側綁定淘寶帳號(登陸優酷、提供淘寶帳號,優酷調用淘寶API實現兩個帳號綁定)和贈送會員並讓會員權益生效(看收費影片、免廣告等等) >html
2016年的雙11在淘寶上買買買的時候,天貓和優酷土豆一塊兒作了聯合促銷,在天貓雙11當天購物滿XXX元就贈送優酷會員,這個過程須要用戶在優酷側綁定淘寶帳號(登陸優酷、提供淘寶帳號,優酷調用淘寶API實現兩個帳號綁定)和贈送會員並讓會員權益生效(看收費影片、免廣告等等)java
這裏涉及到優酷的兩個部門:Passport(在上海,負責登陸、綁定帳號,下文中的優化過程主要是Passport部分);會員(在北京,負責贈送會員,保證權益生效)git
在雙11活動以前,Passport的綁定帳號功能一直在運行,只是沒有碰到過大促銷帶來的挑戰程序員
上圖是壓測過程當中主要的階段中問題和改進,主要的問題和優化過程以下:github
- docker bridge網絡性能問題和網絡中斷si不均衡 (優化後:500->1000TPS) - 短鏈接致使的local port不夠 (優化後:1000-3000TPS) - 生產環境snat單核致使的網絡延時增大 (優化後能達到測試環境的3000TPS) - Spring MVC Path帶來的太高的CPU消耗 (優化後:3000->4200TPS) - 其餘業務代碼的優化(好比異常、agent等) (優化後:4200->5400TPS)
優化過程當中碰到的好比淘寶api調用次數限流等一些業務問題就不列出來了spring
因爲用戶進來後先要登陸而且綁定帳號,實際壓力先到Passport部分,在這個過程當中最開始單機TPS只能到500,通過N輪優化後基本能達到5400 TPS,下面主要是闡述這個優化過程docker
爲了更好地利用資源每臺物理加上部署三個docker 容器,跑在不一樣的端口上(808一、808二、8083),經過bridge網絡來互相通信數據庫
說明:這裏的500 TPS到5400 TPS是指登陸和將優酷帳號和淘寶帳號綁定的TPS,也是促銷活動主要的瓶頸api
在userservice機器上經過netstat也能看到大量的SYN_SENT狀態,以下圖:tomcat
docker(bridge)----短鏈接--->訪問淘寶API(淘寶open api只能短鏈接訪問),性能差,cpu都花在si上;
若是 docker(bridge)----長鏈接到宿主機的某個代理上(好比haproxy)-----短鏈接--->訪問淘寶API, 性能就能好一點。問題多是短鏈接放大了Docker bridge網絡的性能損耗
去掉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
竟然性能又回到了500,太沮喪了,其實最開始帳號綁定慢,Passport這邊就懷疑taobao api是否是在大壓力下不穩定,程序員通常都是認爲本身沒問題,有問題的必定是對方 :) ,taobao api那邊給出調用數據都是1ms之內就返回了(alimonitor監控圖表)。
因而懷疑從優酷的機器到淘寶的機器中間鏈路上有瓶頸,可是須要設計方案來證實這個問題在鏈路上,要不各個環節都會認爲本身沒有問題的,當時Passport的開發也只能拿到Login和Userservice這兩組機器的權限,中間的負載均衡、交換機都沒有權限接觸到。
在嘗試過tcpdump抓包、ping等各類手段分析後,設計了場景證實問題在中間鏈路上。
這個時候奇怪的事情發現了,壓力一上來**場景一、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左右
優化到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
這個問題具體參考我以前發表的優化文章http://www.atatech.org/articles/65232 。 主要是經過火焰圖發現spring mapping path消耗了過多CPU的性能問題,CPU熱點都在methodMapping相關部分,因而修改代碼去掉spring中的methodMapping解析後性能提高了40%,TPS能從3000提高到4200.
代碼中的第二個問題是咱們程序中不少異常(fillInStackTrace),實際業務上沒有這麼多錯誤,應該是一些不重要的異常,不會影響結果,可是異常頻率很高,對這種咱們能夠找到觸發的地方,catch住,而後不要拋出去(也就是別觸發fillInStackTrace),打印一行error日誌就行,這塊也能省出10%的CPU,對應到TPS也有幾百的提高。
部分觸發fillInStackTrace的場景和具體代碼行(點擊看高清大圖):
整個useragent調用堆棧和cpu佔用狀況,作了個彙總(useragent不啓用TPS能從4700提高到5400)
最終經過對代碼的優化勉勉強強將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)