我知道已经有很多这样的问题,但是我找不到适合我的实现的问题。 我在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更好地跟踪内存引用并释放内存)
答案 0 :(得分:1)
如果未连接客户端(因为尚未连接或客户端连接失败或无法连接),则redis客户端会缓冲命令。
确保您可以连接到Redis服务器。确保您的程序已连接到服务器。如果不发出客户端从未连接的客户端,我建议向redisClient.on('connect')
添加一个监听器。
如果已连接,则客户端不应该正在缓冲,但是要使问题尽快出现,请禁用脱机队列,将选项enable_offline_queue: false
传递给createClient
,这将导致尝试在未连接时发送命令连接失败。
您应该将错误侦听器附加到redisClient
:redisClient.on('error', console.error.bind(console))
上。这可能会显示一条消息,说明为什么客户端正在缓冲。