Redis学习(十二)连接数不足报错及分析修复:ERR max number of clients reached.

一、问题介绍

我们在日常的开发过程中,经常会遇到 Redis 连接数不足 的情况,报错如下所示:

  • Caused by: org.redisson.client.RedisException: ERR max number of clients reached. channel
Caused by: org.redisson.client.RedisException: ERR max number of clients reached. channel: [id: 0xf10fcc26, L:/192.168.30.13:64137 - R:192.168.1.163/192.168.1.163:6379] command: (SELECT), params: [1]
	at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:365)
	at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:209)
	at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:147)
	at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:117)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:505)
	at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:283)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1421)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:697)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:632)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:549)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511)
	... 4 common frames omitted

二、问题分析

ERR max number of clients reached. channel 报错是因为 Redis 的连接数不足 导致的。

2.1 redis-cli 登录

我们可以先使用如下命令登录 Redis 的客户端:

  • redis-cli -h 127.0.0.1 -p 6379 -c --raw

    -c:(cluster)选项是连接 Redis Cluster 结点需要使用的。-c 选项可以防止 movedask 异常。

    --raw:选项是反馈格式化后的结果,默认选项。相对应的是 --no-raw,即返回原始格式(二进制)。

2.2 info clients 查看连接数情况

查看 Redis 的当前连接数:

  • info clients
##版本6.2.4,相对5版本新增了部分显示信息

##当前redis节点的客户端连接数
connected_clients:1
##集群的连接数
cluster_connections:0
##客户端最大连接数
maxclients:10000
##当前所有输入缓冲区中队列对象个数的最大值
client_recent_max_input_buffer:24
##当前所有输出缓冲区中占用的最大容量
client_recent_max_output_buffer:0
##正在执行阻塞命令的客户端个数
blocked_clients:0
tracking_clients:0
clients_in_timeout_table:0

2.3 client list 查看具体连接情况

查看 Redis 的具体连接情况:

  • client list

在这里插入图片描述

id=17750 addr=192.168.1.254:35864 laddr=172.17.0.3:6379 fd=9615 name= age=266661 idle=266661 flags=N db=2 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 argv-mem=0 obl=0 oll=0 omem=0 tot-mem=20504 events=r cmd=select user=default redir=-1
id=2575 addr=192.168.1.254:44133 laddr=172.17.0.3:6379 fd=1885 name= age=422195 idle=422195 flags=N db=2 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 argv-mem=0 obl=0 oll=0 omem=0 tot-mem=20504 events=r cmd=select user=default redir=-1
id=18212 addr=192.168.1.254:61386 laddr=172.17.0.3:6379 fd=9929 name= age=266308 idle=266308 flags=N db=2 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 argv-mem=0 obl=0 oll=0 omem=0 tot-mem=20504 events=r cmd=select user=default redir=-1
id=13437 addr=192.168.1.254:17625 laddr=172.17.0.3:6379 fd=6431 name= age=349287 idle=349287 flags=N db=2 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 argv-mem=0 obl=0 oll=0 omem=0 tot-mem=20504 events=r cmd=select user=default redir=-1
id=12730 addr=192.168.1.254:15535 laddr=172.17.0.3:6379 fd=6226 name= age=350448 idle=350448 flags=N db=2 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 argv-mem=0 obl=0 oll=0 omem=0 tot-mem=20504 events=r cmd=select user=default redir=-1

client list 属性说明如下:

属性说明
id客户端连接ID
addr客户端连接IP和端口
laddrredis数据库连接地址和端口
fdsocket的文件描述符
name客户端连接名
age客户端连接存活时间
idle客户端连接空闲时间,单位秒。可以用于判断连接是否有没有被及时释放
flags客户端类型标识
db当前客户正在使用的数据库索引下标
sub/psub当前客户端订阅的频道或模式数
multi当前事务中已执行命令个数
qbuf输入缓冲区总容量
qbuf-free输入缓冲区剩余容量
argv-mem下一个命令的不完整参数(已从查询缓冲区中提取)
obl固定缓冲区的长度
oll动态缓冲区列表的长度
omem固定缓冲区和动态缓冲区使用的容量
tot-mem此客户端在其各个缓冲区中消耗的总内存
events文件描述符时间(r:可读;w:可写)
cmd当前客户端最后一次执行的命令,不包含参数
user用户名称,默认default
redir当前用户跟踪重定位的客户端ID

2.4 分析连接空闲时长

了解了以上的属性,我们再反观刚才 client list 的执行结果,可以看到:

  • 其中 idle(客户端连接空闲时间)和 age(客户端连接存活时间)的值基本一致,说明大部分的连接是没有用到的。

在这里插入图片描述

2.5 client list 根据客户端IP统计连接数

命令如下:

redis-cli -h 127.0.0.1 -p 6379 -c --raw client list | awk -F ' ' '{print $2}' | awk -F : '{print $1}' | sort | uniq -c | sort -nr | head -n 10

docker 命令版:

docker exec -it redis redis-cli client list | awk -F ' ' '{print $2}' | awk -F : '{print $1}' | sort | uniq -c | sort -nr | head -n 10

执行结果:

在这里插入图片描述


三、问题结论和解决

3.1 问题结论:

从上面的问题分析可以看出,问题原因是大部分连接被某一个IP占用导致的,可能是Redis最小连接数配置错误,或者程序Bug导致的。

3.2 解决方案①:优化程序

可以根据客户端的IP和端口定位到客户端的具体应用进行优化,但是如果客户端应用不是在你们部门维护的就不太好推进了。

3.3 解决方案②:扩大最大连接数

  • 方式一:redis.conf 配置文件中进行修改,如下所示:
# 设置最大连接数为10w
maxclients 100000
  • 方式二: 通过命令设置,如下所示:
config set maxclients 100000
  • 方式三: 启动 redis.service 服务时,添加参数 --maxclients 100000,如下所示:
redis-server --maxclients 100000 -f /ext/redis.conf
  • 验证: 使用命令查看最大连接数,如下所示:
config get maxclients

3.4 解决方案③:杀死指定连接

可以在 redis 中使用如下命令杀死指定连接:

# 方式一:通过ip:port杀死
client kill ip:port
# 方式二:通过连接ID杀死
client kill id 5299

可以使用如下命令针对指定 IP 的连接进行批量杀死,例如批量杀死192.168.1.123的 3 个连接:

redis-cli client list | grep '192.168.1.123' | awk -F ' ' '{print \$1}' | sed 's/id=//g' | head -n 3 | xargs -n 1 redis-cli client kill id
  • 如果需要杀死所有连接,可以去掉 head -n 3

docker 命令版:

docker exec -it redis sh -c "redis-cli client list | grep '192.168.1.254' | awk -F ' ' '{print \$1}' | sed 's/id=//g' | head -n 3 | xargs -n 1 redis-cli client kill id"
  • 注意1: 这里需要使用 sh -c 来包装整个命令,确保命令在一个子 shell 中执行,否则会报错: the input device is not a TTY
  • 注意2: 这里需要使用 xargs -n 1 来将 awk 筛选后的结果逐行执行,-n 1 用于确保逐行执行,否则会报错: (error) ERR syntax error
  • 如果需要杀死所有连接,可以去掉 head -n 3

整理完毕,完结撒花~🌻





参考地址:

1.Redis:13–常用功能之redis-cli redis-server等命令,https://cloud.tencent.com/developer/article/1784416
2.redis client list使用,https://blog.csdn.net/weixin_44375561/article/details/121955791
3.[问题分析]redis客户端连接数过多,大量空闲连接和readonly连接,https://segmentfault.com/a/1190000020256823

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不愿放下技术的小赵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值