1. 壓測端硬件、網絡或軟件
問題1:域名壓測致使大量請求流向外網,並出現流量清洗前端
現象:測試結果顯示tps很是低,請求量壓測端統計與服務端統計相差很大java
解決思路:mysql
確認壓測域名是否走內網IP,ping + 壓測域名獲取到的ip地址與運維確認是否爲內網ip,若不支持ping(騰訊雲機器不支持ping)可嘗試tracert。nginx
肯定未走內網可能須要運維協助,在入口機器(nginx)配置host將域名指定到某臺或多臺服務器上。web
問題2:jmeter測試報告顯示出現各類異常報錯信息,如500、50二、Non Http responsecoderedis
現象:控制檯錯誤請求量增長、測試報告顯示相應錯誤提示、錯誤算法
解決思路:肯定錯誤類型,根據錯誤類型尋找錯誤真實緣由。spring
Non HTTP response code: java.net.ConnectException,java.net.ConnectException,通常是鏈接超時(查日誌)。從幾個方面排查,腳本問題、網絡、服務器承受能力到了極限(監控系統資源),併發量超過系統處理能力會出現這種狀況(可參考http://confluence.sui.work/pages/viewpage.action?pageId=13182064)sql
問題3:jmeter Jvm分配內存不足致使內存溢出數據庫
現象:控制檯出現報錯,出現OutOfMemoryError
解決思路:
Windows中對應的文件路徑:Jmeter_Home/bin/jmeter.bat
set HEAP=-Xms512m -Xmx512m
set NEW=-XX:NewSize=128m -XX:MaxNewSize=128m
Linux下對應文件路徑:Jmeter_Home/bin/jmeter
HEAP=-Xms512m -Xmx512m
NEW=-XX:NewSize=128m -XX:MaxNewSize=128m
一般就meter默認的HEAP -Xms512:初始化內存大小,-Xmx512m:最大堆內存。須要增長內存的時候須要注意
- 通常會將-Xms和-Xmx兩個值配置爲相同值,目的是爲了能在java的GC完成後堆內存不須要從新分隔計算堆區大小而浪費資源
- -Xms和-Xmx兩個值修改的值通常須要爲512的整數倍
- -Xmx不要超過物理內存的50%,超出可能會致使jmeter變慢
- 當腳本執行過程當中出現內存溢出outfmenmory錯誤,先嚐試增長增長HEAP的-Xms和-Xmx
- JDK32位的電腦Xmx不能超過1500m,最大1378m.不然在啓動Jmeter時會報錯
- -XX:NewSize:新生代初始內存大小,該值必定要小於—Xms
- -XX:MaxNewSize:新生代可被分配的內存的最大上限,這個值應該小於-Xmx的值,由於新生代佔內存來自整個堆內存一般設置爲-Xmx的三分之一
- jvm在執行GC時,會中止工做。MaxnewSize的增大,能夠下降GC頻率
問題4: 端口被佔用
現象:併發6000次/s,錯誤率高達66.89%
錯誤日誌:Non HTTP response code:java.net.BindException,Non HTTP response message: Address already in use
緣由:Jmeter windows壓測環境:Windows Server 缺失MaxUserPort和TcpTimedWaitDelay;限制了tcpip最大鏈接數和響應時間
解決辦法:註冊表HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/ Services/TCPIP/Parameters;添加MaxUserPort和TcpTimedWaitDelay,分別設置值爲6553四、30,以增大可分配的tcp鏈接端口數、減少處於TIME_WAIT狀態的鏈接的生存時間
2. 服務器硬件、網絡
問題1:壓測方式使用的是域名壓測,走的外部網絡,因此壓測壓力未能如預期同樣對目標服務器施壓,致使TPS很是低,服務器各類資源消耗也很小。
現象:使用單臺壓測機器分別進行了100、500、1000進程壓測,500個線程的時候tps只有180-200,再增長壓力Tps上不去。
解決思路:一開始覺得服務器鏈接數有問題,修改Tomcat最大鏈接數無效果。最後統計壓測端請求量與被測服務器接收請求量相差比較大
解決方式:網絡入口配置host/dns的形式將指定域名的請求所有指向測試服務器(對應IP)
問題2:原有集羣到達最大極限,TPS達到280左右就出現CPU適應太高的狀況
現象:2臺web和4臺service在調整配置、代碼優化出現瓶頸,使用單臺壓測機器分別進行了100、500、1000進程壓測,500個線程的時候tps達到280位最高併發,90%響應時間最小並且CPU等資源正常,增長併發數到1000後tps下降、響應時間增長CPU使用率>70%
解決方法:增長集羣機器
3. 中間件
問題1:Nginx入策略配置不平均,後端4臺服務器負載不均衡,致使壓測時其中一臺cpu使用率遠遠高於其餘3臺
解決:優化Nginx輪訓策略,默認使用的輪訓算法修改爲安權重分配
問題2:Nginx入口未開啓長鏈接,致使TPS上不去
現象:增長併發數,tps、響應時間無太大增加,服務器資源消耗都在正常範圍內,TPC鏈接數中出現大量time-wait,tomcat已開啓長鏈接配置,能夠肯定是入口長鏈接配置沒生效
- keepalive_timeout 20s; #一個keepalive 鏈接被閒置之後還能保持多久打開狀態
- keepalive_requests 1000; #一個客戶端能夠經過一個keepalive鏈接的請求次數。
問題3:Tomcat鏈接處瓶頸,致使高併發時出現接口超時
現象:500線程組併發的時候,服務端日誌出現大量超時提示,排查Tomcat線程數配置的時候發現maxThreads(線程池中最大活躍線程數)爲100。
解決:修改maxThreads、accept-count爲500後錯誤解決
- maxThreads:最大請求進程數,默認設置爲200,該值設置應該考慮實際狀況,當
請求進程數達到最大值時,通常會出現錯誤提示:SEVERE: All threads (150) are currently busy, waiting. Increase maxThreads (150) or check the servlet status
- accept:可接隊列長度,與maxThreads對應,當達到maxThreads後進入等待隊列。而等待隊列數達到最大值後,再有新請求後就會出現refuse connection(拒絕請求)
問題4:. 502 Bad Gateway和504 Gateway Time-out
問題定位:tomcat的參數配置問題
解決辦法:調整tomcat配置文件server.xml的配置:主要是最大線程數、最大創建鏈接數和最長鏈接時間。
問題擴展:Nginx或騰訊雲LB代理模式下後端tomcat服務器出現問題引發的。首先,檢查Nginx/騰訊LB或者tomcat的配置參數;其次,檢查tomcat應用服務器的內存、CPU和代碼BUG致使的。服務端栗子:方法內部RPC 調用,併發大,方法可用率降低,同時調用次數也會急劇上升。系統外部服務的接入層,對接邏輯容器時,應該添加緩衝隊列,最好異步。
問題5:未開啓長鏈接
- keepAliveTimeout=300000 <!--沒有請求保持長鏈接的時間ms -->
- maxKeepAliveRequests=50000 <!--長鏈接能保持的請求數 -->
問題6:dubbo參數優化
現象:隨着壓測併發線程數遞增,tps未能如預期中同步正向增加,達到峯值出現必定的降低。在調整了Tomcat配置參數後進一步優化其餘中間件配置
dobbo:protocol-服務提供者協議配置:
- name :協議名稱
- port :dubbo協議默認端口爲20880,若是配置爲-1或沒配置port,則會分配一個沒被佔用的端口
本次調優主要關注一下內容:
- heartbeat :心跳間隔,對於長鏈接當物理層斷開(如拔網線,TCP的FIN消息未能及時發送,對方收不到斷開事件此時就須要心跳檢查鏈接是否斷開)
- dispatcher :協議的消息派發方式,用於指定線程模型,好比:dubbo協議的all, direct, message, execution, connection等
- threadpool : 默認fixed,線程池類型,可選:fixed/cached
- threads : 服務線程池大小,默認值爲100
dubbo:reference-服務消費者引用服務配置:
本次性能優化主要關注內容
- connections :對每一個提供者的最大鏈接數,rmi、http、hessian等短鏈接協議表示限制鏈接數,dubbo等長鏈接協表示創建的長鏈接個數
- timeout :服務方法調用超時時間(毫秒),缺省使用<dubbo:consumer>的timeout。
問題7:JVM優化
現象:TPS每隔段時間就降爲0
問題定位:(1)監控tcp的鏈接數,等待數;(netstat -an |grep 6222 | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}')(2)查看服務端FULL GC的次數(過多,FULL GC會致使全部線程)
解決辦法:JVM調優+ tomcat參數調優
一、取消飛行記錄模式,去除參數(-XX:+UnlockCommercialFeatures -XX:+FlightRecorder)
二、jdk1.8 下取消了-XX:PermSize=500m-XX:MaxPermSize=500m
三、垃圾回收機制改爲G1模式(堆內存被劃分爲固定大小的多個區域,存活的對象從一塊區域轉移到另外一塊區域,這樣能夠進行垃圾回收的同時不中止其餘應用程序線程)
JVM的經常使用參數以下:
-Xms設置初始化堆的最大值
-Xmx 設置堆的最大值
PS:-Xms和-Xmx通常是相同的,能夠減小Full GC的頻率,最大能夠到服務器總內存的80%
-Xmn 設置年輕代的大小(年老代=最大值-年輕代),通常爲最大值的1/3左右。
問題8:java 啓動腳本優化
4. 數據庫、緩存等
問題1:DB 優化
(1)優化sql,儘量少使用join、or 語句,select 出來的字段是必需的字段。
(2) 優化索引,讓每條select 都走索引
(3) 設置鏈接池的最大鏈接數,設置爲10000/14 = 700, (10000 爲項目使用的mysql 最
大鏈接數,14 爲機器數)
(4)嘗試測試不一樣的鏈接池,選擇性能最佳的,如圖4 爲數據庫鏈接池性能測試,最
終肯定選擇hikari。
(5)不使用數據庫事務,由於數據庫操做代碼都在消費者中,在代碼中作冪等性。
查詢一條語句性能測試(ms)
問題2:Redis優化
1、優化redis 存儲數據結構
將db 中的數據load 保存爲redis 的hash 結構(全表保存),根據業務優化redis 存儲
結構,減小redis 查詢次數(例如將phone 和券code 的領取狀態單獨存儲)。
2、redis cpu爲單核,進行分片處理
大量查詢會成爲嚴重短板,經過hash 值進行分片處理,由於項目不存在熱點key 的問
題。優化事後redis 可以承受的量是以前的3 倍。
3、設置redis最大鏈接數
Redis 最大鏈接數設置爲:3*10000/14 = 2100(這裏乘以3 是由於微利項目有三臺redis)
問題3:mq 優化
1、優化mq 消息
消息體通常爲redis key,能夠去redis 拿取數據,優化消息存儲大小。按功能不一樣,拆
分多個隊列,加快單邏輯處理速度,微利項目根據業務拆分爲5 個隊列。
2、加快消費者消費速度
增長消費者數量爲20 個,根據下游(DB、業務方)TPS 屢次測試得出,能夠利用消費者數
量控制下游的負載。
增長消費者預讀取數據數量爲50 個,從而減小網絡請求次數。
優化消費邏輯,完善冪等操做(解決消息重複消費問題),db 操做,業務查詢操做。
問題4:Redis鏈接池瓶頸
優化後的配置:
redis.pool.maxTotal=5000
redis.pool.maxIdle=100
redis.pool.minIdle=50
關鍵參數說明:
maxTotal:資源池中最大鏈接池,默認值8
- 最大鏈接數的配置須要結合實際狀況進行調整,而考慮的關鍵因素包括:
- 業務要求Redis達到的併發量
- 客戶端執行命令時間
- Redis資源:如應用個數*maxTotal不能超過Redis的最大鏈接數
- 資源開銷:控制空閒鏈接,儘可能使鏈接池的頻繁建立、釋放形成沒必要要的開銷
例如:
假如一個命令的平均耗時是1ms,一個鏈接的QPS(Redis每秒執行指令數)大約1000,而業務要求QPS(每秒執行請求數)是50000。
理論上資源池最大鏈接池設置應該爲50000/1000=50個,可是實際設置上能夠比理論值稍大。須要注意的是該值不是越大越好,一是鏈接太多須要佔用客戶端和服務端更多資源另外一個是Redis假如出現阻塞資源池再大也沒做用。
maxIdle:資源池容許最大空閒的鏈接數,默認值8
minIdle:資源池確保最少空閒的鏈接數,默認值0
- maxIdle:實際上纔是業務須要的最大鏈接數,該值不能過大(不能大於maxTotal)或太小(太小會致使新增Redis鏈接開銷),而minIdle是爲了控制空閒資源監測
備註:以上均參考自https://yq.aliyun.com/articles/236383
問題5:DataSource參數優化
spring.datasource.initialSize=10
spring.datasource.minIdle=10
spring.datasource.maxActive=200
spring.datasource.maxWait=60000
- initialSize,鏈接初始值,鏈接池啓動時建立的鏈接數量的初始值
- maxActive,鏈接池的最大值,同一時間能夠從池分配的最多鏈接數量,0時無限制
- maxIdle,最大空閒值.當通過一個高峯時間後,鏈接池能夠慢慢將已經用不到的鏈接慢慢釋放一部分,一直減小到maxIdle爲止,0時無限制
- minIdle,最小空閒值.當空閒的鏈接數少於閥值時,鏈接池就會預申請去一些鏈接,以避免洪峯來時來不及申請
問題6:領券接口gainTPS 2W/s達到瓶頸
問題現象:6臺tomcat服務器+3臺redis-cache+2臺redis-MQ的TPS僅有2W/s,和理論值6k(單臺tomcat的最大值)有差距。
問題定位:(1)增長一臺redis-cache,TPS沒有改觀,初步判定redis-cache存在瓶頸。(2)代碼分析:發現gain接口裏面有大量的increment操做;熱點key避免產生瓶頸落在不一樣的redis上,但increment時全部的機器都來競爭操做這個key,形成瓶頸。(3)查看redis的監控,發現4臺redis-cache中有1臺的CPU達到100%,其餘3臺都在80~90%,造成木桶效應。
解決辦法:increment主要是爲了實時統計領券量,並顯示在看板上方便監控數據。非核心業務,能夠去掉increment操做,改爲經過elk日誌統計。
問題7:熱點key達到瓶頸
典型的瓶頸問題:併發量大時,操做同一個key(熱點key),hash的方式可能會落在同一臺redis服務器,達到單臺redis服務器的瓶頸。
存在問題的場景:理財市場登陸預熱(除夕紅包活動開始前把全部開戶信息加載到緩存中)
解決辦法:對熱點key進行加工和計算。理想的狀況下,集羣中有N個緩存節點,那麼加工後的key也應該有N個。
問題8:Jms消費慢
問題現象:壓測gain接口,jms消息有堆積
優化點:一、redis用的公共組件,有加鎖;二、gain接口會產生兩臺msg消息,分別丟進兩條隊列(一條入庫,一條調騰訊接口),同步改爲異步;(3)一個線程取消息多個線程消費-》改爲多個線程取消息多個線程消費
問題9:spdata分發有延時
問題現象:雲上的數據向IDC推送數據用到了JMS消息,併發量大,容易延時(已知問題)。
影響範圍:理財僅響應運營系統發獎,卡牛和微粒影響了雲上的兌換,致使用戶體驗很差。
解決辦法:spdata分發的方案不變,再增長方案:領取時前端已加密串形式保存QQ用戶信息,給兌換獎券時用。
問題10:日誌優化(經過日誌分析不出來)
一、異步寫日誌文件
二、減小日誌打印,例如正常請求僅打印入參和出參
三、kafka+ELK
問題11:spdatad多業務方數據源問題,致使預演併發量時,卡牛和微粒的數據未下發,不能兌換獎券(線上問題)
問題緣由:for循環按業務下推數據,每次先推進理財的;若是理財有下推數據,最後會clear掉dataSource,致使其餘業務查詢爲空;若是理財未下推數據,不會調用clear,正常推送其餘業務;
代碼以下:
解決辦法:dataSource從上文傳下來,避免執行clear時,dataSource被清空
規避方法:增長多業務的性能測試場景(跨公司的壓測資源和環境受限);
問題12. 業務繁忙(線上問題)
問題緣由:
(1)網絡緣由,例如:靜態資源文件未放運營商CDN服務器、網絡慢或異常;
(2)receive_api未獲取QQ:openid(小几率事件),服務端從新請求騰訊接口獲取QQ用戶openid,生成數字驗籤錯誤;
(3)騰訊雲問題,聯合騰訊壓測初步解決。