请教关于Nodejs多进程共享缓存数据
请教关于Nodejs多进程共享缓存数据
业务场景大概如下:
server A上需要开启10个左右的node进程. 每个进程需要从MongoDB/Redis读取一系列得数据,大概在1MB左右. 此数据可以缓存30mins左右. 但是如果10个进程都去MongoDB/Redis获取,无疑增加MongoDB/Redis的负担. 而且对网络流量损耗也比较大.
请教是否有什么方案,可以在这些缓存数据在10个进程中共享,而无需每次都访问 MongoDB/Redis.
补充下,业务需要支持>1kw/day的请求
在Node.js中实现多进程之间的共享缓存是一个常见的需求,尤其是在处理高并发场景时。对于你的业务场景,你可以使用多种方法来实现这一目标,例如使用内存数据库、分布式缓存或进程间通信(IPC)机制。这里我将介绍一种基于Worker Threads
的解决方案,它允许你在Node.js中创建多个线程来共享数据。
方案概述
- 主进程:负责启动工作线程,并维护一个共享的数据存储。
- 工作线程:从MongoDB/Redis加载数据到主进程的共享存储中,然后直接从该存储中获取数据。
示例代码
首先,确保你使用的是Node.js版本10或更高版本,因为Worker Threads
是在Node.js v10.5.0中引入的。
主进程 (main.js
)
const { Worker } = require('worker_threads');
// 创建共享对象
let sharedCache = {};
function startWorker() {
const worker = new Worker(__filename, {
workerData: sharedCache // 将共享对象传递给工作线程
});
worker.on('message', (data) => {
console.log(`Received data from worker: ${data}`);
});
worker.on('exit', () => {
console.log('Worker exited');
});
}
for (let i = 0; i < 10; i++) {
startWorker();
}
工作线程 (main.js
)
const { isMainThread, parentPort, workerData } = require('worker_threads');
if (isMainThread) {
throw new Error('This script should be run with a Worker object.');
}
// 使用传递过来的共享对象
let sharedCache = workerData;
parentPort.on('message', async (message) => {
if (message === 'load-data') {
try {
// 模拟从MongoDB/Redis加载数据
let data = await loadDataFromDatabase();
sharedCache[data.key] = data.value;
parentPort.postMessage('Data loaded into cache');
} catch (error) {
parentPort.postMessage(`Error loading data: ${error.message}`);
}
} else if (message === 'get-data') {
parentPort.postMessage(sharedCache[message]);
}
});
解释
- 主进程:负责创建多个工作线程,并通过
workerData
传递共享对象。每个工作线程都会接收并更新这个共享对象。 - 工作线程:从主线程接收消息,根据消息类型执行不同的操作。如果消息是
load-data
,则模拟从数据库加载数据,并将其存储在共享对象中;如果是get-data
,则从共享对象中获取数据并返回。
这种方法减少了对MongoDB/Redis的频繁访问,减轻了数据库的压力,同时也降低了网络流量。不过需要注意的是,由于所有的数据都存储在内存中,这可能会受到单个节点内存限制的影响。如果你的应用需要更高的可用性和可扩展性,考虑使用分布式缓存系统如Redis Cluster。
你要缓存的数据量并不大,每个进程各自缓存一份自己的数据就可以。
抱歉,忘记说明了,我在原文补充了下,需要支撑最少>1kw/day的请求,如果每个进程都缓存一份会导致内存占用过大.所以才提出了这个问题,请教关于进程间的共享缓存
多进程共享缓存或多机共享缓存,无疑需要使用redis之类的内存缓存。 jsGen以前使用Node.js内存缓存数据,不能开多进程,现在全改成redis缓存了,从而可以多进程或多机运行jsGen了。 redis是异步驱动,写起代码来还是有点啰嗦,不过对于小数据缓存,还是有办法实现一个同步的redis缓存。jsGen的config数据就是用的这种redis同步缓存,稍后出文讲讲这个实现。
其实我需要寻求的是一个单机的,进程中数据的共享方案. 使用外部缓存(redis/memcached/mongo等等都可以胜任)最大的问题,是需要多一次网络传输. 性能上损耗还是比较大的,哪怕是异步的方式.
我想尽量避免开这些损耗,想了解是否nodejs有单机进程间的数据共享方案
-
如果要共享内存,可以试试node-shm模块;如果对速度的要求没那么快,可以试试node-easy-ipc。两个模块的区别就是shared memory vs. unix domain socket。
-
详细的讨论(墙外链接):如何在node.js中共享内存
俺是新手,做个假设,不知可否。如果数据不大,当子进程A被分配去读取数据时,先判断内存中是否已经存在这些数据,如果不存在则读取数据,然后将读取到的数据传递给主进程,主进程将其保存在内存中,以便后面的子进程进行前面说的判断。
同样遇到的了这个问题 make
为了减少对 MongoDB/Redis 的访问频率并提高性能,可以考虑使用内存中的缓存机制来共享数据。常见的解决方案包括使用 In-Memory 数据库或共享内存库。以下是几种可能的方法:
使用 Redis
尽管你提到希望避免频繁访问 Redis,但是你可以利用 Redis 的发布/订阅功能或者键过期事件来实现各个进程间的通信。这样可以将数据存储在 Redis 中,但并不频繁地访问它。
const redis = require('ioredis');
const redisClient = new redis();
// 存储数据到 Redis
async function storeData(key, data) {
await redisClient.set(key, JSON.stringify(data));
}
// 从 Redis 获取数据
async function getData(key) {
const cachedData = await redisClient.get(key);
return cachedData ? JSON.parse(cachedData) : null;
}
使用 In-Memory 数据库(如 SQLite 或 LevelDB)
你也可以选择使用轻量级的本地数据库来存储共享数据,例如 SQLite 或 LevelDB。这能显著降低对外部存储系统的依赖。
使用 Node.js 内置模块 cluster
如果你想要在同一台机器上管理多个 Node.js 进程,并且它们能够共享一些资源,可以使用 cluster
模块。通过使用共享内存或进程间通信 (IPC),可以在不同子进程中同步数据。
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
// Example IPC communication
setInterval(() => {
cluster.workers[0].send({ message: 'Hello from Master' });
}, 5000);
} else {
process.on('message', (msg) => {
console.log(`Worker received message: ${msg.message}`);
});
}
使用共享内存库
你还可以使用专门设计用于多进程共享内存的库,如 sharedb
或 shmdata
,这些库提供了更高级别的抽象来简化内存共享过程。
综上所述,使用 Redis、In-Memory 数据库或 Node.js 集群模块都是有效的方式。根据你的具体需求和基础设施选择最合适的方案。