【问题标题】:Firebase function connection with GCP Redis instance in the same VPC keeps on disconnectingFirebase函数与同一VPC中的GCP Redis实例的连接不断断开
【发布时间】:2020-12-24 23:56:23
【问题描述】:

我正在开发多个 Firebase 云功能(全部托管在同一区域),它们使用 VPC 连接器与同一区域中的 GCP 托管 Redis 实例连接。我正在为 Redis 使用 3.0.2 版的 nodejs 库。在云功能的调试日志中,我看到频繁的连接重置日志,这些日志是针对每个云功能触发的,在连接重置的时间线周围没有固定模式。并且每次在错误事件处理程序中捕获的错误都是 ECONNRESET。在创建 Redis 实例时,我提供了一个 retry_strategy 以在 5 毫秒后重新连接,最多 10 次这样的尝试,同时将 retry_unfulfilled_commands 设置为 true,期望在连接重置时任何未完成的命令都会自动重试(参考代码下面)。

const redisLib = require('redis');
const client = redisLib.createClient(REDIS_PORT, REDIS_HOST, {
    enable_offline_queue: true,
    retry_unfulfilled_commands: true,
    retry_strategy: function(options) {
        if (options.error && options.error.code === "ECONNREFUSED") {
          // End reconnecting on a specific error and flush all commands with
          // a individual error
          return new Error("The server refused the connection");
        }

        if (options.attempt > REDIS_CONNECTION_RETRY_ATTEMPTS) {
          // End reconnecting with built in error
          console.log('Connection retry count exceeded 10');
          return undefined;
        }

        // reconnect after 5 ms
        console.log('Retrying connection after 5 ms');
        return 5;
      },
});

client.on('connect', () => {
    console.log('Redis instance connected');
});

client.on('error', (err) => {
    console.error(`Error connecting to Redis instance - ${err}`);
});

exports.getUserDataForId = (userId) => {
    console.log('getUserDataForId invoked');
    return new Promise((resolve, reject) => {
        if(!client.connected) {
            console.log('Redis instance not yet connected');
        } 
        
        client.get(userId, (err, reply) => {
            if(err) {
                console.error(JSON.stringify(err));
                reject(err);
            } else {
                resolve(reply);
            }
        });
    });
}

// more such exports for different operations

以下是我面临的问题/问题。

  1. 为什么连接会间歇性重置?
  2. 我看过日志,即使正在执行云功能,与Redis服务器的连接丢失导致命令失败。
  3. retry_unfulfilled_commands 设置为 true,我希望它能处理上面第 2 点中提到的场景,但根据调试日志,云功能在这种情况下会超时。这就是我在那种情况下的日志中观察到的。
getUserDataForId invoked
Retrying connection after 5 ms
Redis instance connected
Function execution took 60002 ms, finished with status: 'timeout' --> coming from wrapper cloud function
  1. 我是否应该尝试在每次这样的 Redis 操作期间创建一个连接,而不是在全局级别创建一个 Redis 连接实例?它可能存在一些性能问题以及有关并发 Redis 连接数量的问题(因为我有多个云功能,并且所有这些功能都会为每个同时调用创建 Redis 连接),对吗?

所以,如何最好地处理它,因为我在开发过程中遇到了所有这些问题,所以不确定是代码相关问题还是一些基础设施配置相关问题。

【问题讨论】:

  • 您是使用 Memorystore for Redis 还是您的 Redis 托管在 GCE 实例或 GKE 上?您还可以与我们分享您正在使用的 Redis 版本以及 ECONNRESET 错误的完整日志条目。
  • 我正在使用 Memorystore for Redis。版本为 4.0(基本层)。除了记录为 ECONNRESET 的错误外,我在云功能日志中看不到任何其他日志。有没有办法获得增强的 Redis 日志记录?

标签: google-cloud-platform redis google-cloud-functions


【解决方案1】:

此行为可能是由后台活动引起的。

“后台活动是在你的函数完成之后发生的任何事情 终止”

当后台活​​动干扰 Cloud Functions 中的后续调用时,可能会发生难以诊断的意外行为和错误。在函数终止后访问网络通常会导致 "ECONNRESET" 错误。

要解决此问题,请通过在日志中搜索表示调用完成的行之后的条目来确保没有后台活动。后台活动有时可能会更深地隐藏在代码中,尤其是在存在异步操作(例如回调或计时器)时。检查您的代码以确保在终止函数之前完成所有异步操作。

Source

【讨论】:

  • 我有一种预感,这可能是问题所在,而且确实直到某个时候才出现。我试图解决所有这些问题并检查日志也没有发生这样的后台活动,但仍在观察这个问题。目前,我已经删除了 Redis 的全局实例,并在需要时(在每个操作期间)创建它。我已经有 2-3 天没有观察到 ECONNRESET 错误了。
  • 我很高兴听到您能够解决您的问题。
猜你喜欢
  • 2021-10-11
  • 1970-01-01
  • 1970-01-01
  • 2019-01-21
  • 2012-11-09
  • 2020-04-02
  • 1970-01-01
  • 2017-05-10
  • 1970-01-01
相关资源
最近更新 更多