讲师中心 微信公众号
AI工具推荐 视频效率加速

怎样在Node.js中防止Redis缓存击穿_使用Promise与锁机制

星芳吖_2598

星芳吖_2598

发布时间:2026-07-09 10:56:15

|

489人浏览过

|

来源于php中文网

原创

Redis分布式锁需满足互斥性、安全性、超时释放、原子性及可重入性;核心用SET key value NX EX t原子加锁,Lua脚本校验值后删锁防误删,Redisson提供自动续期等高级特性。

怎样在node.js中防止redis缓存击穿_使用promise与锁机制

缓存未命中时多个请求同时查库,怎么只让一个去执行?

核心是“请求排队”:当 redis.get(key) 返回 null,不能直接放行所有请求去查数据库,必须用某种机制让其余请求暂停,等第一个请求完成并写入缓存后,再统一返回结果。

Node.js 单线程特性反而帮了忙——不需要处理多线程锁的可见性问题,但得小心 Promise 状态共享和竞态。常见错误是每个请求都新建一个 Promise 去查库,导致 10 个并发请求各自触发一次 DB 查询。

  • 用一个全局 Map 存储正在重建缓存的 Promise:pendingPromises.set(key, promise)
  • 后续同 key 请求先查这个 Map,命中就直接 await 它,不新建 Promise
  • Promise resolve 后立即 pendingPromises.delete(key),避免内存泄漏
  • 务必加 catch 并主动 delete,否则失败后该 key 会永远卡在 pending 状态

用 Redis SETNX 实现分布式锁,为什么不能只靠它?

单纯用 SET key value NX EX 30 加锁,在 Node.js 中容易漏掉两个关键环节:锁释放时机不可控、锁被其他实例误删。比如请求 A 拿到锁,查库花了 35 秒,锁自动过期;此时请求 B 成功加锁,而请求 A 在写缓存时仍会执行 DEL key,把 B 的锁干掉了。

安全做法是用 Lua 脚本保证“判断+删除”原子性,且锁值必须是唯一标识(如 uuidv4()),不能写死。

  • 加锁:用 client.set(key, randomValue, 'NX', 'EX', 30),不是 SETNX 命令(ioredis 已弃用)
  • 解锁:必须用 Lua 脚本,检查 value 相等才删,示例:if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end
  • 别在 try/finally 里无条件 DEL,那是典型误删来源
  • 锁超时时间要明显大于 DB 查询 + 缓存写入耗时,建议设为后者 2–3 倍

为什么用 EventEmitter 实现等待比纯 Promise Map 更稳?

当服务重启或进程崩溃,Map 里的 pending Promise 全丢,新请求又得重来一遍;而 EventEmitter 的 once 是事件驱动模型,天然支持“发布-订阅”,只要事件名一致,哪怕中间有延迟,监听者也能收到通知。

Rydberg Agent Node
Rydberg Agent Node

使用一条命令部署ProbeChain Rydberg测试网代理节点。自动注册为Agent(NodeType=1),免gas,支持macOS/Linux/Windows。触发词:/r

下载

不过要注意:事件名必须带业务上下文,比如 cache:rebuild:user:123,不能只用 rebuild,否则不同 key 的重建会互相干扰。

  • 首次请求触发 emitter.emit(key, result),之后所有 emitter.once(key) 都能拿到结果
  • 必须在 Promise resolve 后立刻 emit,reject 时也 emit(传 error 或 null)
  • Node.js 的 EventEmitter 默认最大监听数 10,高并发下需调用 emitter.setMaxListeners(0)
  • 不用手动清理监听器,once 自动移除,比 Map 的 delete 更省心

本地内存锁(Mutex)在集群部署下完全失效

如果你用 const mutex = new Mutex() 这类纯内存锁,它只在当前 Node 进程内有效。一旦部署多实例(PM2 cluster、K8s 多 Pod),每个实例都有自己的 mutex 实例,根本起不到互斥作用——10 个实例各放行一个请求,还是 10 次 DB 查询。

真正的分布式场景,锁必须落在共享存储上。Redis 是最直接选择,但要注意:单点 Redis 故障会导致全部请求阻塞,生产环境建议搭配降级策略(如允许少量击穿,或 fallback 到本地 LRU 缓存)。

  • 不要在开发环境用内存锁测试,然后上线换 Redis 锁——行为差异太大
  • ioredis 的 lock 插件(如 redlock)比手写 SETNX 更可靠,内置租约续期和故障转移逻辑
  • 如果 Redis 不可用,mutex 应快速失败(比如 acquire(timeout=100)),而不是无限等待
  • 锁粒度宁细勿粗,按业务 key 分,别用一个全局锁锁住所有缓存重建

真正难的不是写对一行 SETNX,而是想清楚“谁在等谁”“等多久”“等不到怎么办”。很多线上事故,都出在锁释放逻辑没覆盖异常分支,或者降级开关压根没测过。

热门AI工具

更多
UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

LibLibAI
LibLibAI Hot

一款AI视频创作工具,主要用于国内领先的AI创意平台,以海量模型、低门槛操作与“创作-分享-商业化”生态,让小白与专业创作者都能高效实现图文乃至视频创意表达,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

相关专题

更多
node.js调试
node.js调试

node.js调试可以使用console.log()输出调试信息、断点调试和第三方调试工具。详细介绍:1、console.log()输出调试信息,通过在代码中插入console.log()语句,开发人员可以在控制台输出变量的值、函数的执行结果等信息,以便观察代码的执行流程和状态;2、断点调试,可以在代码中设置断点,以便在特定位置暂停代码的执行,观察变量的值和执行流程等。

9689

2023.09.19

JavaScript 全栈开发基础(Node.js + 前端)
JavaScript 全栈开发基础(Node.js + 前端)

本专题系统介绍 JavaScript 在全栈开发中的核心知识结构,涵盖 Node.js 基础、Express/Koa 接口构建、前端交互设计、模块化与包管理、数据库连接、前后端数据通信与部署流程。通过完整项目示例,帮助学习者掌握从浏览器到服务器的一体化开发能力,实现真正意义上的全栈入门。

414

2025.11.26

Node.js后端开发与Express框架实践
Node.js后端开发与Express框架实践

本专题针对初中级 Node.js 开发者,系统讲解如何使用 Express 框架搭建高性能后端服务。内容包括路由设计、中间件开发、数据库集成、API 安全与异常处理,以及 RESTful API 的设计与优化。通过实际项目演示,帮助开发者快速掌握 Node.js 后端开发流程。

741

2026.02.10

JavaScript Node.js流处理与高效数据管道构建实践
JavaScript Node.js流处理与高效数据管道构建实践

本专题聚焦 Node.js 在大规模数据处理场景中的应用,系统讲解 Stream 流机制、背压控制、管道(Pipe)处理以及文件与网络数据流的高效传输方式。内容包括可读流、可写流、双工流与转换流的实现原理,并结合实际案例构建高性能数据处理管道,帮助开发者提升数据处理效率与系统吞吐能力。

304

2026.04.07

TypeScript Node.js 全栈工程化与Monorepo架构实践
TypeScript Node.js 全栈工程化与Monorepo架构实践

本专题围绕 TypeScript 在 Node.js 全栈开发中的工程化实践展开,系统讲解 Monorepo 架构设计、包管理策略、模块复用机制以及服务端与前端统一类型系统的构建方法。通过真实项目案例,帮助开发者提升大型全栈项目的可维护性与协作效率。

518

2026.06.16

promise的用法
promise的用法

“promise” 是一种用于处理异步操作的编程概念,它可以用来表示一个异步操作的最终结果。Promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。Promise的用法主要包括构造函数、实例方法(then、catch、finally)和状态转换。

4200

2023.10.12

html文本框类型介绍
html文本框类型介绍

html文本框类型有单行文本框、密码文本框、数字文本框、日期文本框、时间文本框、文件上传文本框、多行文本框等等。详细介绍:1、单行文本框是最常见的文本框类型,用于接受单行文本输入,用户可以在文本框中输入任意文本,例如用户名、密码、电子邮件地址等;2、密码文本框用于接受密码输入,用户在输入密码时,文本框中的内容会被隐藏,以保护用户的隐私;3、数字文本框等等。

3523

2023.10.12

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

4289

2023.11.02

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

80

2026.09.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WebStorm 官方调试文档
WebStorm 官方调试文档

共0课时 | 0人学习

RabbitMQ 教程手册
RabbitMQ 教程手册

共0课时 | 0人学习

Node.js 教程
Node.js 教程

共57课时 | 25.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn