前言
本人的从事dubbo架构和gateway网关的开发,昨天晚上(8月23日)我们整个业务系统进行升级,其中dubbo架构的注册中心出现了一些问题,分享给大家,希望大家引以为鉴。
项目背景/结构
dubbo调用就是常规的,只不过提供者和调用者并非直连,而是中间使用了F5架构,注册中心为自己做的,有权限、路由管路、告警和整理监控等功能。
调用顺序是这样的
- 提供方在管理平台上填写申请,允许注册到注册中心,并根据不同的域/机房分配一个F5地址。
- 调用方在管理平台上填写申请,这样做是为了控制权限,并且可以分配正确的F5。
- 调用时,调用方从注册中心拿到提供方的F5地址,F5架构会根据配置转发到对应的提供方。
事件回顾
- 22:00 管理平台审核通过,调用方开始大批量启动/重启
- 22:10 调用方反馈,订阅时间太长了,可能有问题,但至少订阅是成功了,业务请求正常
- 22:15 调用方反馈,订阅时间超时(30秒),订阅失败,重启的业务开始大面积报错,bate环境开始暂停动作,这时第一反应是这事大家都在重新订阅,又刚好赶上注册中心推数据(注册中心5s推一次数据给消费者),可能cpu慢了,等一下就好
- 22:30 业务反应,注册中心无法注册,无法订阅,并且会报错,看到报错日志就只知道,注册中心出事了
事故分析
这时候第一反应,立刻上服务器,看看进程是不是挂了,但第一感觉就是服务器超级卡,先用top命令看一下,发现java进程CPU占用率最低150%,最高500%+,并且看了一下日志,在疯狂的刷新,证明服务正在运行,但是不健康
这时立刻用jstack dump下来日志,发现有深度的栈全部在等redis
同时,每过5s,cpu就会飙升,就连dump日志都搞不下来
此时就完全没了想法,为什么都在等redis,redis连接又为何让cpu高的离谱,后面用netstat发现,服务器在频繁的创建链接,关闭连接
可能有的小伙伴会说,这很正常啊,注册中心哎,就是要频繁创建链接的啊。但其实这是不对的,无论是redis,mysql,各种中间件,都有连接池,一般情况下,1分钟之内最高和最低不会超过10个,而现在,10几秒内,最高和最低相差60多个,证明有东西在频繁的创建线程和销毁线程,还记得dump日志吗,没错,就是redis在频繁的创建和销毁线程,因为创建和销毁是耗性能的,于是需要看为啥会频繁的创建和销毁,矛头直指向redis连接池代码
....maxTotal_dubbo=200 # 连接池中总连接的最大数量
....maxIdle_dubbo=50 # 最大空闲的连接数
....minIdle_dubbo=10
maxIdle属性所代表的最大空闲的连接数,才真正是业务可用的最大连接数。如果maxTotal和maxIdle二者不相等,就会涉及到连接的销毁与创建操作,会产生一定的开销,所以建议设置maxIdle=maxTotal,尽可能的避免由于频繁地创建和销毁连接而造成连接池性能下降,使连接池能够达到最佳性能
于是,破案!因为maxTotal和maxIdle二者不相等,所以服务器一直在创建线程 -> 没线程了去拆开已有的线程 -> 拿拆开的线程去创建新的线程 -> 没线程了去拆开已有的线程 -> ......
更改后的配置:
....maxTotal_dubbo=200 # 连接池中总连接的最大数量
....maxIdle_dubbo=200 # 最大空闲的连接数
....minIdle_dubbo=10
注意:这里不要乱写,要先去问dba,问一下redis能扛住多少,需要需要扩容
后续
改完线程池,又出问题了,内存快不够,一直在YGC
接下来就好办了,中间件扩扩容,新生代参数改一改,过程过于简单,就不展示了啊哈哈哈哈哈哈
终结
本次bug原因:由于大量的订阅、发布,导致注册中心相比往常的压力更大,导致连接池出现问题。
不多啰嗦了,大家一定要记住,连接池,一定要小心、注意、谨慎。