Nodejs 使用Cluster多进程有没有办法共享内存缓存?

Nodejs 使用Cluster多进程有没有办法共享内存缓存?

**jsGen**大量使用了内存缓存,开启Cluster多进程后,各进程进程之间是独立的,这个进程更新了数据缓存,那个进程却没有更新。有什么办法让各个进程共享内存缓存?

8 回复

当使用 Node.js 的 cluster 模块来创建多进程应用时,每个工作进程(worker)都有自己独立的内存空间。这意味着一个进程中的内存缓存不会自动被其他进程访问到。为了解决这个问题,我们需要找到一种方法让这些进程共享内存缓存。

一种常见的解决方案是使用分布式缓存系统,比如 Redis 或者 Memcached。这些系统允许不同的进程通过网络访问相同的缓存数据。以下是一个使用 Redis 实现共享内存缓存的例子:

  1. 首先,确保你已经在你的机器上安装了 Redis。
  2. 安装 Redis 客户端库,例如 ioredis:
npm install ioredis
  1. 在你的应用中设置一个 Redis 客户端,并在需要的地方使用它:
const { Worker, isMainThread, createWorkerData } = require('worker_threads');
const Redis = require('ioredis');

// 创建 Redis 客户端
const redisClient = new Redis();

if (isMainThread) {
    const cluster = require('cluster');
    const numCPUs = require('os').cpus().length;

    if (cluster.isMaster) {
        console.log(`Master process running on ${process.pid}`);

        for (let i = 0; i < numCPUs; i++) {
            cluster.fork();
        }

        // 监听子进程退出事件
        cluster.on('exit', (worker, code, signal) => {
            console.log(`Worker ${worker.process.pid} died`);
        });
    } else {
        // 子进程逻辑
        console.log(`Worker process running on ${process.pid}`);
        workerThread();
    }
} else {
    // 子进程使用的线程函数
    async function workerThread() {
        // 更新缓存
        await redisClient.set('key', 'value');
        console.log(`Updated cache in worker ${process.pid}`);

        // 读取缓存
        const value = await redisClient.get('key');
        console.log(`Read cache in worker ${process.pid}: ${value}`);
    }
}

在这个例子中,我们使用了 ioredis 库来连接 Redis 服务器,并在主进程中启动多个子进程。每个子进程都可以通过 Redis 来读写缓存数据,从而实现了跨进程的内存缓存共享。

这种方法的优点是简单且可靠,但需要注意的是,每次读写缓存都会产生网络开销。如果性能成为瓶颈,可以考虑其他更高效的方法,如内存映射文件或自定义的 IPC(进程间通信)机制。


有办法:不用Cluster

仅提供一个思路:在master进程初始化jsGen,worker进程通过message事件向master进程申请jsGen的api访问。写了个简单的例子,实际操作起来还要适当封装api,序列化参数等等

var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
    var info={counter:1}
    for (var i = 0; i < numCPUs; i++) {
        var worker=cluster.fork();
        worker.on('message',function(msg){
            info.counter++;
            this.send(info);
        }.bind(worker));
    }
} else {
    http.createServer(function(req, res) {
        process.send('getInfo');
        process.once('message',function(info){
            res.writeHead(200);
            res.end(info.counter+":hello world\n");
        });
    }).listen(8080);
}

个人是倾向于不用cluster的,非cpu密集运算的应用,多进程对nodejs性能提升甚微;退一步讲,就算要执行cpu密集运算,也可以通过child_process手工fork一个进程来单独执行。

主要是觉得message事件通信读写效率可能也不是很高。

看来要不放弃cluster,要不就是用Redis这样的内存数据库来代替内存缓存了,效率也会低很多。

最好还是Node.js原生实现可在各进程间共享的Buffer

单进程占用太多内存会影响性能吧。 缓存还是使用专门的缓存服务器吧

嗯,看来会要动大手术

redis当缓存?

当使用 Node.js 的 Cluster 模块时,主进程和工作进程之间默认是隔离的,每个进程都有自己的内存空间。这意味着一个进程中的内存缓存无法直接被其他进程访问。不过,可以通过一些方法实现进程间的共享内存缓存。

一种解决方案是使用第三方库,如 memory-cache 结合 redis 或者 memcached 来实现跨进程的内存缓存。这里以 redis 为例,展示如何设置一个共享内存缓存:

示例代码

首先安装必要的库:

npm install redis memory-cache

然后在应用中配置缓存:

const redis = require('redis');
const MemoryCache = require('memory-cache');

// 创建 Redis 客户端
const client = redis.createClient();

client.on('error', function (err) {
    console.log('Redis client error: ' + err);
});

function getFromCache(key, callback) {
    // 先从本地内存缓存获取
    let value = MemoryCache.get(key);
    if (value !== null) {
        return callback(null, value);
    }

    // 如果本地缓存没有,则从 Redis 获取
    client.get(key, (err, reply) => {
        if (err) return callback(err);
        const data = JSON.parse(reply);
        MemoryCache.put(key, data); // 将数据存储到本地内存缓存
        callback(null, data);
    });
}

function setToCache(key, data, ttl) {
    client.set(key, JSON.stringify(data), 'EX', ttl, () => {
        // 设置成功后,同步更新本地内存缓存
        MemoryCache.put(key, data, ttl * 1000);
    });
}

解释

  • 使用 redis 作为共享缓存服务器,所有工作进程都连接到同一个 Redis 实例。
  • MemoryCache 用于在每个工作进程中提供快速的本地缓存访问。
  • 当从缓存获取数据时,优先检查本地内存缓存;如果未找到,则查询 Redis 并将结果存储到本地内存缓存中。
  • 当向缓存写入数据时,同时更新 Redis 和本地内存缓存。

通过这种方式,你可以确保即使在启用 Cluster 模式下,所有工作进程也能访问到最新的缓存数据。

回到顶部