怎么用GlobalData实现数据共享_分布式开发技巧【技巧】

2次阅读

node.js 多进程间无法共享全局数据,global/require.cache 仅限单进程内有效;跨进程应使用 redis 等外部存储,避免文件、sqlite 或轮询等不可靠方式。

怎么用GlobalData实现数据共享_分布式开发技巧【技巧】

GlobalData 在 Node.js 多进程间不共享

Node.js 的 GlobalData 并不是标准 API,也没有内置的 GlobalData 对象。你实际遇到的,很可能是某个框架(比如 NestJS 插件)、自研模块、或误把 global / globalThis 当成了跨进程共享机制。真正的多进程(如 cluster 模式或多个 worker_threads)之间,内存完全隔离,global 上挂的变量只在当前进程内有效。

常见错误现象:
– 主进程设置 global.userData = { id: 1 },子进程读出来是 undefined
– 用 cluster.fork() 启动多个 worker,彼此修改同名全局变量互不影响

  • 别依赖 global 或任何 JS 全局对象做分布式状态同步
  • 如果只是单进程内模块间共享,用 ES 模块导出/导入更安全,比挂 global 清晰且可 tree-shake
  • 真要跨进程通信,优先选 process.send() + message 事件cluster 场景),或 WorkerpostMessage()

替代方案:Redis 是最稳妥的 GlobalData“模拟器”

所谓“分布式 GlobalData”,本质是需要一个外部、可并发读写的键值存储。Redis 不仅快,还天然支持过期、原子操作、发布订阅——比自己用文件或 http 服务靠谱得多。

使用场景:
– 用户登录态在多个 Node 实例间同步
– 计数器(如限流计数)需全集群一致
– 配置热更新后通知所有工作进程

  • 避免用 redis.set('config', json.stringify(obj)) 然后各进程轮询 —— 这是低效 polling,改用 PUBLISH config:update + SUBSCRIBE
  • 连接 Redis 时务必复用客户端实例,不要每个请求都 createClient(),否则快速耗尽 socket
  • 对简单共享数据,用 SET key value EX 300(5 分钟过期)比长期驻留更安全,防脏数据

为什么不用 SQLite 做分布式 GlobalData?

SQLite 文件锁在 NFS 或容器挂载卷上行为不可靠,SQLITE_BUSY 错误会频繁出现,尤其写密集场景。它适合单机工具类应用,不适合服务间共享状态。

常见错误现象:
docker 多副本挂同一个 host 路径,一个实例写入时另一个报 database is locked
PRAGMA journal_mode = WAL 也不能解决跨主机竞争

  • 即使本地测试能跑通,上线到 kubernetes 或 ECS 多可用区时必然出问题
  • 如果硬要用文件存储,至少选 etcdconsul 这类专为分布式协调设计的组件,而非数据库
  • 临时调试可以 fs.writeFileSync('./shared.json', JSON.stringify(data)),但上线前必须替换掉

Node.js 里真正能“近似 GlobalData”的只有 module.exports 缓存

ES 模块和 CommonJS 的模块缓存机制(require.cache / import.meta.url 缓存)是单进程内最接近“全局共享数据”的可靠方式——只要路径相同,多次 require()import 拿到的是同一份对象引用。

示例:
shared.js 导出一个对象:

module.exports = { count: 0, inc() { this.count++ } };

两个不同文件都 const s = require('./shared'),调用 s.inc() 会真实共享状态

  • 这仅限同一进程,不能跨 child_processworker_threads
  • 注意循环引用风险:A require B,B 又 require A,可能导致部分属性未初始化
  • 如果共享的是配置,建议导出 getter 函数而非裸对象,便于后期接入远程拉取逻辑

跨进程共享这事,没有银弹。选 Redis 不是因为它多酷,而是它把并发、持久、通知这些事都做对了。其它方案要么假共享,要么埋雷等上线炸。

text=ZqhQzanResources