Springcloud 高並發 配置 (一文全懂)
瘋狂創客圈 Java 高並發【 億級流量聊天室實戰】實戰系列之15 【博客園總入口 】
前言
瘋狂創客圈(筆者尼恩創建的高並發研習社群)Springcloud 高並發系列文章,將為大家介紹三個版本的 高並發秒殺:
一、版本1 :springcloud + zookeeper 秒殺
二、版本2 :springcloud + redis 分布式鎖秒殺
三、版本3 :springcloud + Nginx + Lua 高性能版本秒殺
以及有關Springcloud 幾篇核心、重要的文章:
二、Springcloud 中 SpringBoot 配置全集 , 收藏版
三、Feign Ribbon Hystrix 三者關系 , 史上最全 深度解析
四、SpringCloud gateway 詳解 , 史上最全
這是《Springcloud 高並發 配置 | 一文全懂》篇,為大家解讀如果做到Springcloud 高並發 配置。
Springcloud的性能問題
Springcloud 原始的配置,性能是很低的,大家可以使用Jmeter測試一下,QPS不會到50。要做到高並發,需要做不少的配置優化,主要的配置優化有以下幾點:
- Feign 配置優化
- hystrix配置 優化
- ribbon 優化
- Servlet 容器 優化
- Zuul配置 優化
Servlet 容器 優化
默認情況下,Spring Boot 使用 Tomcat 來作為內嵌的 Servlet 容器,可以將 Web 服務器切換到 Undertow 來提高應用性能,Undertow 是紅帽公司開發的一款基於 NIO 的高性能 Web 嵌入式
Zuul使用的內置容器默認是Tomcat,可以將其換成undertow,可以顯著減少線程的數量,替換方式即在pom中添加以下內容:
第一步,移除Tomcat 依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
第二步,增加Untertow 依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
第三步,Undertow 的屬性配置
server:
undertow:
io-threads: 16
worker-threads: 256
buffer-size: 1024
buffers-per-region: 1024
direct-buffers: true
server.undertow.io-threads: 設置IO線程數, 它主要執行非阻塞的任務,它們會負責多個連接, 默認設置每個CPU核心一個線程,不要設置過大,如果過大,啟動項目會報錯:打開文件數過多
server.undertow.worker-threads: 阻塞任務線程池, 當執行類似servlet請求阻塞IO操作, undertow會從這個線程池中取得線程,它的值設置取決於系統線程執行任務的阻塞系數,默認值是IO線程數*8
server.undertow.buffer-size: 以下的配置會影響buffer,這些buffer會用於服務器連接的IO操作,有點類似netty的池化內存管理,每塊buffer的空間大小,越小的空間被利用越充分,不要設置太大,以免影響其他應用,合適即可
server.undertow.buffers-per-region: 每個區分配的buffer數量 , 所以pool的大小是buffer-size * buffers-per-region
server.undertow.direct-buffers: 是否分配的直接內存(NIO直接分配的堆外內存)
Zuul配置 優化
我們知道Hystrix有隔離策略:THREAD 以及SEMAPHORE ,默認是 SEMAPHORE 。
Zuul默認是使用信號量隔離,並且信號量的大小是100,請求的並發線程超過100就會報錯,可以調大該信號量的最大值來提高性能,配置如下:
zuul:
semaphore:
max-semaphores: 5000
表示,當Zuul的隔離策略為SEMAPHORE時,設置指定服務的最大信號量為5000。對於特定的微服務,可以通過下面的方式,設置最大信號量
設置默認最大信號量:
zuul:
semaphore:
max-semaphores: 5000 # 默認值
設置指定服務的最大信號量:
zuul:
eureka:
<commandKey>:
semaphore:
max-semaphores: 5000
為了方便ThreadLocal的使用,也可以改為使用線程隔離的策略,這種場景下,就需要調大hystrix線程池線程大小,該線程池默認10個線程,調整的配置示例如下:
zuul:
ribbonIsolationStrategy: THREAD
hystrix:
threadpool:
default:
coreSize: 100
maximumSize: 400
allowMaximumSizeToDivergeFromCoreSize: true
maxQueueSize: -1
hystrix.threadpool.default.allowMaximumSizeToDivergeFromCoreSize:是否讓maximumSize生效,false的話則只有coreSize會生效
hystrix.threadpool.default.maxQueueSize:線程池的隊列大小,-1代表使用SynchronousQueue隊列
hystrix.threadpool.default.maximumSize:最大線程數量
hystrix.threadpool.default.allowMaximumSizeToDivergeFromCoreSize:是否讓maximumSize生效,false的話則只有coreSize會生效
hystrix.threadpool.default.maxQueueSize:線程池的隊列大小,-1代表使用SynchronousQueue隊列
zuul.ribbon-isolation-strategy:設置線程隔離,thread 線程隔離,SEMAPHORE 表示信號量隔離
默認配置都可以去HystrixThreadPoolProperties和ZuulProperties這兩個java文件中查找
Feign 配置優化
feign 默認不啟用hystrix,需要手動指定 feign.hystrix.enabled=true 開啟熔斷
feign 啟用壓縮也是一種有效的性能優化方式,具體的配置如下
feign:
compression:
request:
enabled: true
mime-types: text/xml,application/xml,application/json
response:
enabled: true
feign HTTP請求方式選擇
feign默認使用的是基於JDK提供的URLConnection調用HTTP接口,不具備連接池,所以資源開銷上有點影響,經測試JDK的URLConnection比Apache HttpClient快很多倍。Apache HttpClient和okhttp都支持配置連接池功能,也可以使用okhttp請求方式。
當使用HttpClient時,可如下設置:
feign:
httpclient:
enabled: true
max-connections:1000
max-connections-per-route: 200
當使用OKHttp時,可如下設置:
feign:
okhttp:
enabled: true
httpclient:
max-connections: 1000
max-connections-per-route: 200
max-connections 設置整個連接池最大連接數(該值默認為200), 根據自己的場景決定
max-connections-per-route 設置路由的默認最大連接(該值默認為50),限制數量實際使用
hystrix配置 優化
首先需要設置參數hystrix.threadpool.default.coreSize 來指定熔斷隔離的線程數,這個數需要調優,經測試線程數我們設置為和提供方的容器線程差不多,吞吐量高許多。
其次,啟用Hystrix后,很多服務當第一次訪問的時候都會失敗 是因為初始化負載均衡一系列操作已經超出了超時時間了,因為默認的超時時間為1S,需要修改超時時間參數,方可解決這個問題。
參考的hystrix配置如下:
hystrix:
threadpool:
default:
coreSize: 500
command:
default:
circuitBreaker:
requestVolumeThreshold: 1000
fallback:
enabled: true
execution:
isolation:
thread:
timeoutInMilliseconds: 100000
hystrix.command.default: 全局的作用域,作用的所有的hystrix的客戶端,如果需要對某個微服務,可以寫serviceId
hystrix.command.default.fallback.enabled 是否開啟回退方法
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds 請求處理的超時時間,缺省為1000,表示默認的超時時間為1S
hystrix.threadpool.default.coreSize 核心線程池數量
hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests 回退最大線程數
hystrix.command.default.circuitBreaker.requestVolumeThreshold 熔斷器失敗的個數,進入熔斷器的請求達到1000時服務降級(之后的請求直接進入熔斷器)
ribbon 優化
Ribbon進行客戶端負載均衡的Client並不是在服務啟動的時候就初始化好的,而是在調用的時候才會去創建相應的Client,所以第一次調用的耗時不僅僅包含發送HTTP請求的時間,還包含了創建RibbonClient的時間,這樣一來如果創建時間速度較慢,同時設置的超時時間又比較短的話,很容易就會出現上面所描述的顯現。
因此我們可以通過設置:
ribbon:
eager-load:
enabled:true
clients:service-1,service-2,service-n
參數說明:
ribbon.eager-load.enabled : 開啟Ribbon的飢餓加載模式
ribbon.eager-load.clients: 指定需要飢餓加載的服務名,如果不指定服務名稱,飢餓加載模式無效
Zuul的飢餓加載,沒有設計專門的參數來配置,而是直接采用了讀取路由配置來進行飢餓加載。所以,如果我們使用默認路由,而沒有通過配置的方式指定具體路由規則,那么 zuul.ribbon.eager-load.enabled=true 的配置就沒有什么作用了。
如果需要真正啟用Zuul 的飢餓加載,需要通過zuul.ignored-services=*
來忽略所有的默認路由,讓所有路由配置均維護在配置文件中,以達到網關啟動的時候就加載好各個路由的負載均衡對象。
關於Zuul 的默認路由,這里詳細介紹一下。假設你的注冊服務中心有三個已經注冊的服務名稱service-a,service-b,service-c。但是在zuul配置文件中,只映射了service-a,service-b,如下:
zuul:
ribbon:
eager-load:
enabled: true
ignored-services: ‘*’
routes:
a:
path: /a/**
serviceId: service-a
b:
path: /b/**
serviceId: service-b
這里,雖然沒有配置service-c的映射,但是,由於zuul有默認的映射機制,還是可以通過http://ip:port/service-c/的Url,訪問到你的service-c服務,如果不想向外界暴露默認的服務映射,可以加上 zuul.ignored-services:*
最后,介紹一下瘋狂創客圈:瘋狂創客圈,一個Java 高並發研習社群 【博客園 總入口 】
瘋狂創客圈,傾力推出:面試必備 + 面試必備 + 面試必備 的基礎原理+實戰 書籍 《Netty Zookeeper Redis 高並發實戰》
瘋狂創客圈 Java 死磕系列
-
Java (Netty) 聊天程序【 億級流量】實戰 開源項目實戰
-
Netty 源碼、原理、JAVA NIO 原理
-
Java 面試題 一網打盡
-
瘋狂創客圈 【 博客園 總入口 】
[外鏈圖片轉存中...(img-AaP9w9ZI-1571062386803)]
瘋狂創客圈 Java 死磕系列
-
Java (Netty) 聊天程序【 億級流量】實戰 開源項目實戰
-
Netty 源碼、原理、JAVA NIO 原理
-
Java 面試題 一網打盡
-
瘋狂創客圈 【 博客園 總入口 】