背景
生产环境SpringCloud集群下,业务服务频繁卡顿、假死、心跳超时,触发自动重启机制。
版本
Eureka Server | |
SpringCloud | Hoxton.SR10 |
SpringBoot | 2.3.9.RELEASE |
网关程序、业务服务 client | |
SpringCloud | Edgware.RELEASE |
SpringBoot | 1.5.10.RELEASE |
zuul | 1.4.0.RELEASE |
注:由于业务服务未升级到新版,存在新旧版本共存现象,但版本兼容性不是影响卡顿的原因。
故障监控
生产环境卡顿现象密集发生时,将故障节点流量切至备用节点,保留故障现场,以便进一步分析问题。
1. 监控日志
2022-02-16 15:02:39.973 ERROR [foun,,,] 746 --- [scoveryClient-0] task supervisor timed out
2022-02-16 15:07:08.286 ERROR [foun,,,] 746 --- [tbeatExecutor-0] DiscoveryClient_FOUNDATION/192.168.1.109:8405 - was unable to send heartbeat!
发现存在socket超时,无法发送心跳现象
2. 监控线程
线程存在大量WAITING,但未发现死锁
线程在业务高峰时段开始飙升,后服务卡死,无法监控
故障节点摘除后,无流量导入,服务夯住一段时间后,线程陆续释放,最终恢复正常。
3. 网关服务存在频繁重试现象
请求失败,触发重试机制,重试多次后正常
故障分析
针对以上监控信息,综合分析如下:
1. 超时问题:
由eureka心跳监控触发超时,如果超过极限值,会剔除实例,触发探活自动重启机制,但重启需要时间,期间其他节点压力会骤增,客户有感知。
解决:
- 关闭eurekaServer中的心跳Listener,因存在手写探活代码,对心跳线程会产生影响
- 优化心跳间隔参数,避免网络抖动带来的影响。
- 为了保证高可用,搭建备用节点,采用秒级接管,切换流量。
2. 线程问题:
按 网关 -> App_1 -> App_2 调用链,采用压测工具,300并发测试如下
App_1线程:无异常
App_2线程:无法达到并发数
接口响应loading,问题再现
解决:
针对以上问题,分析由App_1调用App_2产生了瓶颈,调用方式采用的是feignClient,所以优化连接池参数如下:
feign.httpclient.maxConnections: 800 #最大连接数,默认200
feign.httpclient.maxConnectionsPerRoute: 400 #最大路由,默认50
调整后,App_2线程数恢复正常,如下图
注:由于网关服务较特殊,需要追加优化如下参数,连接数要比下游服务大一些
ribbon.MaxTotalConnections: 2000
ribbon.MaxConnectionsPerHost: 1000
#如使用tomcat容器,也要修改连接限制,根据服务器配置优化:
server.tomcat.max-threads: 1000
server.tomcat.max-connections: 10000
3. 重试问题:
此问题展开分析后,发现异常通常为以下信息:
IOException: unexpected end of stream on Connection
因网关使用的是zuul,并选择okHttp3作为连接框架,okHttp会与服务器保持长连接,如果发现长连接关闭(超时后关闭),即导致以上异常产生,并会发起重试。
参考:总结okhttp的错误IOException: unexpected end of stream on okhttp3的解决办法_mace_android的博客-CSDN博客
解决:要排除此问题,在框架版本不升级的前提下,可选择更稳定的httpClient作为底层框架,配置如下参数:
ribbon.httpclient.enabled: true
ribbon.okhttp.enabled: false
另外关闭重试也可以减少无用请求发生,参数如下:
spring.cloud.loadbalancer.retry.enabled: false
zuul.retryable: false
# 对所有操作请求都进行重试
ribbon.OkToRetryOnAllOperations: false
ribbon.MaxAutoRetries: 0
ribbon.MaxAutoRetriesNextServer: 0
总结
综上分析,导致卡顿的原因有很多,除本文重点描述的SpringCloud参数优化外,还有数据库连接池优化、JVM优化、日志优化,更有业务代码优化等关注点,当然,这些都需要各团队的努力,才能一一攻破,本着对生产故障的敬畏之心,架构人员需要对系统更深入的理解,找到问题的突破口,带领团队不断完善系统缺陷。