Redis缓冲区设置

对于Redis服务器的输出(也就是命令的返回值)来说,其大小通常是不可控制的。有可能一个简单的命令,能够产生体积庞大的返回数据。另外也有可能因为执行了太多命令,导致产生返回数据的速率超过了往客户端发送的速率,这是也会导致服务器堆积大量消息,从而导致输出缓冲区越来越大,占用过多内存,甚至导致系统崩溃。

所幸,Redis设置了一些保护机制来避免这种情况的出现,不同类型的客户端有不同的限制参数。限制方式有如下两种:

(1)、大小限制,当某一个客户端的缓冲区超过某一个大小值时,直接关闭这个客户端的连接;

(2)、持续性限制,当某一个客户端的缓冲区持续一段时间占用过大空间时,会直接关闭客户端连接。

 

我们来看看配置文件关于客户端输出缓冲区的配置:

client-output-buffer-limit normal 0 0 0

client-output-buffer-limit slave 256mb 64mb 60

client-output-buffer-limit pubsub 8mb 2mb 60

 

不同客户端有不同策略,策略如下:

Ø  对于普通客户端来说,限制为0,也就是不限制。因为普通客户端通常采用阻塞式的消息应答模式,何谓阻塞式呢?如:发送请求,等待返回,再发送请求,再等待返回。这种模式下,通常不会导致Redis服务器输出缓冲区的堆积膨胀;

Ø  对于Pub/Sub客户端(也就是发布/订阅模式),大小限制是8M,当输出缓冲区超过8M时,会关闭连接。持续性限制是,当客户端缓冲区大小持续60秒超过2M,则关闭客户端连接;

Ø  对于slave客户端来说,大小限制是256M,持续性限制是当客户端缓冲区大小持续60秒超过64M,则关闭客户端连接。

上述三种规则都是可以修改的。可以通过CONFIG SET 命令设置或者直接修改redis.conf文件。

 

 

 

 

 

 

 

jedis 的 Unexpected end of stream 解决方案

  • redis 服务端版本号:2.8.X
  • Jedis 客户端版本号:2.8.1
  • 单线程、无并发操作

Jedis单链接、JedisPool、ShardedJedisPool,无论使用哪一种方式对 redis 服务进行操作,均出现了 Unexpected end of stream 的问题。

通过查看源码发现,报错具体位置是:RedisInputStream 类的 ensureFill() 方法

private void ensureFill() throws JedisConnectionException {
    if (count >= limit) {
      try {
        limit = in.read(buf);
        count = 0;
        if (limit == -1) {
          throw new JedisConnectionException("Unexpected end of stream.");
        }
      } catch (IOException e) {
        throw new JedisConnectionException(e);
      }
    }
  }

 

解决方案:

第一步,检查 redis config 中的 client-output-buffer-limit 配置

client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 0 0 0
client-output-buffer-limit pubsub 0 0 0
  • 1
  • 2
  • 3

请根据实际情况合理设置Redis输出缓冲区限制,确定不是因为缓冲区太小,导致链接关闭,进而引起 Unexpected end of stream ,可以临时都设置成 “0(关闭缓冲区限制)” 来验证此种场景

第二步,检查 redis config 中的 timeout 配置

当此时间设置过短时,同一个 jedis 链接,两次访问 redis 服务的时间间隔 > ${timeout} , 服务端会单方关闭这个jedis链接,第二次使用这个jedis对象 操作 redis 时,会发生 Unexpected end of stream , 可以将其设置成“0(无过期)”来验证此种场景

第三步,优化客户端代码,增加重试机制

经过前两步的调试,根据业务实际情况,调整配置,但这样并不能完全杜绝 Unexpected end of stream 的发生,比如 “网络抖动”之类的场景下,依然会发生此问题(实际生产环境中,此种情况发生概率极低), 
但是为了防止此异常引起 jvm宕机,建议在代码层面上增加加重试机制。

话外篇:

使用 redis 做存储层时,有可能出现数数据不一致的情况( redis 无事务)

posted @ 2018-01-16 12:51  Mr.Ming2  阅读(5781)  评论(1编辑  收藏  举报