最近在做快艇骰子联机对战项目,踩了实时联机通信的不少坑,今天用通俗的思路,讲清为什么实时游戏一定要用 Redis + WebSocket,以及这套架构该怎么落地。

一、一个真实联机场景,暴露三种方案的优劣

4 人同时在线联机玩骰子,玩家 A 掷完骰子,B、C、D 需要立刻收到结果并同步界面。简单想了三种实现方式,差距一目了然:

方案 A:纯 HTTP 轮询

B 每隔 500ms 就请求一次服务器:「A 掷骰子了吗?」

  • 缺点:延迟高、服务器请求量大、客户端耗电

  • 体验:玩家操作反馈卡顿,玩起来像看 PPT

方案 B:纯 WebSocket 长连接

A 完成操作后,服务器直接通过长连接推送给其他玩家。

  • 优点:实时性拉满,毫秒级推送

  • 致命问题:无状态、无持久化,服务器一旦重启 / 崩溃,整局游戏数据直接丢失,对局无法恢复

方案 C:Redis + WebSocket 双引擎(最终最优解)

A 操作完成 → 数据写入 Redis 持久缓存 → WebSocket 广播给所有玩家

  • 服务器宕机重启:直接从 Redis 读取对局数据,继续游戏

  • 实时性、稳定性、容错性全部兼顾

这就是我项目最终落地的实时游戏双引擎架构

二、双引擎分工:黑板 + 喇叭,各司其职

用一个生活化的比喻,快速理解两者定位:

表格

组件

形象比喻

核心作用

特性

Redis

黑板

存储当前对局实时数据

内存读写、微秒级响应,宕机可恢复

WebSocket

喇叭

实时广播消息,不存数据

长连接推送,毫秒级通知,只传话

标准协作流程

plaintext

玩家执行操作 → 写入Redis固化数据 → WebSocket广播推送 → 所有玩家同步状态

核心铁则:必须先写 Redis,再发广播

如果顺序颠倒,服务器崩溃在广播前,数据就会丢失,无法回滚。

三、游戏三类数据,精准选择 Redis 结构

根据数据冷热程度,分层存储,兼顾性能与成本。

3.1 热数据:对局中高频变化,全放 Redis

游戏进行中实时变动的数据,优先 Redis,拒绝频繁查库拖慢速度:

表格

存储数据

Redis 结构

选型原因

房间基础信息

Hash

房主、在线人数、房间状态,多字段独立更新

对局进度

Hash

当前轮次、轮到哪位玩家

玩家分数

Hash

总分、上下半区得分,按需更新字段

13 项计分格子

Hash

每个格子是否填写、对应分数,字段级修改

当前骰子状态

Hash

5 个骰子点数、锁定状态,独立更新

实时排行榜

Sorted Set

自动按分数排序,查询排名 O (logN),无需手动排序

为什么不用 String / List?
  • String:修改单个字段要重写整个对象,性能浪费

  • List:有序但随机查询效率低,不适合字段式更新

  • Hash:字段独立,改哪写哪,完美适配对局动态数据

  • Sorted Set:天然排序,排行榜一键实现

3.2 温数据:Redis + MySQL 双写归档

单局游戏结束后,对局最终战绩:

  1. 读取 Redis 内完整对局数据

  2. 批量写入 MySQL 持久化

  3. 主动清理 Redis 对局缓存(也可依靠 2 小时过期自动清理)

主动清理能减少 Redis 内存占用,避免缓存堆积。

3.3 冷数据:MySQL 长期存储

历史战绩、个人对局记录、全服长期排行榜:

  • 历史对局复盘

  • 个人游玩统计

  • 全服长期排名榜单

这类数据查询频率低、要求永久存储,存入 MySQL 建立索引,保证数据可靠。

四、WebSocket 消息规范:上行下行清晰分层

把 WebSocket 消息分为三类,结构清晰,便于后端解析、前端对接。

4.1 上行消息:玩家 → 服务器

玩家主动发送的操作指令:

表格

指令

含义

服务器处理逻辑

roll

掷骰子

生成随机点数,写入 Redis,广播结果

lock

锁定骰子

更新 Redis 锁定状态,同步广播

submit

提交计分

计算得分、更新 Redis,广播并判断对局是否结束

chat

发送聊天

直接广播给房间内所有玩家

4.2 下行广播:服务器 → 房间所有玩家

对局状态变更,全员同步:

表格

指令

触发场景

dice_result

玩家掷骰子完成

lock_update

骰子锁定状态变更

score_update

玩家提交计分

next_turn

切换至下一位玩家回合

game_over

13 轮对局结束,结算战绩

player_left

玩家离线 / 退出房间

4.3 下行单发:服务器 → 单个玩家

个性化提示、错误拦截,仅发给对应玩家:

表格

指令

触发场景

error

非法操作(非自己回合、计分格子已填写)

your_turn

轮到该玩家操作,前端激活操作按钮

五、核心一致性保障,规避联机 BUG

实时联机最怕并发问题、重复操作,用 Redis 原子特性轻松解决。

5.1 防重复提交

计分格子只能填一次,利用 Redis Hash 单字段查询校验:

redis

# 查询第8格是否已填写
HGET game:10001:scores:1 8
# 返回空值:可正常提交;返回分数:拒绝重复填写

单字段查询 O (1),性能极高,杜绝重复计分。

5.2 回合安全切换

玩家同时提交操作,依靠 Redis 串行执行保证原子性:

redis

# 查询当前操作玩家
HGET game:10001 current_player_id
# 切换至下一位玩家
HSET game:10001 current_player_id 1002

Redis 天然串行处理命令,不会出现多人同时操作、回合混乱的问题。

六、项目架构演进路线,从小玩法到多人联机

从极简版到高并发版,清晰的升级路径:

表格

阶段

架构方案

适用场景

MVP 基础版

HTTP + MySQL

单机人机对战,验证核心玩法

简易联机版

HTTP + MySQL + 轮询

2–4 人小规模联机,低并发场景

实时对战版

WebSocket + Redis + MySQL

多人实时联机,高并发核心架构

大规模服务版

WebSocket + Redis 集群 + MySQL

分房间模式,支持万人同时在线

本次快艇骰子项目,直接从简易联机版升级到实时对战版,核心改动:

  1. 传统 HTTP 接口 → WebSocket 消息通信

  2. 实时数据直接查 MySQL → 优先读取 Redis

  3. 对局结束单条写入 → 批量归档 MySQL

七、一句话总结核心架构原则

Redis 是真理,WebSocket 是嘴巴,MySQL 是档案。

  • 对局进行时:状态以 Redis 为准,实时读写

  • 消息通知:靠 WebSocket 实时推送,无需客户端轮询

  • 对局结束后:存入 MySQL,永久留存可追溯

八、参考资料


本文结合实际项目落地经验,拆解了实时联机游戏的架构设计。

如果有架构疑问、代码实现细节,欢迎评论区交流~

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐