【问题标题】:why did i get redis command timeout when using brpop comand whose timeout option value(50 seconds)is less than redis command timeout(200s) setting?为什么我在使用超时选项值(50 秒)小于 redis 命令超时(200 秒)设置的 brpop 命令时出现 redis 命令超时?
【发布时间】:2021-11-05 23:26:14
【问题描述】:

我使用 redis 列表作为分布式阻塞队列。在客户端,我使用以下代码:

public String tryAquire(String appName, long timeout, TimeUnit timeUnit){
  return String.valueOf(redisTemplate.opsForList.rightPop(getKey(appName), timeout, timeUnint)); 
}

它在内部使用brpop 命令,并且超时值设置为小于50 秒。这项服务可以正常运行大约两周,直到最近 2 天我发现了一些例外情况:

org.springframework.QueryTimeoutException:Redis command time out;
nest exception is io.lettuce.core.RedisCommandException:
Command time out after 200 seconds(s)

这个异常每天出现 1 到 2 次,每天大约有 2000 个请求,在这个异常之后服务器仍然可以正常工作,后续请求的花费时间变得正常,但是抛出这个异常的请求将花费超过 200 秒和这是一个非常糟糕的情况。

这个超时值(200 秒)适合我的 lettuce 客户端命令超时设置。

但是,对于tryAquire(appName, timeout, timeUnit) 方法,最大阻塞时间设置为小于 50 秒。因此,这个命令不应该花费超过 50 秒的时间,因为 50 秒后如果 redis 列表中没有元素,它应该只返回 null 而不是继续等待。似乎没有网络问题,因为日志中没有与套接字相关的异常,并且在redis命令超时异常之后,后续请求执行成功。

【问题讨论】:

    标签: java redis spring-data-redis


    【解决方案1】:

    以防万一有人遇到同样的问题。长话短说:NAT 映射到期,并且在达到最大 tcp 重试次数后,应用程序会发现断开的网络链接。

    此服务部署在使用定制 SDN 的云环境中。如果一段时间内 tcp 连接上没有活动,则 NAT 映射过期。但是,tcp 客户端和服务器都无法意识到这一点,即使 NAT 映射已过期,客户端也会继续尝试发送数据,直到达到某些 tcp 重试最大限制配置。

    一个简单的解决方案:只需将redis服务器“tcp-keepalive”配置值设置为小于NAT映射过期时间,或者如果您不想更改redis服务器设置,请使用任何其他心跳机制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-17
      • 1970-01-01
      • 2021-09-06
      • 2021-10-07
      • 1970-01-01
      • 2012-05-17
      • 2015-09-18
      • 2013-04-03
      相关资源
      最近更新 更多