【问题标题】:Redis publish memory leak?Redis 发布内存泄漏?
【发布时间】:2018-12-28 17:09:59
【问题描述】:

我知道已经有很多这样的问题,但我找不到适合我的实现的问题。 我在 Node.js 环境中使用 redis,感觉 redis.publish 正在泄漏一些内存。我希望它是某种“背压”的东西,就像在这里看到的那样: Node redis publisher consuming too much memory

但据我理解:Node需要在同步上下文中释放这种压力,否则不会调用node事件循环,也不会调用GC。

我的程序是这样的:

const websocketApi = new WebsocketApi()
const currentState = {}

websocketApi.connect()
websocketApi.on('open', () => {
  channels.map((channel) => websocketApi.subscribeChannel(channel))
})

websocketApi.on('message', (message) => {
  const ob = JSON.parse(message)

  if (currentState[ob.id]) {
    currentState[ob.id] = update(currentState[ob.id], ob.data)
  } else {
    currentState[ob.id] = ob.data
  }

  const payload = {
    channel: ob.id,
    info: currentState[ob.id],
    timestamp: Date.now(),
    type: 'newData'
  }
  // when i remove this part, the memory is stable
  redisClient.publish(payload.channel, JSON.stringify(payload))
})
// to reconnect in case of error
websocketApi.on('close', () =>
  websocketApi.connect())

似乎消息之间的距离太近了,所以来不及释放redis.publish中保存的字符串。

你知道这段代码有什么问题吗?

编辑:更具体地说,当我对我的应用程序进行内存转储时,我可以观察到什么:

  • 内存由作为我的字符串化 JSON 有效负载的字符串和通过 Redis 本身发送的消息“块”组成。它们的 ref 保存在 redis 客户端中,保存在名为 chunk 的变量中。 一些字符串有效负载仍然被释放,但我创建它们的速度更快。

  • 当我不通过 Redis 发布消息时,“currentState”变量会增长到某个点,然后不再增长。它显然对 RAM 有很大的影响,但这是意料之中的。其余的都很好,应用程序稳定在 400mb 左右,它会随着 redis 发布者而爆炸(PM2 重新启动它导致它达到最大 RAM 容量)

  • 我在这里的感觉是我要求redis发布更多它可以处理的方式,而redis没有时间完成发布消息。它仍然包含所有上下文,因此它不会释放任何内容。我可能需要某种“队列”来让 redis 释放一些上下文并完成消息的发布。这真的有可能还是我疯了?

基本上,我的程序中的每个循环都是“独立的”。是否有可能拥有与循环一样多的 redis 客户端?这是一个更好的主意吗? (恕我直言,节点是单线程的,所以它不会有帮助,但它可能有助于 V8 更好地跟踪内存引用并释放内存)

【问题讨论】:

    标签: node.js redis


    【解决方案1】:

    如果客户端由于尚未连接或连接失败或连接失败而未连接,redis 客户端会缓冲命令。

    确保可以连接到 redis 服务器。确保您的程序已连接到服务器。我建议向redisClient.on('connect') 添加一个侦听器,如果没有发出,客户端永远不会连接。

    如果您已连接,客户端不应进行缓冲,但为了让问题尽快出现禁用离线队列,请将选项 enable_offline_queue: false 传递给 createClient 这将导致在未连接时尝试发送命令失败。

    您应该将错误侦听器附加到redisClientredisClient.on('error', console.error.bind(console))。这可能会产生关于客户端为何缓冲的消息。

    【讨论】:

    • 是的,我知道当前状态会增加直到某个点。当所有 ils 初始化时,更新基本上什么都不添加,只会更改一些值。真正的泄漏(恕我直言)留在 redis 发布者中:当我对我的应用程序进行一些内存转储时,我大多会找到我的 JSON stringify 有效负载的字符串,这些字符串保存在我的 redis 客户端中。之后似乎没有释放内存。当我删除发布部分时,内存会增长到一个点,然后保持相对稳定。
    • 编辑后评论:这段代码是redis客户端连接时调用的,所以可能不是这样。不仅连接了redis,而且如果我听它的频道,我可以看到它的结果。我仍然会尝试添加选项 enable_offline_queue: false 并尝试一下。我将在我原来的帖子中添加一些关于我在内存转储中可以看到的细节,希望对您有所帮助。
    • 增加 32 MB 服务器端的 Pub/Sub 客户端默认硬限制 + enable_offline_queue: false 在我的情况下似乎非常有效。我从来没有这么轻。非常感谢
    猜你喜欢
    • 2012-03-07
    • 2013-04-10
    • 1970-01-01
    • 2012-07-18
    • 2014-08-18
    • 2012-09-14
    • 2014-08-09
    • 2011-10-13
    • 2015-06-16
    相关资源
    最近更新 更多