【Jedis testOnBorrow配置 引发的生产事故】

  • 背景
  • 问题排查
  • 问题总结
  • 原因分析
  • 破案
  • 总结

背景

公司系统在昨晚升级之后,一晚上基本没睡觉的我一大早7点被运维打电话叫醒,并告诉了我一个噩耗:线上Redis连接过载!连接数是未升级之前的2-3倍!!cpu被打到90%!!系统处于奔溃的边缘,或者说,已经奔溃了!

问题排查

此时的我也是奔溃的,来不及去公司,直接开电脑开始排查,好
冷静一下,排查思路要明确:

  1. 连接数这么高,那这么多连接现在在做什么!
  2. 连接数高是某个应用单独连接数高导致,还是每个应用连接都比之前高2-3倍导致。
  3. 是否有连接泄漏,回想昨晚升级的点是否有地方导致应用连接泄漏。

关于第一点:

client list 命令在Redis服务器上执行看下这么多连接都在做什么:
结果发现大量的ping请求打在Redis服务器上,而且大多数ping请求的idle空闲时间不长,如下截图:

再让运维看下消耗cpu的命令排行榜:ping命令占用50%cpu

马上确认第二个问题,是具体哪个服务发起的ping还是每个服务都有ping:

运维采样几个服务上的Redis连接数,发现每个服务连接数都很高。也就是每个服务都在执行大量的ping命令。

关于第三个问题,想想看昨晚修改的代码,哪里可能有连接泄漏风险:

其实不用想了,从现象上看,这个不是连接泄漏,而是应用拿了较多的连接,且这些连接都在执行ping操作,泄漏的话应该会不止2-3倍连接,且连接的idle空闲时间会更长!

再想:现在现象是升级之后有大量的ping命令打到服务器上,这显然不是我们代码导致的,代码不会无缘无故去执行与业务无关的ping命令。但肯定是升级导致的,毕竟升级前后差距太大,那既然不是代码导致,升级前后有什么差异?对了,是不是配置会调整?马上让运维看下升级前后的nacos配置,最终看到不同的点:

太坑了,testOnBorrow配置不小心被人打开为true了!当即让运维修改false关闭并逐个重启几十个涉及到的服务,随着服务重启,redis连接逐渐下降到恢复正常;整个过程历经1小时,线上生产事故大奖已发放。

问题总结

至于testOnBorrow为什么会引起这么多ping命令,这个后面会说。
testOnBorrow配置项其实来自于Apache CommonPools,意思是从连接池中取出是检查连接是否失活,默认都是关闭的,之前mysql数据库因为这个配置项开启会引起性能问题我们是知道的,所以当时发现testOnBorrow被打开,想都不用想为什么会导致ping多,直接让运维关闭再说。

原因分析

公司底层连接Redis客户端用的是Jedis,看下为什么这个配置打开会导致有很多ping。

先来看下Redis配置都有哪些

testOnBorrow配置介绍:


#指明是否在从池中取出对象前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个.
testOnBorrow =false

大家都知道Jedis是Java Redis 连接池,从maxIdle、minIdle、maxTotal等配置可以知道Jedis也是实现了apache common pool连接池的一种,像我们数据库的连接池等原理一样,一定也是实现并重写了apache common pool连接池的,有关apache common pool连接池简单介绍参考:

https://www.jianshu.com/p/2cd47d1e4aee

想想看:

连接池的套路基本都一样的,工厂模式肯定会被用到,Google大致了解一下apache common pool的默认工厂类:PooledObjectFactory

里面方法不多,值得注意的两个方法很快被注意到:

 //生产对象的方法PooledObject<T> makeObject() throws Exception;//校验对象的方法boolean validateObject(PooledObject<T> p);

Jedis肯定是实现了它的工厂类,顺着找到Jedis的工厂类JedisFactory,对应看下这两个方法的实现,熟悉的代码找到了,可疑的点也找到了:

//validateObject()方法中:jedis.ping().equals("PONG") !!!在执行命令

  @Overridepublic boolean validateObject(PooledObject<Jedis> pooledJedis) {final Jedis jedis = pooledJedis.getObject();try {// 看看这是在干什么?? jedis.ping()!!!!!!!!!!!!!!!!return jedis.getConnection().isConnected() && jedis.ping().equals("PONG");} catch (final Exception e) {logger.error("Error while validating pooled Jedis object.", e);return false;}}@Overridepublic PooledObject<Jedis> makeObject() throws Exception {Jedis jedis = null;try {//这代码是不是很不熟悉jedis = new Jedis(jedisSocketFactory, clientConfig);jedis.connect();return new DefaultPooledObject<>(jedis);} catch (JedisException je) {if (jedis != null) {try {jedis.quit();} catch (RuntimeException e) {logger.debug("Error while QUIT", e);}try {jedis.close();} catch (RuntimeException e) {logger.debug("Error while close", e);}}throw je;}}

再找找看工厂生产方法是不是会执行validateObject()方法,找一下这个方法会被什么类调用,如图:

打开对应类方法:

破案

Jedis的testOnBorrow配置项实现原理就是从连接池获取连接时,利用Redis提供的PING命令来检查连接是否可用,生产上不小心打开了,至于怎么不小心打开了不重要,重要的是打开了会导致每次获取连接时,向Redis额外执行一下ping命令。

总结

有关连接池的配置,像数据库连接池等,生产环境testOnBorrow配置均需关闭,有兴趣可以看下数据库连接池validateObject()方法做了什么,肯定也会带来较大性能消耗。

【Jedis testOnBorrow配置 引发的生产事故】相关推荐

  1. 一个情怀引发的生产事故

    在一个项目中,需要轻量级用到脚本语言,来提高应用服务的灵活性.因为知道Roslyn可以动态编辑C#,本着情怀,就自然用Roslyn来处理这块业务了.开在windows上执行,一次调用风平浪静,因为这个 ...

  2. 一个情怀引发的生产事故(续)

    接上一篇博文,用Roslyn动态编译C#语句片段,情怀了一把,但内存会飙升,执行速度也奇慢,这条路走不通,回归正道,说起脚本,Lua是常用的手段之一,那就看看NLua怎么样,用NLua实现同样的效果, ...

  3. 【问题排查】InheritableThreadLocal类引发的生产事故

    目录 背景 项目背景 问题 现有代码逻辑 线程池配置类 线程上下文持有类:ThreadContext Session过滤器 分析 初步分析 重现问题 debug调试 从获取SessionId的代码入手

  4. 生产事故 java_记一次生产事故:30万单就这样没了!

    背景 你好,我是彤哥. 昨天晚上下班回家,在地铁上,老大突然打来电话,B系统生产环境响应缓慢,影响了A系统的使用,几万小哥收不了单,大概有30万单卡住了,你去帮忙定位一下. 我8点半左右到家,立马上线 ...

  5. Spring Transactional还能导致生产事故?

    在Spring中进行事务管理非常简单,只需要在方法上加上注解@Transactional,Spring就可以自动帮我们进行事务的开启.提交.回滚操作.甚至很多人心里已经将Spring事务与@Trans ...

  6. Spring官方推荐的@Transactional还能导致生产事故?

    在Spring中进行事务管理非常简单,只需要在方法上加上注解@Transactional,Spring就可以自动帮我们进行事务的开启.提交.回滚操作.甚至很多人心里已经将Spring事务与@Trans ...

  7. mysql grant produce_ERROR 1045 (28000) Mysql中grant 使用不当导致的生产事故

    背景: 新项目上线,Data Warehouse 的同事要从Mysql 的SLAVE 库上抽取数据.其中一项任务是授予读取数据库的权限. 没想到这个简单的操作也引发了一些意外. 在只读用户增加权限后, ...

  8. 什么?Spring官方推荐的@Transational还能导致生产事故?

    在Spring中进行事务管理非常简单,只需要在方法上加上注解@Transactional,Spring就可以自动帮我们进行事务的开启.提交.回滚操作.甚至很多人心里已经将Spring事务与@Trans ...

  9. 出现生产事故测试应该怎么做

    目录 前言 一.笔者工作中遇到的生产故障 二.笔者反思 总结 前言 出现生产事故测试应该怎么做(对于测试人员来说,1000个测试用例抵不上一个漏测,出现生产bug事件很恐怖的事情),下面笔者根据自己实 ...

最新文章

  1. jqgrid 单元格绑定点击事件_自定义事件带参数的触发过程
  2. SpringBoot @Configuration •@Import •@Conditional•@ImportResoure基本使用
  3. MySQL高级 - 查询缓存 - 配置参数
  4. Python问答环节(2)
  5. vs2005部署报表服务器项目老提示输入用户名密码解决办法
  6. day13--决策树与随机森林
  7. C语言实现二维伊辛模型的蒙特卡罗方法模拟
  8. 计算机联锁维修管理机,计算机联锁试卷
  9. 第二届广东大学生网络安全攻防大赛 个人向Write Up
  10. linux 中压缩文件夹命令行,Linux下压缩文件夹命令使用
  11. ovs 内核态加打印调试
  12. Mongodb数据丢失解决办法
  13. 计算机应用期刊投中难吗,计算机应用研究投稿水平高吗
  14. JQuery日历 日期选择
  15. 幼儿园观察记录的目的和目标_幼儿园一日观察报告
  16. 小新air14 2020 i5-1035G1完美黑苹果
  17. 自己用C语言写RL78 serial bootloader
  18. Google Hacking 搜索教程,一步到位。
  19. Selenium学习 - ActionChains接口
  20. ixed php,「」解决PHP script * is protected by SourceGuardian

热门文章

  1. ts打包代码详解 (ffmpeg)
  2. oracle11g 联机重做日志、归档日志、日志文件组以及日志文件操作
  3. 逆向——企业微信根据手机号查微信用户信息并添加好友
  4. 2021 年全年详细工作日、周末、节假日数据JSON
  5. 汉诺塔-扩展版(四阶汉诺塔)
  6. 震撼收藏:《歌声飘过30年--百首金曲演唱会 第一场 春回大地(1978年-1985年)抒情歌曲的复兴》,场场精彩!
  7. java 解析 ical_使用Java编写.ics iCal文件
  8. cadence16.6软件窗口内容缺失
  9. 掌握了这 10 款开源安全工具,从此系统稳定可靠乐无忧!
  10. ElasticSearch在Java中的使用