node.js - Redis 连接丢失且没有任何指示

标签 node.js redis

我正在使用一个非常简单的 Redis 发布-订阅应用程序,其中我在 AWS 中有一个 Redis 服务器,以及一个基于 Nodejs 的 Redis 客户端,该客户端位于办公室 LAN 内并订阅某个 channel 。

这一直很有效,直到网络发生变化,并且似乎某些设备现在正在干扰传出连接(我还开始在出站 SSH 连接上收到套接字挂断,我通过在SSH 配置)。

网络更改后,每当执行 Redis 客户端应用程序时,它都会创建一个 Redis 客户端,订阅某个 channel 并对该 channel 中发布的消息进行操作。 它在几分钟内工作正常,但随后停止接收任何消息。

我将 Redis 客户端注册到所有已知的连接事件(包括“错误”事件),添加了“retry_strategy”处理程序,并将配置修改为“socket_keepalive”和“socket_initialdelay”为 10 秒(请参阅下面的代码) )。

尽管如此,当连接受到干扰时,不会触发任何事件。

当应用程序停止接收消息时,我看到 Redis 端口上的连接仍然有效:

dev@server:~> sudo netstat -tlnpua | grep 6379
tcp        0      0 10.43.22.150:52052      <server_ip>:6379     ESTABLISHED 27014/node

我还在端口 6379 上捕获了一个 PCAP,在该端口上我没有看到任何重置或 TCP 错误,并且从连接角度来看,一切似乎都是有效的。

我尝试从 LAN 内运行另一个 Nodejs 应用程序,在其中创建一个连接到 AWS Redis 服务器的客户端,注册所有事件并且仅偶尔发布消息。 几分钟后(连接中断),我尝试发布另一个命令,错误事件处理程序确实被触发:

> client.publish("channel", "ANOTHER TRY")
true
> Error: Redis connection to <server_hostname>:6379 failed - read ECONNRESET
Redis connection ended
Redis reconnecting
Redis connected
Redis connection is ready

因此,如果我在连接受到干扰后尝试通过客户端发布,则确实会调用连接事件回调,并且我可以运行某种重新连接逻辑。

但是在我订阅并等待发布到 channel 的情况下,没有调用连接事件处理程序,并且应用程序基本上已损坏。

应用程序代码:

const redis = require('redis');

const config = { "host": <hostname>, "port": 6379, "socket_keepalive": true, 
"socket_initdelay": 10};

config.retry_strategy =  function (options) {
    console.log("retry strategy. error code: " + (options.error ? 
options.error.code : "N/A"));
    console.log("options.attempt", options.attempt, "options.total_retry_time", 
options.total_retry_time);
    return 2000;
}

const client = redis.createClient(config);

client.on('message', function(channel, message) {
    console.log("Channel", channel, ", message", message);
});

client.on("error", function (err) {
    console.log("Error " + err);
});

client.on("end", function () {
    console.log("Redis connection ended");
});

client.on("connect", function () {
    console.log("Redis connected");
});

client.on("reconnecting", function () {
    console.log("Redis reconnecting");
});

client.on("ready", function () {
    console.log("Redis connection is ready");
});

const channel = "channel";
console.log("Subscribing to channel", channel);
client.subscribe(channel);

我使用的是 redis@2.8.0 和 Node v8.11.3。

最佳答案

这个问题的解决方案很令人遗憾。

首先,redis客户端和服务器之间确实存在一些网络设备,它会在超时后丢弃不活动的连接。看来这个超时时间真的很低(几分钟)。

Redis 有一个默认启用的 socket_keepalive 配置,它的默认值是 Node.js 的默认套接字保持事件值(如果我没记错的话,设置为 2 小时)。

如上所示,我使用了一个 socket_initdelay 配置参数,该参数应该更改此默认值,但不幸的是,使用此参数的代码不在 redis 中> npm 包,而是在 node-redis 中。

总结一下: redis@2.8.0(撰写本文时的最新版本)中没有配置设置可以更改保持事件超时值。 您可以:

  1. 使用接受 socket_initdelay 设置的 node-redis

  2. 通过运行以下命令手动修改超时:

const client = redis.createClient();
client.on("connect", function () {
    client.stream.setKeepAlive(true, <timeout_value_in_milliseconds>);
}

关于node.js - Redis 连接丢失且没有任何指示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57383470/

相关文章:

ruby-on-rails - 不使用 Heroku 上的 Resque 进行后台作业

python - 为什么我会收到有关 String not defined 的错误消息?

php - PHP使用Redis存储Session需要多少个socket?

python - Redis 中的字典列表

javascript - 使用 Javascript 的表格内容的正则表达式

node.js - 用于获取给定一个点的边界框的 API 或框架

css - 使用 Grunt 构建 Stylus 主题

node.js - AWS Lambda SDK - TooManyRequestsException

javascript - 为什么我的 AWS Lambda 函数总是超时?

node.js - React Stripe - 如何保存信用卡信息?