一般項目上線之前,除了我們的測試之外,其實性能壓測也是必要並且很關鍵的一部分,這樣會避免我們線上當遇到大的訪問量的時候,項目請求無法響應或者響應超時的問題。
解決這種大的併發問題,提高我們項目的訪問量一直是我們項目性能經常需要探討的一個問題,高併發的結局並不是無腦的擴容服務器,應該針對具體問題做出合適的性能優化策略。下面我會通過一個小案例來提高他的訪問量
說到性能壓測,我們都離不開jmeter,如何使用,下面先做一個簡單的講解:
我們以最簡單,最常用的爲例。一般我們會用到jmeter的四部分來做壓測工作:
1)線程組:模擬我們多線程多次請求
2)http請求:真正測試的http請求
3)查看結果樹:詳細的http請求信息成功與否
4)據合報告:根據據合報告分析性能,失敗了多少,吞吐量是多少等等
新建線程組
線程組上新建http請求,測試我們的請求uri
這裏需要注意:因爲我們測試的是接口或者說是請求地址的性能,爲了避免請求之間建立連接和關閉連接的耗時,我們需要長連接來避免這部分的性能損耗,所以【基本】裏面需要勾選【KeepAlive】,【高級】裏面的客戶端實現需要選擇【java】
我們簡單的一個壓測測試,只請求一次,返回成功
對應的而聚合報告:
好了上面介紹完jmeter的使用,下面我們來壓測我們項目,並看一下是如何發現項目接口的性能瓶頸的
1)首先linux啓動我們的項目,先查看一下當前默認springBoot中維護了多少個線程
查看一下我們運行的java程序的pid
ps -ef | grep java
查看我們springBoot項目內嵌的tomcat默認維護的線程總數量
pstree -p java的pid | wc -l
當我們的jmeter進行壓測,模擬500個線程,10秒,循環100次的時候,最大線程數漲到了221,已經是極限
2)在我們的springBoot內嵌的tomcat的配置文件中有一些我們需要注意和優化的參數
可以找到【spring-configuration-metadata.json】文件,所有搜索【server.tomcat】節點的都是關於tomcat的默認配置的,下面我們注意關注以下幾個參數:
2.1)server.tomcat.accept-count:等待隊列長度,默認100;
當我們的tomcat連接用完,所有的多餘的請求會被放到這個等待隊列中,若是放滿默認的100個還有多餘的請求,則會請求報錯
2.2)server.tomcat.max-connections:最大被連接數,默認10000
2.3)server.tomcat.max-threads:最大的工作線程數,默認200
2.4)server.tomcat.min-spare-threads:最小的工作線程數,默認10
結合上面的一些默認配置我們需要根據我們測試的性能瓶頸進行修改,我們對配置文件做出如下修改
server.tomcat.accept-count=1000
server.tomcat.max-connections=10000
server.tomcat.max-threads=800
server.tomcat.min-spare-threads=100
(默認經驗來說,一個4核8G內存的服務器,最大線程數800較爲合適,最小工作線程數爲100較爲合適)
然後我們重啓我們的項目,可以看到,我們默認情況下tomcat總的線程數變爲了121個
我們再次進行壓測,可以看到我們的總線程數量達到了821個,比優化之前將近擴充了4倍,大大提高了我們的併發訪問能力
好了,我們的簡單的一個併發數的提升優化至此結束。
除此之外,我們springboot內嵌tomcat並沒有對keepAlive參數做任何優化,說到keepAlive,這裏先做一個簡單的介紹:
當我們的客戶端請求服務器的時候在請求頭上帶上了我們的keepalive,就代表我們的客戶端需要和服務器端保持長久的連接,也就是服務器對客戶端做完響應不要立刻斷開連接,而是保持連接可以複用連接來減少斷開重連時間的消耗問題;http1.0之前沒有此參數,也就是http都是無狀態的短鏈接,因爲cpu資源的稀缺;現在加上此參數,是因爲現在的很多應用程序都需要頻繁的與服務器做交互請求,因此需要做長連接請求;但是也有一些問題,如果不做限制,無限等待,會有惡意攻擊(如dos攻擊),那麼我們網站也是不安全的,所以需要對此參數要做出相應的一些配置
所以我們需要對keeAlive也應該做一下定製化的配置,一來避免頻繁建聯帶來的性能消耗,二來避免長時間連接無限等待帶來的惡意損耗。主要配置如下兩個參數:
keepAliveTimeOut:多少毫秒後不響應的斷開keepalive
maxKeepAliveRequest:多少次請求後keepalive斷開失效
我們通過config配置類來進行相關配置,因爲內嵌tomcat並沒有暴露相關keepAlive的配置
新建一個配置類,具體內容如下:
//當Spring容器內沒有TomcatEmbeddedServletContainerFactory這個bean時,會吧此bean加載進spring容器中
@Component
public class WebServerConfiguration implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
@Override
public void customize(ConfigurableWebServerFactory configurableWebServerFactory) {
//使用對應工廠類提供給我們的接口定製化我們的tomcat connector
((TomcatServletWebServerFactory)configurableWebServerFactory).addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
//定製化keepalivetimeout,設置30秒內沒有請求則服務端自動斷開keepalive鏈接
protocol.setKeepAliveTimeout(30000);
//當客戶端發送超過10000個請求則自動斷開keepalive鏈接
protocol.setMaxKeepAliveRequests(10000);
}
});
}
}
類中註釋了配置參數的含義,不再多介紹。至此我們tomcat部分的優化到此結束
拋出問題,當我再壓測的時候,我通過【top -H】命令看到了如下服務性能情況:
我們的cpu幾乎快要達到百分之一百,而【load average】的平均一分鐘達到7.57,而且主要性能耗費在mysql數據庫上
後面我們會陸續講述我們利用redis的緩存機制來減輕mysql數據庫的壓力,使其性能再次做一個提升