背景:
1.系统由多个进程组成,几乎每个进程都需要访问redis。
2.所有进程都部署在一台机器,包括redis/mysql。
3.redis驱动程序使用的是jedis 2.8。
4.每个进程配置的redis连接池数量都较大,最大大概几百个连接。
5.现场人员报告,页面某功能偶现不可用的情况,经查相关进程日志,是由于redis连接建立失败导致的。
排查过程:
1.搭建压力测试环境,模拟现网压力,同样出现了redis建立连接失败,异常显示socket connection timeout。
2.尝试修改连接池配置,将idl调成和total一致,均为200,问题并未解决。
3.尝试加大连接池数量,问题并未解决。
4.后来想到,redis服务器是单线程的,即同一时刻,仅处理一个连接发出的指令,那么连接池中的多个连接,虽然将指令发送至redis,但redis并未立即处理,而是在排队。那么,与其将指令发送给redis,在redis端排队,不如在本进程内排队,暂不将指令发送至redis,即将redis连接池idl/total均设为1,仅维持一条与redis的连接,如果业务量过大,本进程内排队超时,也就是等待从连接池获取连接超时,那么可以通过加大连接池的maxwait值来解决。想到此点之后,将连接池idl/total调整为1,开始压力测试,未再出现连接建立超时。
5.问题解决。
经验:redis服务器是单线程模型,加大连接池,只是加大排队的队列数,但是,redis是多进程共用,压力较大,在处理大量的redis指令的同时,还要维护大量的连接,是很耗资源的。所以,每个进程仅维持一条与redis的连接,通过加大maxwait,来控制在本进程内排队,可以降低redis的压力。redis和mysql等不同,mysql是可以多个连接的指令并行执行的,所以连接池设置过大没有意义。