Nodejs 多服务器实例下,怎么让不同请求的 backend 共享同一个 promise
Nodejs 多服务器实例下,怎么让不同请求的 backend 共享同一个 promise
说明一下:
- 用户会按时间顺序请求 A 接口 和 B 接口
- 目前 B 接口需要请求第三方 api ,比较慢( 10 秒)
- 现在想提前到 A 接口去请求,B 接口使用
- 但是有一个问题就是不能保证 B 接口被访问的时候第三方 api 已经返回
- 我的想法就是 A 接口 share 一个 promise ,让 B 接口可以拿到并等到数据返回
但是目前并没有这样一个解决方案(因为 A 和 B 可能发生在不同服务器,所以无法直接共享文件或者内存)
所以看看大家有没有什么比较好的解决方案
(之前得到过一个方法:可以用 redis pubsub )
这。。。大概可以理解成:
在 A 时预加载 B 的数据,并在 B 被调用时使用这个数据。
你可以让客户端或者 A 所在服务调用 B 所在服务,或者通过消息队列通知给 B 所在的服务。
然后,你只要在 B 服务实现预加载或者是缓存功能就好了。
对于 B 接口不同时间的调用,也可能是由不同 server 承接
可以认为 A 和 B 在同一个 web service 中,但是这个 service 会有很多 server (或者 instance )
既然已经跨实例了,就已经脱离语言本身的范畴了,需要使用系统架构来满足需求。
你得到了 redis pub/sub 的方法,就直接用这个方法呗。
建议负载均衡层面根据 token 做 sticky session ,这样就能保证客户端短时间请求始终转发到同一个 instance 中去了。
内存里用 Map 简单缓存一下这个 Promise ,记得把时间也记录下来,定期清理掉过期的 Promise 防止泄漏
在这个基础上再实现一个 fallback 机制,极端情况下,前一个 instance 凑巧被杀死了,后一个缓存里读不到 Promise 的时候还是需要走全流程
好的,这个看起来比较不错
在 Node.js 多服务器实例(例如,通过 PM2 或 Nginx 负载均衡)环境下,确保不同请求的 backend 共享同一个 Promise,可以通过使用全局变量或外部缓存服务(如 Redis)来实现。这里提供一个使用全局变量的简单示例,但请注意,全局变量在多实例环境下并不适用,因此更推荐使用外部缓存服务。
使用全局变量(不推荐,仅适用于单实例环境)
// global.js
global.sharedPromise = null;
// server.js
const express = require('express');
const app = express();
app.get('/init', (req, res) => {
if (!global.sharedPromise) {
global.sharedPromise = new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => resolve('Data loaded'), 2000);
});
}
global.sharedPromise.then(data => res.send(data));
});
app.listen(3000, () => console.log('Server running on port 3000'));
使用 Redis(推荐)
const redis = require('redis');
const client = redis.createClient();
const loadData = async () => {
const key = 'sharedPromiseKey';
const value = await client.getAsync(key);
if (value) {
return JSON.parse(value);
} else {
const data = await new Promise((resolve, reject) => {
setTimeout(() => resolve('Data loaded'), 2000);
});
client.setex(key, 3600, JSON.stringify(data)); // 设置1小时过期时间
return data;
}
};
// 在你的请求处理逻辑中调用 loadData()
使用 Redis 可以确保在多实例环境下数据共享,并且具有持久化和过期管理的功能。