找回密码
 立即注册
首页 业界区 业界 [Redis] Redis (7) 连接与会话管理

[Redis] Redis (7) 连接与会话管理

边书仪 2025-6-3 00:20:04
序:文由


  • 因今日排查问题,发现微服务因 ERR max number of clients reached (已达到客户端的最大数量) redis异常,而导致服务在健康检测时未通过,进而导致高频宕机。
概述:Redis 连接与会话管理

Redis 连接会话的原理


  • redis通过监听一个TCP端口或socket的方式接收来自客户端的连接,当与客户端建立连接后,redis内部会进行如下操作:
(1)客户端socket会被设置为非阻塞模式,因为redis在网络时间处理上采用的是非阻塞多路复用模型;
(2)为这个socket设置TCP_NODELAY属性,禁用Nagle算法;
(3)创建一个可读的文件事件用于监听这个客户端socket的数据发送。
常用功能与指令

连接操作类

查看连接总数 : info clients
  1. > info clients
  2. # Clients
  3. connected_clients:95
  4. client_recent_max_input_buffer:2
  5. client_recent_max_output_buffer:0
  6. blocked_clients:0
  7. rx_controlled_clients:0
  8. total_real_rx_controlled:0
  9. total_tx_controlled:0
  10. total_rx_controlled:824214
  11. proxy_header_error:0
复制代码
查看连接详情列表 : client list


  • client list : 命令用于返回所有连接到服务器的客户端信息和统计数据。
http://www.redis.cn/commands/client-list.html
  1. client list
复制代码
1.png


  • 返回值
bulk-string-reply: 一个独特的字符串。具体格式:
每个已连接客户端对应一行(以 LF 分割)
每行字符串由一系列 属性=值(property=value) 形式的域组成,每个域之间以空格分开。
各字段的含义::
  1. id: 唯一的64位的客户端ID(Redis 2.8.12加入)。
  2. addr: 客户端的地址和端口
  3. fd: 套接字所使用的文件描述符
  4. age: 以秒计算的已连接时长
  5. idle: 以秒计算的空闲时长
  6. flags: 客户端 flag
  7. db: 该客户端正在使用的数据库 ID
  8. sub: 已订阅频道的数量
  9. psub: 已订阅模式的数量
  10. multi: 在事务中被执行的命令数量
  11. qbuf: 查询缓冲区的长度(字节为单位, 0 表示没有分配查询缓冲区)
  12. qbuf-free: 查询缓冲区剩余空间的长度(字节为单位, 0 表示没有剩余空间)
  13. obl: 输出缓冲区的长度(字节为单位, 0 表示没有分配输出缓冲区)
  14. oll: 输出列表包含的对象数量(当输出缓冲区没有剩余空间时,命令回复会以字符串对象的形式被入队到这个队列里)
  15. omem: 输出缓冲区和输出列表占用的内存总量
  16. events: 文件描述符事件
  17. cmd: 最近一次执行的命令
复制代码
设置当前连接点redis的名称 : CLIENT SETNAME
  1. CLIENT SETNAME
复制代码
查看当前连接的名称 : CLIENT GETNAME
  1. CLIENT GETNAME
复制代码
杀死指定连接 : CLIENT KILL {ip}:{port}
  1. CLIENT KILL {ip}:{port}
复制代码
连接配置类

查看/设置连接的默认超时自动断连时间(空闲超时时间) : config [get|set] timeout [{second}]


  • 查看连接的默认超时自动断连时间(空闲超时时间)
默认值 = 0
  1. > config get timeout
  2. 0
复制代码

  • 设置连接的默认超时自动断连时间(空闲超时时间)
单位:秒钟
  1. config set timeout 600
复制代码
查询/设置允许的最大连接数 : config get maxclients


  • 查询允许的最大连接数
  1. config get maxclients
复制代码

  • 设置允许的最大连接数
方法1:在2.6之后版本,可以修改最大连接数配置,默认10000,可以在redis.conf配置文件中修改
  1. ...
  2. # maxclients 10000
  3. ...
复制代码
方法2: config set maxclients num 可以设置redis允许的最大连接数
  1. 127.0.0.1:6379> CONFIG set maxclients 10
  2. OK
  3. 127.0.0.1:6379>
复制代码
方法3:启动redis.service服务时加参数--maxclients 100000来设置最大连接数限制
  1. redis-server --maxclients 100000 -f /etc/redis.conf
复制代码
FAQ for Redis 连接与会话管理

Q: 连接过多,乃至报ERR max number of clients reached(Redis客户端连接数已达到最大限制)?


  • 问题分析


  • redis maxclients
redis maxclients 是redis server的重要配置,它决定了客户端的最大连接数量最大客户端连接数量
由于redis不区分连接是客户端连接、还是内部打开文件、或者和slave连接等。所以,maxclients最小存在32个连接数,如果超过了设置的maxclients,redis会给新的连接发送"max number of clients reached",并关闭连接


  • 硬编码限制
在Redis 2.4中,可以同时处理的最大客户端数量存在硬编码限制
在Redis 2.6中,此限制是动态的:默认情况下,它设置为10000个客户端,除非Redis.conf中的maxclients指令另有说明。


  • 原因分析
绝大部分原因:由于客户端很多空闲连接都没有被及时释放掉,从而导致connected_clients非常高
其他可能:maxclients设置的太少了
还有可能:软硬件存在限制


  • 解决方法


  • 1 客户端 - 设置超时时间
  1. JedisPoolConfig jedisPoolConfig = initPoolConfig();   
  2. jedisPool = new JedisPool(jedisPoolConfig, "*.*.*.*", 6379);  
  3. =========> 修改为:
  4. JedisPoolConfig jedisPoolConfig = initPoolConfig();   
  5. jedisPool = new JedisPool(jedisPoolConfig, "*.*.*.*", 6379, 2*1000); //timeout = 2*1000 = connectionTimeout = soTimeout
复制代码
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port, final int connectionTimeout, final int soTimeout, final String password, final int database, final String clientName)


  • 2 客户端 - 回收连接资源
  1.         Jedis jedis = JedisUtils.getJedis();
  2.         try {
  3.                 //Todo
  4.     } catch (Exception e){
  5.         throw new RuntimeException(e.getMessage(), e);
  6.         JedisUtils.returnBrokenResource(jedis); //释放连接
  7.     } finally {
  8.         JedisUtils.returnResource(jedis); //释放连接
  9.     }
  10. ----
  11.     /**
  12.          * 回收Jedis对象资源
  13.          *
  14.          * @param jedis
  15.          */
  16.         public synchronized void returnResource(Jedis jedis) {
  17.                 if (jedis != null) {
  18.                         jedisPool.returnResource(jedis);
  19.                 }
  20.         }
  21.         /**
  22.          * Jedis对象出异常的时候,回收Jedis对象资源
  23.          *
  24.          * @param jedis
  25.          */
  26.         public synchronized void returnBrokenResource(Jedis jedis) {
  27.                 if (jedis != null) {
  28.                         jedisPool.returnBrokenResource(jedis);
  29.                 }
  30.         }
复制代码
在 Jedis 2.6.2 以后,由于重写了jedis.close(),实现自动关闭,2.6.3以后正式使用,详见Deprecates JedisPool returnResource and returnBrokenResource ,这样可以代码使用JDK7中新增的try-with-resource语法糖,这样代码会简洁很多如下:
  1.     try (Jedis jedis = JedisUtils.getJedis()) {
  2.         //Todo
  3.     } catch (Exception e) {
  4.         throw new RuntimeException(e.getMessage(), e);
  5.     }
复制代码


  • 3 通过ip排查对应的service服务,查看是否还可以进行优化。
  • 4 查看空闲超时时间: config get timeout
0 : 默认不开启


  • 5 设置空闲超时时间 : config set timeout {second}
建议为0,尤其是有用分布式锁的情况下、具体看业务场景
如:配置默认空闲超时时间为60s : config set timeout 60


  • 6 config rewrit : 保存
可在 redis.conf 配置文件中添加重启生效。
X 参考文献


  • redis 连接工具_redis之timeout(默认建议为0) , maxclients(重要)  - 博客园
  • 解决Redis 连接池报错:ERR max number of clients reached - CSDN 【推荐】
  • 生产-已解决-Redis连接数占满 报错 (error) ERR max number of clients reached - CSDN 【推荐】
(error) ERR max number of clients reached
"我仔细审查了一下前同事写的Redis工具类,发现连接用完,全都没有归还连接"
  1.     public <T> T get(String key, String modulePrefix, Class<T> t) {
  2.         checkJedisPool();
  3.         key = generateKey(key, modulePrefix);
  4.         try (Jedis jedis = jedisPool.getResource()) {
  5.             String valueStr = jedis.get(key);
  6.             return parse(valueStr, t);
  7.         }
  8.     }
复制代码
   本文作者:        千千寰宇   
    本文链接:         https://www.cnblogs.com/johnnyzen   
    关于博文:评论和私信会在第一时间回复,或直接私信我。   
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA     许可协议。转载请注明出处!
    日常交流:大数据与软件开发-QQ交流群: 774386015        【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!   

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册