Redis连接丢失,没有任何迹象

时间:2019-08-06 20:22:02

标签: node.js redis

我正在使用一个非常简单的redis pub-sub应用程序,其中我在AWS中有一个Redis服务器,而位于办公室LAN内并订阅某个频道的基于Node.js的Redis客户端。

这一直有效,直到网络发生变化,并且似乎某些设备现在正在干扰传出连接(我也开始在出站SSH连接上接收套接字挂断,我通过SSH配置中的ServerAliveInterval 60设置缓解了此问题)。

网络更改后,每当执行redis客户端应用程序时,它都会创建一个redis客户端,订阅某个频道并根据该频道中已发布的消息进行操作。 可以正常运行几分钟,但是随后它停止接收任何消息。

我将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

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

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

应用代码:

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和节点v8.11.3。

1 个答案:

答案 0 :(得分:2)

此问题的解决方案非常可悲。

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

Redis具有 private void timerFFTp_Tick(object sender, EventArgs e) { if (drawBitmap) { Bitmap bitmap = new Bitmap(_fftControl.Width, _fftControl.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); _fftControl.DrawToBitmap(bitmap, new Rectangle(0, 0, _fftControl.Width, _fftControl.Height)); if (!fDraw) { bitmap.MakeTransparent(); Bitmap fftFormBitmap = new Bitmap(_fftForm.BackgroundImage); Graphics g = Graphics.FromImage(fftFormBitmap); g.DrawImage(bitmap, 0, 0); _fftForm.BackgroundImage = fftFormBitmap; } else { fDraw = false; _fftForm.Width = bitmap.Width + 16; _fftForm.Height = bitmap.Height + 48; _fftForm.BackgroundImage = bitmap; } } } 配置,默认情况下启用此配置,其默认值为Node.js的默认套接字保持活动值(如果我没记错的话,将其设置为2小时)。

从上面可以看到,我使用了一个socket_keepalive配置参数,该参数应该已经更改了该默认值,但是不幸的是,使用此参数的代码不在socket_initdelay npm包中,而是在redis

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

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

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

socket_initdelay