SpringCloud组件性能优化技巧分享

电子说

1.3w人已加入

描述

Springcloud的性能问题

应用服务组件调优

Servlet 容器 优化

Feign 配置优化

Gateway组件调优

Zuul配置 优化

hystrix配置 优化

ribbon 优化

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 依赖

 


   org.springframework.boot
   spring-boot-starter-web
   
      
         org.springframework.boot
         spring-boot-starter-tomcat
      
   

 

第二步,增加Untertow 依赖

 


   org.springframework.boot
   spring-boot-starter-undertow

 

第三步,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直接分配的堆外内存)

QPS

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),限制数量实际使用

QPS

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

项目地址:https://github.com/YunaiV/yudao-cloud

视频教程:https://doc.iocoder.cn/video/

Gateway组件调优

Zuul配置 优化

我们知道Hystrix有隔离策略:THREAD 以及SEMAPHORE ,默认是 SEMAPHORE 。

Zuul默认是使用信号量隔离,并且信号量的大小是100,请求的并发线程超过100就会报错,可以调大该信号量的最大值来提高性能,配置如下:

 

zuul:
  semaphore:
    max-semaphores: 5000

 

表示,当Zuul的隔离策略为SEMAPHORE时,设置指定服务的最大信号量为5000。对于特定的微服务,可以通过下面的方式,设置最大信号量

设置默认最大信号量:

 

zuul:
semaphore:
max-semaphores: 5000 # 默认值

 

设置指定服务的最大信号量:

 

zuul:
  eureka:
    :
      semaphore:
        max-semaphores: 5000  
QPS

 

为了方便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文件中查找

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时服务降级(之后的请求直接进入熔断器)

QPS

ribbon 优化

Ribbon进行客户端负载均衡的Client并不是在服务启动的时候就初始化好的,而是在调用的时候才会去创建相应的Client,所以第一次调用的耗时不仅仅包含发送HTTP请求的时间,还包含了创建RibbonClient的时间,这样一来如果创建时间速度较慢,同时设置的超时时间又比较短的话,很容易就会出现上面所描述的显现。

因此我们可以通过设置:

 

ribbon:
 eager-load:
     enabled:true
 clients:service-1,service-2,service-n
QPS

 

参数说明:

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有默认的映射机制,还是可以通过Url,访问到你的service-c服务,如果不想向外界暴露默认的服务映射,可以加上 zuul.ignored-services:*


 



审核编辑:刘清

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分