Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

一个关于 redis 长链接的问题 #1615

Open
ZhangDianPeng opened this issue Jun 29, 2022 · 3 comments
Open

一个关于 redis 长链接的问题 #1615

ZhangDianPeng opened this issue Jun 29, 2022 · 3 comments
Labels

Comments

@ZhangDianPeng
Copy link

ZhangDianPeng commented Jun 29, 2022

我们在使用 ioredis 过程中遇到一个问题,连接的 redis 服务是通过 nginx 四层负载做的主从切换的代理,如果 redis1 可以连通就直接连接 redis1,否则切换到 redis2。但是 node 客户端永远都去连接 nginx:6379。

现在遇到一个问题,就是当 redis1 挂掉以后(比如直接电源关机),这个时候 node 客户端这边大约要等10 分钟左右才能成功连接成功,中间一直 hold 没反应。这个我们测试了下和客户端本身的 tcp.keepalive 配置有关:

net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_keepalive_intvl=75
net.ipv4.tcp_keepalive_probes=9
感觉像是 75 * 9 的时间,确实把系统这个参数改小可以短时间内完成切换。

我们全局 redis 只用了一个长链接,也没有什么连接池之类的,不知道大神之前遇到过类似问题吗?java 相关的服务使用连接池好像没这个问题,我们 redis 配置如下:

redisClient = new Redis(tempRedisParams.port, tempRedisParams.host, {
            password: tempRedisParams.pass,
            connectTimeout: tempRedisParams.connect_timeout,
            enableReadyCheck: false,
            maxRetriesPerRequest: 20,
            keepAlive: 3 * 1000,
            retryStrategy: function (times) {
                console.log('redis.retryTimes:', times, 'clientIndex:', clientIndex, sign);
                let delay = Math.min(times * 100, 5000);
                return delay;
            }
        });

想问下有没有遇到过类似的情况?

@luin
Copy link
Collaborator

luin commented Jun 29, 2022

我想类似的 issue 是这个:#275 。是你描述的问题吗?

@luin luin added the question label Jun 29, 2022
@ZhangDianPeng
Copy link
Author

我看了下,和 #139 这个 issue 比较像,看起来是 node 本身不支持 tcp_keepalive_intvl 和 tcp_keepalive_probes 两个参数的配置,所以 ioredis 也没办法支持。因此连接断开基本需要消耗 75* 9 = 11 min。

看来只能通过在客户端侧添加心跳主动去断开连接来实现了,晚点试下看看,多谢大神。

@FantasyNeurotic
Copy link

FantasyNeurotic commented Dec 19, 2023

我看了下,和 #139 这个 issue 比较像,看起来是 node 本身不支持 tcp_keepalive_intvl 和 tcp_keepalive_probes 两个参数的配置,所以 ioredis 也没办法支持。因此连接断开基本需要消耗 75* 9 = 11 min。

看来只能通过在客户端侧添加心跳主动去断开连接来实现了,晚点试下看看,多谢大神。

这里没发现更好的方式解决这个问题,下面是我解决这个问题的代码

  const delay = (t, v) => new Promise((resolve, reject) => {
    setTimeout(reject.bind(null, v), t);
  });
  const heartBeatFunc = async () => {
    let serverStatus;
    try {
      serverStatus = await Promise.race([
        client.ping('isAlive'),
        delay(5000, 'Ping command timeout'),
      ]);
    } catch (error) {
      app.coreLogger.error('[egg-data:redis] ping 报错', error);
    }
    app.coreLogger.info(`server status: ${serverStatus}`);
    if (!['isAlive', 'pong', 'PONG'].includes(serverStatus)) {
      app.coreLogger.info(`ping status: ${serverStatus} connection disconnect`);
      await client.disconnect();
      await client.connect();
    }
  };

  if (app.config.eggData.heartbeat.enable) {
    let beat = app.config.eggData.heartbeat.interval;
    beat = beat > 0 ? beat : 30;
    schedule.scheduleJob(`*/${beat} * * * * *`, () => {
      heartBeatFunc();
    });
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants