找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

720

积分

0

好友

90

主题
发表于 5 小时前 | 查看: 2| 回复: 0

现在的招聘里,往往都有一条:“熟悉 Node.js,有 BFF 开发经验者优先。”

当我们用 Node.js 写接口转发、写 SSR 时,有一个问题绕不开:状态共享

  • 用户登录了:Session 存在哪?存在 global.session 变量里?那服务器重启就没了。
  • 接口限流:限制 IP 每分钟访问 60 次。存在 Map 里?那如果你开启了 PM2 多进程,每个进程的数据是不互通的。

这时候,我们需要一个“外挂的大脑”——Redis。它是内存数据库,速度极快(微秒级),且天然支持原子操作。

今天,我们用 Redis + Node.js 解决两个真实痛点:接口限流分布式 Session

为什么要用 Redis?(给前端的解释)

你可以把 Node.js 进程想象成一个“收银员”。

  • 没有 Redis:收银员把账记在自己的脑子里(内存)。如果换班了(重启),或者开了两个收银台(多进程),账就乱了。
  • 有了 Redis:收银员把账写在身后的黑板上(Redis)。不管换几个收银员,大家看的都是同一块黑板。

核心特性:

  1. 极速:基于内存,读写几十万次/秒。
  2. 原子性:多个请求同时改一个数据,Redis 能保证排队执行,不会数据错乱。

实战场景 A:接口限流 (Rate Limiting)

需求:限制每个 IP,每 60 秒只能访问接口 10 次。

代码实现 (使用 ioredis 库):

import Redis from 'ioredis';
const redis = new Redis(); // 默认连接本地 6379

async function rateLimitMiddleware(ctx, next) {
  const ip = ctx.request.ip;
  const key = `limit:${ip}`;

  // 1. 获取当前 IP 的访问次数
  const current = await redis.get(key);

  if (current && current >= 10) {
    // 2. 超过限制,直接拒绝
    ctx.status = 429;
    ctx.body = { msg: '手速太快了,休息一下' };
    return;
  }

  // 3. 计数 +1(原子操作)
  // multi() 是事务,保证两条命令一起执行
  await redis.multi()
    .incr(key) // 自增
    .expire(key, 60) // 💡 关键:每次访问都重置/或设置过期时间?
    // 👆 这里有个坑:简单的做法是第一次设置过期,后续只 incr
    // 更好的做法是用 Lua 脚本保证原子性
    .exec();

  await next();
}

🔥 进阶:Lua 脚本 (面试杀手锏)

上面的代码在高并发下有漏洞(比如 increxpire 之间断网了)。

最完美的写法是用 Lua 脚本 将判断逻辑打包发给 Redis:

-- limit.lua
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('get', key) or "0")

if current + 1 > limit then
  return 0 -- 拒绝
else
  redis.call("INCRby", key, 1)
  redis.call("expire", key, 60)
  return 1 -- 通过
end

实战场景 B:分布式 Session

痛点:Token 无状态(JWT)虽然好,但无法“强制踢人下线”。

如果我想实现“修改密码后,所有设备强制登出”,JWT 做不到(除非换 Secret)。

解法:Redis 存 Session/Token 黑名单

// 登录成功
async function login(user) {
  const token = generateUUID();
  // 存入 Redis,30分钟过期
  // Key: session:token123  Value: userId
  await redis.set(`session:${token}`, user.id, 'EX', 1800);
  return token;
}

// 中间件校验
async function authMiddleware(ctx, next) {
  const token = ctx.headers['authorization'];

  // 去 Redis 查这张“票”还有效吗
  const userId = await redis.get(`session:${token}`);

  if (!userId) {
    ctx.status = 401;
    return;
  }

  // 续期 (活跃用户自动续时间)
  await redis.expire(`session:${token}`, 1800);

  ctx.user = { id: userId };
  await next();
}

优势:只要我在 Redis 里删掉这个 Key,用户下一秒请求就会 401,立刻下线。

2026 前端架构趋势:Serverless Redis

面试官可能会问:“前端不会运维,Redis 谁来管?”

在 2026 年,我们通常使用 UpstashVercel KV 这种 Serverless Redis

你不需要买服务器装 Redis,直接调 API 就能用,按量付费。这才是前端全栈的未来。

结语

Redis 是后端领域的“瑞士军刀”。

对于前端工程师来说,不需要精通 Redis 的持久化原理(RDB/AOF),但必须掌握它的数据结构(String, Hash, List)和应用场景(缓存、限流、消息队列)

当你开始思考“数据存在哪最安全/最快”时,你就已经脱离了单纯的 UI 开发,迈向了全栈架构。想获取更多实战经验和前沿架构知识,欢迎来 云栈社区 交流探讨。




上一篇:深入理解Java反射机制:原理、应用场景与性能考量
下一篇:X推荐算法开源解析:基于Grok架构的7步推荐流程揭秘
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-26 18:43 , Processed in 0.413184 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表