在本项目中, Redis 扮演着"高速缓存"和"临时状态存储"的关键角色,主要解决了 高频访问 和 数据时效性 的问题。
1. Redis 存储了什么?
根据 data_redis.hpp 的代码实现,Redis 被封装为三个核心类,分别存储了三种数据:
-
会话信息 ( Session 类)
- KV 结构 : Key: {session_id} -> Value: {user_id}
- 作用 :用于 用户鉴权 。当用户登录成功后,服务端生成一个随机的 session_id 返回给客户端,后续客户端的所有请求都会携带这个 ID。服务端通过查 Redis 里的这个 KV 对,快速反查出是哪个用户在操作,而不需要每次都去查 MySQL。
-
在线状态 ( Status 类)
- KV 结构 : Key: {user_id} -> Value: "" (空字符串)
- 作用 :用于 判断用户是否在线 。
- 场景 :
- 防止重复登录 :用户登录时,先查 Redis 里有没有这个 Key ,如果有,说明用户已经在别处登录了,拒绝本次登录请求(互斥登录)。
- 消息推送 :发送消息时,Transmite 服务会查这个 Key ,如果存在,说明用户在线,尝试通过长连接推送消息;如果不存在,说明用户离线,直接存离线消息。
-
验证码 ( Codes 类)
- KV 结构 : Key: {code_id} -> Value: {verification_code} (设置了 5 分钟过期时间)
- 作用 :用于 注册/登录验证 。
- 场景 :用户请求发送短信验证码时,生成的验证码存入 Redis 并设置 TTL(Time To Live,如 300秒)。用户提交验证码时,直接从 Redis 取出比对。
2. 为什么要用 Redis? (核心价值)
A. 极高的读写性能 (High Performance)
- 内存存储 :Redis 是基于内存的 KV 数据库,读写速度在微秒级(QPS 可达 10万+)。
- 场景匹配 :IM 系统中, "鉴权" (每个请求都要做)和 "检查在线状态"(每发一条消息都要做)是极其高频的操作。如果这些请求都打到 MySQL(磁盘 IO),数据库会瞬间崩溃。Redis 就像是 MySQL 前面的挡箭牌。
B. 临时数据的自动过期 (TTL)
- 验证码场景 :验证码通常只有 5 分钟有效期。Redis 原生支持 EXPIRE 设置过期时间,过期后自动删除。
- MySQL 的痛点 :如果用 MySQL 存验证码,不仅要多存一个 expire_time 字段,还需要启动定时任务去轮询清理过期数据,实现复杂且效率低。
C. 分布式共享存储 (Stateless)
- 微服务架构需求 :我们的 User 服务、Transmite 服务、Gateway 服务都是 无状态 的,可能部署多个实例。
- 场景 :用户在 User 服务实例 A 登录,保存了会话。当他发消息时,请求可能被路由到 Transmite 服务实例 B。
- 如果 Session 存在实例 A 的本地内存里,实例 B 就拿不到了。
- Redis 的作用 :作为一个独立的、中心化的存储,让所有微服务实例都能共享 Session 和在线状态数据。
D. 简单的 KV 模型
- 开发效率 :对于 Session ID 到 User ID 的映射,或者 User ID 是否存在的标记,Key-Value 模型是最直观、最高效的数据结构,不需要关系型数据库复杂的表结构和 SQL 语句。
总结
Redis 在本项目中主要负责"快" (缓存鉴权/状态)和 "短"(验证码生命周期管理),是保障 IM 系统高并发、低延迟的核心组件。