Nodejs 多服务器实例下,怎么让不同请求的 backend 共享同一个 promise

发布于 1周前 作者 ionicwang 来自 nodejs/Nestjs

Nodejs 多服务器实例下,怎么让不同请求的 backend 共享同一个 promise
说明一下:
- 用户会按时间顺序请求 A 接口 和 B 接口
- 目前 B 接口需要请求第三方 api ,比较慢( 10 秒)
- 现在想提前到 A 接口去请求,B 接口使用
- 但是有一个问题就是不能保证 B 接口被访问的时候第三方 api 已经返回
- 我的想法就是 A 接口 share 一个 promise ,让 B 接口可以拿到并等到数据返回

但是目前并没有这样一个解决方案(因为 A 和 B 可能发生在不同服务器,所以无法直接共享文件或者内存)
所以看看大家有没有什么比较好的解决方案

(之前得到过一个方法:可以用 redis pubsub )


8 回复

这。。。大概可以理解成:
在 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 可以确保在多实例环境下数据共享,并且具有持久化和过期管理的功能。

回到顶部