在无状态REST API中使用Redis存储用户相关数据是否属于错误方案?
关于Redis存储用户Socket映射是否会让REST API变为有状态的解答
将user->socketID的映射存储在Redis中,不会让你的REST API变成有状态服务。
服务是否有状态的核心判定标准是:服务实例本身是否存储了请求会话相关的专属状态数据。如果同一个用户的同一请求,发送到不同的服务实例会得到不同的处理结果,说明服务是有状态的;反之如果所有服务实例的处理逻辑完全不依赖自身存储的专属会话数据,所有状态都从外部共享存储获取,那服务就是无状态的。
你最初用全局变量存储映射的方案之所以会导致服务有状态,是因为这部分数据只存在单个Node.js进程的本地内存中:
- 如果你部署多个服务实例做负载均衡,用户请求如果被分配到没有存储对应映射的实例,就无法正常发送消息
- 单个实例重启后,本地存储的所有映射数据会全部丢失,用户连接状态直接失效
Redis属于独立的外部共享存储层,所有你的Node.js服务实例都会连接同一个Redis服务(或集群)查询映射数据:
- 无论用户请求被负载均衡分配到哪个服务实例,都能从统一的Redis中查询到一致的user->socketID映射,处理结果完全一致
- 你的服务实例本身不存储任何会话相关的状态数据,实例扩容、重启都不会影响用户连接状态,完全符合无状态服务的特征
实践建议
- 可以给存储的user->socketID键设置合理的过期时间,避免socket异常断开没有主动删除键导致的脏数据
- 如果支持用户多端同时登录,可以用Redis的
Set类型存储同一个用户对应的多个socketID,消息推送时遍历发送即可
内容的提问来源于stack exchange,提问作者Kritidipto Ghosh
相关产品推荐
相关产品推荐

