我知道已经有很多这样的问题,但我没有找到适合我实现的问题。 我在 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 本身发送的消息“ block ”。他们的 ref 被保存在 redis 客户端内部,称为 chunk 的变量中。 一些字符串有效负载仍在发布,但我创建它们的速度更快。
当我不通过 Redis 发布消息时,“currentState”变量增长到一个点,然后不再增长。它显然对 RAM 有很大的影响,但这是意料之中的。其余的很好,应用程序稳定在 400mb 左右,它在 redis 发布者中爆炸(PM2 重新启动它导致它达到最大 RAM 容量)
我的感觉是,我要求 Redis 发布更多它可以处理的方式,而 Redis 没有时间完成发布消息。它仍然拥有所有的上下文,所以它不会释放任何东西。我可能需要某种“队列”来让 Redis 释放一些上下文并完成消息的发布。这真的有可能还是我疯了?
基本上,我程序中的每个循环都是“独立的”。是否可以拥有与我拥有的循环一样多的 redis 客户端?这是一个更好的主意吗? (恕我直言, Node 是单线程的,所以它无济于事,但它可能有助于 V8 更好地跟踪内存引用和释放内存)
最佳答案
如果客户端因为尚未连接或连接失败或连接失败而未连接,则 redis 客户端会缓冲命令。
确保您可以连接到redis 服务器。确保您的程序已连接到服务器。我建议向 redisClient.on('connect')
添加一个监听器,如果它没有发出,则客户端从未连接。
如果您已连接,客户端不应缓冲,但要使问题尽快出现,请禁用离线队列,将选项 enable_offline_queue: false
传递给 createClient
这将导致在未连接时尝试发送命令失败。
您应该将错误监听器附加到 redisClient
:redisClient.on('error', console.error.bind(console))
。这可能会产生一条消息,说明客户端缓冲的原因。
关于node.js - Redis发布内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53943451/