IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> JedisPool - Java.net.SocketException: Broken pipe (write failed) -> 正文阅读

[大数据]JedisPool - Java.net.SocketException: Broken pipe (write failed)

一.引言

使用 JedisPoll 多线程写入时,阶段性报错 broken pipe,重启后任务正常,一段时间后再次出现该报错。

JedisPool 配置如下:

  val config = new JedisPoolConfig
  config.setMaxIdle(20)
  config.setMinIdle(20)
  config.setNumTestsPerEvictionRun(-2)
  config.setTimeBetweenEvictionRunsMillis(30000)
  config.setSoftMinEvictableIdleTimeMillis(3600000)
  config.setMinEvictableIdleTimeMillis(-1)
  config.setTestOnBorrow(false)
  config.setTestOnReturn(false)
  config.setTestWhileIdle(false)

二.问题分析与解决

1.问题场景

任务很简单,采取 JedisPool 在集群多线程写入数据,该报错会在任务运行一段时间后抛出,做了 Try catch 发现任务是偶发报错,并非全部写入失败;且重启任务后短时间内无该报错。初步分析就是 getResource 方法会存在获取无效连接的情况,从而导致偶发的写入失败,而重启后任务运行正常是因为任务刚启动获取的 redis 连接都有效,从而没有 Broken pipe。

2.问题解决

通过配置可以看到下述三个参数设置均为 false:

  config.setTestOnBorrow(false)
  config.setTestOnReturn(false)
  config.setTestWhileIdle(false)

将 TestOnBorrow 设置为 true 或者把 testWhileIdle 设置为 true,如果还不行则都设置为 true。

?

3.参数含义

· setTestOnBorrow

borrow 即从 JedisPool 连接池中获取连接,该参数控制在获取 redis 连接时检查该连接的有效性,如果检查到该链接已失效,则会清理掉并重新获取新连接,这里可以参考源码中 getResource 方法,该方法从 Pool 中执行 borrowObject 方法获取连接,该类所在位置为 redis.client.util.Pool,底层实现参考了 org.apache.commons.pool2.impl.GenericObjectPool。

  public T getResource() {
    try {
      return internalPool.borrowObject();
    } catch (Exception e) {
      throw new JedisConnectionException("Could not get a resource from the pool", e);
    }
  }

配置该参数后,borrow 调用获取新连接时,如果连接失效则会调用?activeObject 方法重置连接内部状态,相当于获取新连接:

    try {
        this.factory.activateObject(p);
    } catch (Exception var15) {
        try {
            this.destroy(p);
        } catch (Exception var14) {
        }

        p = null;
        if (create) {
            NoSuchElementException nsee = new NoSuchElementException("Unable to activate object");
            nsee.initCause(var15);
            throw nsee;
        }
    }

?

· setTestOnReturn

return 是在调用 returnResource 时配置的参数,该参数控制向连接池返回 resource 连接时,检查该连接的有效性,如果该链接已经失效则会清理该连接,该方法从 Pool 中执行 returnResourceObject 方法返还连接,该类所在位置为 redis.client.util.pool,底层实现同样参考 GenericObjectPool。

  public void returnResourceObject(final T resource) {
    if (resource == null) {
      return;
    }
    try {
      internalPool.returnObject(resource);
    } catch (Exception e) {
      throw new JedisException("Could not return the resource to the pool", e);
    }
  }

如果配置该参数后,在 returnObjectResource 时代码会对连接调用 ValidateObject 方法判断有效性,如果无效则 destory :

        if (this.getTestOnReturn() && !this.factory.validateObject(p)) {
            try {
                this.destroy(p);
            } catch (Exception var10) {
                this.swallowException(var10);
            }

            try {
                this.ensureIdle(1, false);
            } catch (Exception var9) {
                this.swallowException(var9);
            }

            this.updateStatsReturn(activeTime);
        }

· setTestWhileIdle

该参数控制对空闲的连接进行测试。该参数与?config.setTimeBetweenEvictionRunsMillis(30000) 相对应,这里空闲的判断依据即为该参数内设置的毫秒时间。这里检验空闲连接的有效性,真正执行清除的是 evict 方法 :

    public void evict() throws Exception {
        this.assertOpen();
        if (this.idleObjects.size() > 0) {
            PooledObject<T> underTest = null;
            EvictionPolicy<T> evictionPolicy = this.getEvictionPolicy();
            synchronized(this.evictionLock) {
                EvictionConfig evictionConfig = new EvictionConfig(this.getMinEvictableIdleTimeMillis(), this.getSoftMinEvictableIdleTimeMillis(), this.getMinIdle());
                boolean testWhileIdle = this.getTestWhileIdle();
                int i = 0;
                int m = this.getNumTests();

                while(true) ...

这里第 7?行还涉及到?MinEvictableIdleTimeMillis 和?SoftMinEvictableIdleTimeMillis 两个时间参数,这里涉及线程池 idleEvictTime 的选取,优先读取前者,如果前者为负数则默认为 maxLong、如果前者未配置则读取后者,所以线程池的一些配置参数会出现 -1,-2 的情况,实际上并不存在 -1 ms 的时间。

    public EvictionConfig(long poolIdleEvictTime, long poolIdleSoftEvictTime, int minIdle) {
        if (poolIdleEvictTime > 0L) {
            this.idleEvictTime = poolIdleEvictTime;
        } else {
            this.idleEvictTime = 9223372036854775807L;
        }

        if (poolIdleSoftEvictTime > 0L) {
            this.idleSoftEvictTime = poolIdleSoftEvictTime;
        } else {
            this.idleSoftEvictTime = 9223372036854775807L;
        }

        this.minIdle = minIdle;
    }

真正判断开始执行 evict 逻辑是在下述函数:

    public boolean evict(EvictionConfig config, PooledObject<T> underTest, int idleCount) {
        return config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() && config.getMinIdle() < idleCount || config.getIdleEvictTime() < underTest.getIdleTimeMillis();
    }

满足下述任意条件则执行逐出:

A. 连接空闲时间大于 softMinEvictableIdleTimeMillis 且 连接池的空闲数小于 minIdleNum 即 EvictionConfig 内的第三个参数

B. 连接空闲时间大于?minEvictableIdleTimeMillis?

当然不会只进行逐出,逐出到一定程度,线程池也会进行 ensureIdle 去新建新的连接,保证线程池中有足够多可用的连接。

三.总结

上述报错与场景设置?TestOnBorrow = true 和 TestWhileIdle = true 后完美解决,但是也会带来一定的性能损耗,可以根据自己的场景进行调整,一般情况可以尝试只开启?TestOnBorrow。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-03-16 22:27:35  更:2022-03-16 22:30:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:07:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码