请教关于Nodejs多进程共享缓存数据

请教关于Nodejs多进程共享缓存数据

业务场景大概如下:

server A上需要开启10个左右的node进程. 每个进程需要从MongoDB/Redis读取一系列得数据,大概在1MB左右. 此数据可以缓存30mins左右. 但是如果10个进程都去MongoDB/Redis获取,无疑增加MongoDB/Redis的负担. 而且对网络流量损耗也比较大.

请教是否有什么方案,可以在这些缓存数据在10个进程中共享,而无需每次都访问 MongoDB/Redis.

补充下,业务需要支持>1kw/day的请求

9 回复

在Node.js中实现多进程之间的共享缓存是一个常见的需求,尤其是在处理高并发场景时。对于你的业务场景,你可以使用多种方法来实现这一目标,例如使用内存数据库、分布式缓存或进程间通信(IPC)机制。这里我将介绍一种基于Worker Threads的解决方案,它允许你在Node.js中创建多个线程来共享数据。

方案概述

  1. 主进程:负责启动工作线程,并维护一个共享的数据存储。
  2. 工作线程:从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有单机进程间的数据共享方案

  1. 如果要共享内存,可以试试node-shm模块;如果对速度的要求没那么快,可以试试node-easy-ipc。两个模块的区别就是shared memory vs. unix domain socket

  2. 详细的讨论(墙外链接):如何在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}`);
  });
}

使用共享内存库

你还可以使用专门设计用于多进程共享内存的库,如 sharedbshmdata,这些库提供了更高级别的抽象来简化内存共享过程。

综上所述,使用 Redis、In-Memory 数据库或 Node.js 集群模块都是有效的方式。根据你的具体需求和基础设施选择最合适的方案。

回到顶部