Springcloud原始的配置,性能是很低的,大家可以使用Jmeter测试一下,QPS不会到50。要做到高并发,需要做不少的配置优化,主要的配置优化有以下几点:
Feign配置优化 hystrix配置优化 ribbon优化 Servlet容器优化 Zuul配置优化默认情况下,SpringBoot使用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:trueserver.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直接分配的堆外内存)我们知道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:-1hystrix.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默认不启用hystrix,需要手动指定feign.hystrix.enabled=true开启熔断
feign启用压缩也是一种有效的性能优化方式,具体的配置如下 feign: compression: request: enabled:true mime-types:text/xml,application/xml,application/json response: enabled:truefeignHTTP请求方式选择
feign默认使用的是基于JDK提供的URLConnection调用HTTP接口,不具备连接池,所以资源开销上有点影响,经测试JDK的URLConnection比ApacheHttpClient快很多倍。ApacheHttpClient和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:200max-connections设置整个连接池最大连接数(该值默认为200),根据自己的场景决定
max-connections-per-route设置路由的默认最大连接(该值默认为50),限制数量实际使用首先需要设置参数hystrix.threadpool.default.coreSize来指定熔断隔离的线程数,这个数需要调优,经测试线程数我们设置为和提供方的容器线程差不多,吞吐量高许多。
其次,启用Hystrix后,很多服务当第一次访问的时候都会失败是因为初始化负载均衡一系列操作已经超出了超时时间了,因为默认的超时时间为1S,需要修改超时时间参数,方可解决这个问题。
参考的hystrix配置如下: hystrix: threadpool: default: coreSize:500 command: default: circuitBreaker: requestVolumeThreshold:1000 fallback: enabled:true execution: isolation: thread: timeoutInMilliseconds:100000hystrix.command.default:全局的作用域,作用的所有的hystrix的客户端,如果需要对某个微服务,可以写serviceId
hystrix.command.default.fallback.enabled是否开启回退方法
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds请求处理的超时时间,缺省为1000,表示默认的超时时间为1Shystrix.threadpool.default.coreSize核心线程池数量
hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests回退最大线程数
hystrix.command.default.circuitBreaker.requestVolumeThreshold熔断器失败的个数,进入熔断器的请求达到1000时服务降级(之后的请求直接进入熔断器)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高并发研习社群【博客园总入口】
疯狂创客圈,倾力推出:面试必备+面试必备+面试必备的基础原理+实战书籍《NettyZookeeperRedis高并发实战》
[外链图片转存中...(img-AaP9w9ZI-1571062386803)]
本文内容总结:Springcloud的性能问题,Servlet容器优化,Zuul配置优化,Feign配置优化,hystrix配置优化,ribbon优化,疯狂创客圈Java死磕系列,疯狂创客圈Java死磕系列,
原文链接:https://www.cnblogs.com/crazymakercircle/p/11674597.html