一次redis连接配置修改引发的redis.ption。。。

更新时间:2023-05-15 17:27:49 阅读: 评论:0

⼀次redis连接配置修改引发的redis.ption。。
  在⼀次修改了redis配置之后,出现了⼤批量的redis.ptions.JedisConnectionException: Unexpected end of stream.
  原配置
1 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
2 jedisPoolConfig.tMaxTotal(150);
bed
3 jedisPoolConfig.tMaxIdle(30);
4 jedisPoolConfig.tMinIdle(10);
5 jedisPoolConfig.tNumTestsPerEvictionRun(1024);
6 jedisPoolConfig.tTimeBetweenEvictionRunsMillis(30000);
7 jedisPoolConfig.tMinEvictableIdleTimeMillis(1800000);
8 jedisPoolConfig.tSoftMinEvictableIdleTimeMillis(1800000);
9 jedisPoolConfig.tMaxWaitMillis(1500);
10 jedisPoolConfig.tTestOnBorrow(true);
11 jedisPoolConfig.tTestWhileIdle(true);
12 jedisPoolConfig.tBlockWhenExhausted(fal);
  修改后的配置
1 JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
2 jedisPoolConfig.tMaxTotal(60);
3 jedisPoolConfig.tMaxIdle(60);
4 jedisPoolConfig.tMinIdle(60);
5 jedisPoolConfig.tNumTestsPerEvictionRun(1024);
6 jedisPoolConfig.tTimeBetweenEvictionRunsMillis(30000);
7 jedisPoolConfig.tMinEvictableIdleTimeMillis(1800000);
8 jedisPoolConfig.tSoftMinEvictableIdleTimeMillis(1800000);
9 jedisPoolConfig.tMaxWaitMillis(500);
10 jedisPoolConfig.tTestOnBorrow(fal);
11 jedisPoolConfig.tTestWhileIdle(true);
12 jedisPoolConfig.tBlockWhenExhausted(fal);
  如果⼀开始你就看出异常出现的问题所在了,那么这篇⽂章你就不⽤看了,是在浪费你的时间
  ⽽我看到这个异常最开始的想法是redis-rver出现了问题,在不停debug的时候猜测是redis-rver掐断了jedis连接,导致数据没有传输完成就断开了连接,但是这个想法怎么都没办法说服⾃⼰,虽然后来还是⼀直往这个⽅向⽅向查,因为福尔摩斯说过,排开所有不可能,剩下的那个原因再不可能那也是真相。可是福尔摩斯没有说怎么去找到最后的那个不可能,作为菜鸟的我⼀开始就把那个真相的不可能给排出了。对,我⼀开始就跑偏了,凤梨和菠萝傻傻分不清。
  这⼏天有点空闲时间,所以想着吧jedis的源码都好好看⼀遍,看⼀下我对这个配置的修改到底引发了jedis的怎么不满,让它那么想弄死我。
⼀开始查找的⽅向是testOnBorrow和testWhileIdle,因为我的理解来看,其它⼏个修改应该不会引发redis-rver对我的不满。不会那么随意掐断我的jedis连接。
testOnBorrow有原来的true改为了fal,即在每次查询获取链接的时候,都会检查⼀下获取到的这个链接是否有效,也即是在borrow⼀个jedis链接之前,会⽤这个链接向redis-rver发送⼀个PING命令,如果能得到⼀个PONG响应则返回此链接给调⽤者,⽽我为了节约这⼀次请求,所以就吧testOnBorrow改成了fal。因为testWhileIdle改为了true,所以理所当然的认为在空闲的时候会触发pool中失效的连接的释放。
  所以从现在开始,去彻底理解修改了的这两个参数的⼯作流,⾸先去阅读testOnBorrow参数源码如下:
s.pool2.impl.GenericObjectPool<T>
1if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
2boolean validate = fal;
3    Throwable validationThrowable = null;
4try {
5        validate = factory.validateObject(p);
6    } catch (final Throwable t) {
7        PoolUtils.checkRethrow(t);
8        validationThrowable = t;
9    }
10if (!validate) {
11try {
12            destroy(p);
13            destroyedByBorrowValidationCount.incrementAndGet();
14        } catch (final Exception e) {
15// Ignore - validation failure is more important
16        }
17        p = null;
18if (create) {
19final NoSuchElementException ne = new NoSuchElementException(
20                    "Unable to validate object");
21            ne.initCau(validationThrowable);
22throw ne;
23        }
24    }
silas
25 }
  在第5⾏调⽤了factory.validateObject(p),这⼀⾏代码的作⽤则是保证获取到的实例是安全的,对于jedis来说,就是保证获取到的连接是可⽤的,⽽且验证⽅法实现,则是利⽤获取到的jedis连接想redis-rver发送了⼀个PING命令,判断是否能得到⼀个PONG响应,是则连接可⽤,反之则不可⽤。源码如下:
redis.clients.jedis.JedisFactory
1 @Override
2public boolean validateObject(PooledObject<Jedis> pooledJedis) {
3final BinaryJedis jedis = Object();ontology
4try {
5    HostAndPort hostAndPort = ();
6    String connectionHost = Client().getHost();
7int connectionPort = Client().getPort();
Host().equals(connectionHost)
mayqueen9        && Port() == connectionPort && jedis.isConnected()
10        && jedis.ping().equals("PONG");
11  } catch (final Exception e) {
12return fal;
13  }
14 }
eano  在修改testOnBorrow为fal之后,每次获取jedis连接时就不会再进⾏以上的连接验证了。从这样的源码看来,对于testOnBorrow参数的理解好像也没有什么问题。
  ⽽此时脑⼦⾥突然迸处⼀个想法,也许redis-rver并没有对我有什么不满,也许出现的异常并不是在数据传输过程中,连接被掐断,⽽是连接⼀开始就断了。因为borrow⼀个连接的时候,没有对连接
做有效性检查,那么可能borrow获取到的连接本⾝就是⽆效的,⽽testWhileIdle,可能根本就没有空闲的时候。为此,有去看testWhileIdle的⼯作流程。最后还是在
s.pool2.impl.GenericObjectPool<T>的public abstract void evict() throws Exception;实现中找到了关于testWhileIdle的调⽤。
1// Ur provided eviction policy could throw all sorts of
2// crazy exceptions. Protect against such an exception汽车suv是什么意思
3// killing the eviction thread.
4boolean evict;
5try {
6    evict = evictionPolicy.evict(evictionConfig, underTest,
7            idleObjects.size());
8 } catch (final Throwable t) {
烘炉
9// Slightly convoluted as SwallowedExceptionListener
10// us Exception rather than Throwable
11    PoolUtils.checkRethrow(t);
12    swallowException(new Exception(t));
13// Don't evict on error conditions
14    evict = fal;
15 }
16if (evict) {
17    destroy(underTest);
18    destroyedByEvictorCount.incrementAndGet();
19 } el {
20if (testWhileIdle) {
21boolean active = fal;
22try {
23            factory.activateObject(underTest);
24            active = true;
25        } catch (final Exception e) {
26            destroy(underTest);
27            destroyedByEvictorCount.incrementAndGet();
28        }
specifically29if (active) {
30if (!factory.validateObject(underTest)) {
31                destroy(underTest);
32                destroyedByEvictorCount.incrementAndGet();
33            } el {
34try {
35                    factory.passivateObject(underTest);
36                } catch (final Exception e) {
37                    destroy(underTest);
38                    destroyedByEvictorCount.incrementAndGet();
39                }
toxic什么意思40            }
41        }
42    }
lcross
43if (!dEvictionTest(idleObjects)) {
44// TODO - May need to add code here once additional
45// states are ud
46    }
47 }
  这是⼀个空闲线程移除的⽅法,Jedis中默认的触发频率是30s(我的配置也是30s),但timeBetweenEvictionRunsMillis和
minEvictableIdleTimeMillis配置的时间都是1800s,所以,空闲超过半个⼩时的连接才会被回收,没有超过半⼩时的连接会⾛20⾏的逻辑,⽽在testWhileIdle为true时,虽然有destroy⽆效连接的时候,但是在debug时却从来没有看到被调⽤过,在第30⾏的连接校验也是通过校验了的。也就是说连接池中的连接始终有效,直到配置的MinEvictableIdleTimeMillis和SoftMinEvictableIdleTimeMillis的条件(半个⼩时)触发第6⾏使得evict为true的时候,批量destroy旧的连接,然后新建新的连接重新放⼊pool中。
  到现在为⽌,猜测有两点,⼀、borrow从pool中拿到的连接就是⽆效的;⼆、testWhileIdle空闲检查时,所有的连接都有效。这是⼀个⽭盾的结论,所以让我先想想静静。
后来想了⼀下,服务器会断开空闲客户端,更何况我已经把redis-rver的连接数占满了。问了⼀下运维的同学,说的是服务的会主动断开超过5s的空闲连接,后来想了⼀下,因为服务实例⽐较多,每个实例60的连接,很容易超过redis允许的最⼤连接数,⽽实际上应⽤可能⽤不到60个连接,使⽤旧的连接配置时,每个容器的连接数也就在10个,就是最⼩空闲连接数,所以使⽤新配置时,最⼩空闲连接数时60,也就是说每个容器⾄少有50个连接都是浪费的,所以在pool中可能会存在⼤量的连接没使⽤到,导致⼤量的连接被redis-rver主动断开,导致实例中会存在很多失效的连接,虽然每隔30s会进⾏⼀次清理,但是redis-rver断开的频率可能更⾼(因为连接满了不够⽤),导致Jedis 获取到的连接⼤概率⽆效。
当然最后的猜测我没有实验成功,主要是环境⼀直没有弄好,如果以后弄好了,我在补上。

本文发布于:2023-05-15 17:27:49,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/109598.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:连接   没有   空闲   可能   时候   获取   断开
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图