测试接口:登录
链路调用:nginx-->zuul-server-->[serviceA,serviceB, serviceC, serviceD]
因为登录接口牵涉到一系列的加密校验、权限角色、账号密码验证,所以 zuul-server 路由之后,会调用很多个微服务来获取用户信息。
服务器的话都是用Docker启动的容器,每个服务的内存大概在512M左右,另外每个服务(包括nginx)都只有1个实例。
该请求单次请求的平均响应结果为250ms。
ribbon 超时设置:
ribbon:
ConnectTimeout: 2000
ReadTimeout: 5000
SocketTimeout: 2000
hystrix 设置:
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 15000
通常来说, hystrix 超时时间
1. 每秒启动100线程,循环10次。
结果如下:
并且无法再调大线程数,会直接熔断报错。
经过资料查询,zuul 默认的对请求采用的是信号量隔离的方式,默认值为100,当请求量达到这个信号量时,直接返回错误。因此,对于这个进行参数调整:
zuul:
semaphore:
maxSemaphores: 200
2. 调整 zuul 信号量之后,每秒启动200线程,循环10次。
结果如下:
可以发现,并发量上去了,但是已经会开始出现错误,并且服务器的吞吐量很低。报错依旧为 hytrix 熔断错误。
最后经过检查代码发现,代码中有 for 循环 fegin 调用,导致了接口本身的性能就不行。
所以,通常来说,并发量如果要求不是非常高,比如文中 200 左右即可的话,那么基本上把 zuul 的并发信号量调大即可,至于其他 hystrix 线程数、 tomcat 线程数之类的,默认配置基本OK,扛不住这么高并发更大的可能性是代码有问题,把代码优化做好的价值是远远大于这种参数性能调优的,并且这种参数的调整难度相对比较大,需要考虑服务器性能以及对于预估的并发量从而计算合理的参数。
建议的几个调整参数的点:
1. hystrix 的线城池大小,hystrix 默认隔离策略是按线程方式隔离,所以调整这个线程池的大小,可以比较有效的在突增的高并发中扛住一定的压力,就比如平时都是200并发,突增到300时。线程池大小的计算也不是随意的,比如你预估的并发量是200,而每个接口平均的相应时间为300ms,那么 0.3*200=60,理论上60个线程就足够了,但是最好给他加一点缓冲余地,比如多加10个线程,这个10你可以自己调整,考虑服务器性能,这是为了防止突然增大的流量给个缓冲的余地。
hystrix:
threadpool:
# default: 默认参数,作用的所有的hystrix的客户端
default:
coreSize: 70
反过来,这个线程数大小对于你设置 ribbon 超时时间也是有参考意义的,比如并发量200,线程数70,70/200=0.35 即 350ms。
2. ribbon 的超时,ribbon 的超时设置其实是把双刃剑,如果平时并发量并不是太夸张,而且允许请求虽然慢,但是请求尽量都要有正确的返回值,那么 ribbon 的超时时间可以设置的稍微长一点,这样允许响应速度慢而不会触发熔断。但是,这样做的风险是,如果某一天你的服务器迎来了不可预期的请求量暴增,会导致大量的请求卡死等待响应,因为超时时间长,每个请求一定要等待这么多时间才会出发熔断从而报错,那么持续个几十秒,服务器上累积的等待请求就很多了,最终可能导致服务瘫痪,这是灾难级的事故了。
所以,在很高并发的情况下, ribbon 超时的时间,一般 1秒 就够了,尽快去触发熔断,防止服务瘫痪,当然,优化接口性能也是必不可少的。
ribbon:
ConnectTimeout: 2000
ReadTimeout: 5000
SocketTimeout: 2000
3. tomcat 优化, tomcat 默认的线程池大小为200,可接受的等待请求数大小为100,可以调整这个参数,同样也要视服务器性能而定。
server:
tomcat:
maxThreads: 200
acceptCount: 100
另外还可以用 undertow 来替换 tomcat ,据说这个比 tomcat 性能要好,我没有实践过。