失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 【Redis】Redis最大连接数maxTotal设置过小的问题

【Redis】Redis最大连接数maxTotal设置过小的问题

时间:2020-12-04 12:19:15

相关推荐

【Redis】Redis最大连接数maxTotal设置过小的问题

最近由于不合理的配置了redis中的最大连接数导致了线上服务间歇性不可用的问题,问题无小事,稳定大于一切。

一、结论

先直接说结论:并发量激增,redis最大连接数过小,导致获取redis连接超时,超时导致大量请求阻塞,从而导致客户端因超时主动关闭连接,服务端大量请求阻塞,无法关闭连接,慢慢积累出现close_wait,大量close_wait出现,旧连接不释放,新连接无法创建,导致没法对外提供服务。

方案:1)redis连接池要根据具体的业务量进行设置,太大连接数过多浪费资源,过小无法获取连接,影响业务。

2)不管是请求第三方系统还是缓存,数据库,大数据系统(Hbase)等中间件,要设置符合预期的timeout和降级操作,否则请求积压会拖死系统。

3)当服务出现大量close_wait的情况下,大概率都是服务本身的问题,需要排查响应的代码。

二、现象

2.1 服务模块图

服务模块图

2.2 翻车现场重现

1)由于业务扩展,访问大概增加3倍,因此选择扩容了一倍机器。

2)机器扩容之后,报警来了,说是redis proxy的连接水位找过了70%,op让减小连接数,之前最大连接数maxTotal设置的3000,运维让减小到300,没多想,修改了,上线,proxy不在报警,感觉很好。

3)有个别机器开始间歇性报警,端口不可用,应该是服务内部出现了问题。

2.3 查看各种监控(蓝色问题机器,棕色正常机器)

端口可用性降低:

业务日志明显变少:

mem.used 内存使用骤降

thread.num 线程骤增

close_wait 大量出现:

业务日志:

Caused by: redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool

三、原因

结合之前上线的修改以及业务日志,应该是并发量大的情况下,无法从redis连接池中获取到连接(maxTotal设置过小),导致报错。

3.1 为什么获取不到连接会导致服务不可用?

看一下redis的配置

<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"><!-- 最大空闲数 --><property name="maxIdle" value="100" /><!-- 连接池的最大数据库连接数 --><property name="maxTotal" value="300" /><!-- 最小空连接数 --><property name="minIdle" value="100" /><!-- 最大建立连接等待时间 --><property name="maxWaitMillis" value="1000" /><!-- 连接超时时是否阻塞,false时报异常,true阻塞直到超时, 默认true --><property name="blockWhenExhausted" value="true" /><!-- 返回连接时,检测连接是否成功 --><property name="testOnBorrow" value="true" /><!--定时对线程池中空闲的链接进行validateObject校验 --><property name="testWhileIdle" value="true" /><!--在进行returnObject对返回的connection进行validateObject校验 --><property name="testOnReturn" value="true" /></bean>

看到blockWhenExhausted这个参数是true,说明如果获取连接失败,那么会阻塞maxWaitMills那么长时间再尝试获取连接。那么很清晰了,最大连接数设置的300,但是并发量比它大一到两倍,自然会有大量的请求阻塞在获取连接的阶段。

3.2 什么是close_wait?

感觉学的东西都还给书本了。

active close:主动关闭的一方

passive close:被动关闭的一方

3.3 为什么会出现大量close_wait?

上游在请求的过程中也是有超时时间的,当上游主动发起关闭连接的时候,由于请求在服务端非常慢,收到关闭请求之后就会处于close_wait状态,慢慢的大量的请求积压使得连接处于close_wait状态。

3.4 为什么大量close_wait会影响服务接收请求?

因为大量的连接处于待关闭状态,没法释放资源来应对新的连接。或者说由于端口未释放,导致tcp连接失败。

四、复现

通过微服务来将场景进行复现,服务A:ip:8300;服务B:ip:8200,A.a访问B.b,接口b内部sleep 20s,A.a对B.b的访问有2000ms的超时降级,我们观察一下从A.a发起向B.b访问过程中的网络状态。

发起访问:localhost: wahaha$ netstat -anlt | grep "8200\|8300\|Local"Proto Recv-Q Send-Q Local AddressForeign Address (state)tcp4600 *.8300 *.*LISTENtcp4600 *.8200 *.*LISTENProto/ID FlagsLocal AddressForeign Address (state)2s以内:localhost: wahaha$ netstat -anlt | grep "8200\|8300\|Local"Proto Recv-Q Send-Q Local AddressForeign Address (state)tcp4 00 192.168.0.107.8200192.168.0.107.65332 ESTABLISHEDtcp4 00 192.168.0.107.65332 192.168.0.107.8200ESTABLISHEDtcp6 00 ::1.8300 ::1.65331 ESTABLISHEDtcp6 00 ::1.65331 ::1.8300 ESTABLISHEDtcp4600 *.8300 *.*LISTENtcp4600 *.8200 *.*LISTENProto/ID FlagsLocal AddressForeign Address (state)2s ~ 20s:localhost: wahaha$ netstat -anlt | grep "8200\|8300\|Local"Proto Recv-Q Send-Q Local AddressForeign Address (state)tcp4 00 192.168.0.107.8200192.168.0.107.65332 CLOSE_WAITtcp4 00 192.168.0.107.65332 192.168.0.107.8200FIN_WAIT_2tcp4600 *.8300 *.*LISTENtcp4600 *.8200 *.*LISTENtcp6 00 ::1.8300 ::1.65331 TIME_WAITProto/ID FlagsLocal AddressForeign Address (state)20s以后:localhost: wahaha$ netstat -anlt | grep "8200\|8300\|Local"Proto Recv-Q Send-Q Local AddressForeign Address (state)tcp4600 *.8300 *.*LISTENtcp4600 *.8200 *.*LISTENProto/ID FlagsLocal AddressForeign Address (state)

可以看到在2s ~ 20s直接出现CLOSE_WAIT是客户端超时主动关闭导致的。

五、总结

1)合理的设置redis连接池大小,根据业务进行估算。

2)访问第三方服务和中间件要做降级。

3)大量close_wait出现大概率是被主动关闭了连接,并且有大量超时请求阻塞。

Author:忆之独秀

Email:leaguenew@

注明出处:https://lavorange./article/details/106984845

如果觉得《【Redis】Redis最大连接数maxTotal设置过小的问题》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。