Redis发布内存泄漏?

时间:2018-12-27 10:26:14

标签: node.js redis

我知道已经有很多这样的问题,但是我找不到适合我的实现的问题。 我在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中保留的字符串。

您是否知道这段代码有什么问题?

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

  • 内存充满了字符串(这些字符串是我的Stringified JSON有效负载)和通过Redis本身发送的消息的“块”。他们的引用被男子气概地保存在redis客户端内部的称为块的变量中。 某些字符串有效载荷仍被释放,但是我创建它们的方式更快。<​​/ p>

  • 当我不通过Redis发布消息时,“ currentState”变量会一直增长到某个点,然后不再增长。显然,它对RAM有很大的影响,但这是可以预期的。其余的很好,应用程序稳定在400mb左右,并且在redis发布器爆炸时(PM2重新启动,因为它达到最大RAM容量)而爆炸

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

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

1 个答案:

答案 0 :(得分:1)

如果未连接客户端(因为尚未连接或客户端连接失败或无法连接),则redis客户端会缓冲命令。

确保您可以连接到Redis服务器。确保您的程序已连接到服务器。如果不发出客户端从未连接的客户端,我建议向redisClient.on('connect')添加一个监听器。

如果已连接,则客户端不应该正在缓冲,但是要使问题尽快出现,请禁用脱机队列,将选项enable_offline_queue: false传递给createClient,这将导致尝试在未连接时发送命令连接失败。

您应该将错误侦听器附加到redisClientredisClient.on('error', console.error.bind(console))上。这可能会显示一条消息,说明为什么客户端正在缓冲。