• redis 连接打满的解决


    先上效果,连接数从10000下降到25,提升400倍;

    内存占用,从70%下降到18%,降幅1/4;

     

    一、现象

    服务用了redis,主要为加锁用,保证唯一性;最初服务正常,后期只要用到redis的地方,不超2分钟,10000的连接数就会被打满,最后造成资源耗尽、服务崩溃。

     

    二、分析

    阿里云redis最大连接数是10000个,被打满只有2个可能,连接数创建后,要么没释放(销毁),要么在持续不断的创建,且创建数无大于释放数。

    怀疑1:连接没被释放

    查代码,所有加锁的地方,最终都在finally中作unlock,所以此条被排除、

    1. try{
    2. **业务代码**
    3. } catch (Exception e) {
    4. } finally {
    5. if (rLock.isLocked()) {
    6. if (rLock.isHeldByCurrentThread()) {
    7. rLock.unlock();
    8. }
    9. }
    10. }

    怀疑2:连接在不断的创建,且大于销毁数

    因为最初的redis是用默认配置,代码如下:

    1. public class RedissonConfig {
    2. public static RedissonClient redissonClient() {
    3. Config config = new Config();
    4. String url = xx.getConfig("rds.url");
    5. String pwd = xx.getConfig("rds.pwd");
    6. Integer database = Integer.parseInt(xx.getConfig("rds.database"));
    7. config.useSingleServer(). .setAddress(url).setPassword(pwd).setDatabase(database);
    8. RedissonClient redisson = Redisson.create(config);
    9. return redisson;
    10. }
    11. }

    以为是相关参数没配置,于是把参数加上,然并卵

    1. config.useSingleServer().setConnectTimeout(10000).setTimeout(3000).setIdleConnectionTimeout(10000)
    2. .setConnectionPoolSize(16).setConnectionMinimumIdleSize(6).setRetryAttempts(3).setRetryInterval(1500)
    3. .setAddress(url).setPassword(pwd).setDatabase(database);

    后来查到这位博友:单例模式之「双重校验锁」_HoryC的博客-CSDN博客_单例模式双重校验锁

    的文章,忽然顿悟,可能是JFinal在实现时,没有默认像SpringBoot一样将redis转为单例,造成不断创建线程连接,从源码可以看出,连接池默认是64,在旧锁未释放前,不断创建,造成打爆

    三、解决 

    知道原因就好办了,在创建前先作判断,如果存在则直接return,否则创建

    1. public class RedissonConfig {
    2. //必须有volatile修饰(防止指令重排序)
    3. private volatile static RedissonClient instance;
    4. //构造函数必须私有(防止外部通过构造方法创建对象)
    5. private RedissonConfig() {
    6. }
    7. public static RedissonClient redissonClient() {
    8. //第一个判空(如果是空,就不必再进入同步代码块了,提升效率)
    9. if (instance == null) {
    10. //这里加锁,是为了防止多线程的情况下出现实例化多个对象的情况
    11. synchronized (RedissonConfig.class) {
    12. //第二个判空(如果是空,就实例化对象)
    13. if (instance == null) {
    14. Config config = new Config();
    15. config.setCodec(new org.redisson.client.codec.StringCodec());
    16. config.useSingleServer().setConnectionPoolSize(50);//设置对于master节点的连接池中连接数最大为500
    17. config.useSingleServer().setIdleConnectionTimeout(100000);
    18. //如果当前连接池里的连接数量超过了最小空闲连接数,而同时有连接空闲时间超过了该数值,那么这些连接将会自动被关闭,并从连接池里去掉。时间单位是毫秒。
    19. config.useSingleServer().setConnectTimeout(300000);//同任何节点建立连接时的等待超时。时间单位是毫秒。
    20. config.useSingleServer().setTimeout(30000);//等待节点回复命令的时间。该时间从命令发送成功时开始计时。
    21. // 不能反序列化 阻塞队列中的string元素
    22. Codec codec = new JsonJacksonCodec();
    23. config.setCodec(codec);
    24. // 你的IP
    25. config.useSingleServer().setAddress(url).setPassword(pwd).setDatabase(database).setKeepAlive(true);
    26. instance = Redisson.create(config);
    27. }
    28. }
    29. }
    30. return instance;
    31. }
    32. }

  • 相关阅读:
    猿创征文|Java计算【生日工具类】看这篇就够了
    怎么给自己的网站主页配置SSL证书?
    【大语言模型LLM】-基础语言模型和指令微调的语言模型
    C++入门基础05:表达式(表达式基础、算术运算符与赋值运算符、逻辑关系运算符、成员访问运算符与条件运算符、位运算符、移位运算符与类型转换)
    继承于QObject 的多线程实现
    tkinter绘制组件(32)——圆角按钮
    竞赛 推荐系统设计与实现 协同过滤推荐算法
    asdfsdfsdfd
    智慧物流园区供应链管理系统解决方案:数智化供应链赋能物流运输行业供应链新模式
    【USB声卡】magic_uac 开发板介绍
  • 原文地址:https://blog.csdn.net/zerovpp/article/details/127678054