记一次生产 redis 连接全部打满错误

发现

生产的一个查询界面高延迟,后又陆续发现一些无响应的接口。
经排查出现问题的流程都有和redis交互。
咨询近一期迭代有升级redis客户端。

打开服务器。使用redis-cli命令client list

client list 命令文档 :https://redis.io/commands/client-list/
实时redis连接信息如下,观察一下几点:
addr: 地址
age: 总时间
idle: 空闲时间

发现有大量age=idle 并且cmd为cluster的无效连接

此时脑中模拟画面 ==》在某个不起眼的角落,有行代码在悄悄的不停的创建连接:我就是建着玩,你能拿我怎么样?)

打开git log 提交记录,查看近期有和 redis-cluster 有关的代码

  1. 发现一处可能存在问题的地方
    图一

  2. 继续进去看getJedisResource方法
    图二

  3. 此时可以看到明显疑问点

a. 图一中424L 代码 close是否合理(正常情况下池化思想,比如线程池,比如数据库连接池,开箱即用,不需要去手动调度)
b. 图一中在循环中操作redis可以接受。但是 操作redis的工具点进去,也就是图二是一个 new 方法。在循环中 new redis 的集群客户端的做法是否正确(这里差不多就是此次打满redis连接的元凶了)。

  1. 打开redis客户端的文档
  1. 打开redis中文网->资源->客户端-> 左侧选择java->找到jedis。
  2. 跳转github 。阅读readme部分片段可以得出结论
    第一: 集群客户端是不需要重复创建的。可以想象一下mysql 的连接池概念,都是一个思路写出来的东西。
    第二: 在使用连接完毕后,是不需要自己关闭的。

代码修改,完结发版

在有着少些代码就少出bug 的良好习惯上[dog]。上VSCODE,开整:

  1. 注释掉close方法
  2. for循环整体结构不变。getJedisR... 方法中new 改为单例。部分代码如下:

提交代码。 合并发版。通知相关小伙伴注意后期使用。

------完结撒花-----------
ps: 连接池,调度池,等等什么池, 都是类似线程池的思想。大差不差跑不了那7个入参的设计。所以当自己在工作中写池工具的时候:
首先 固定或者最少活跃数。 就像此次redis集群客户端中的那样。如果没有固定连接数的话。 也不会for循环它会把redis连接数打满。
其次 自己创建出来的线程或者对象要记得自己去管理其生命周期。 就像redis-cluster中自己封装好了close方法一样。不需要使用者去操心这个池领域内的任何事情。
最后希望 奋斗在一线的同志们写出来的代码都像 一个完整产品一样。璀璨夺目。

posted @ 2023-02-22 14:50  博文43231  阅读(165)  评论(0编辑  收藏  举报