使用 AWS Serverless 架构构建新扑克变体
Source: Dev.to
设计前的规划
在编写任何代码之前,我先制作了一份 36 页的低层设计(LLD)文档。LLD 迫使我在一开始就考虑每一个边缘情况、状态转换和故障模式——这正是生产系统的构建方式。
按数字统计
- 7 个 AWS 服务
- 8 个 DynamoDB 表
- 36 页 LLD
- 0 台服务器需要管理
架构
Point Game 是一个完全无服务器、事件驱动的系统。客户端使用 REST API 进行账户和桌面操作,使用 WebSocket 进行实时游戏。
基础设施概览
| 组件 | 技术 |
|---|---|
| CDN 与静态资源 | CloudFront + S3 |
| API 层 | API Gateway(REST + WebSocket) |
| 计算 | AWS Lambda |
| 数据库 | DynamoDB |
| 认证 | Cognito |
| 调度 | EventBridge |
关键洞察:DynamoDB 是唯一的真相来源。所有游戏状态、操作日志和连接映射都存放在 DynamoDB 中。Lambda 函数是无状态的——它们读取状态、处理操作、写入状态并进行广播。这使得系统能够水平扩展并对故障具有弹性。
Client Action → API Gateway → Lambda → DynamoDB → Broadcast
数据模型
| 表格 | 用途 |
|---|---|
| Game State | 当前手牌状态、座位、奖池、棋盘 |
| Action Log | 只追加的每个操作记录 |
| Hand Snapshots | 手牌结束时的状态,用于回放/审计 |
| Connection Store | WebSocket ID → 玩家映射 |
| Turn Timers | 计划的超时跟踪 |
| Inter‑Round Queue | 待处理的加入/离开/配置操作 |
| Users | 账户数据和余额 |
| Ledger | 买入/兑现历史 |
困难问题
Challenge 1: Optimistic Concurrency Control
同时的玩家操作可能会破坏状态。我实现了sequence‑based versioning:每次状态变更都包含一个预期的序列号。如果序列号不匹配,写入失败,客户端会重新同步,从而消除竞争条件和丢失的操作。
Challenge 2: Turn Timer System
Lambda 函数无法“等待”。我使用了EventBridge scheduled events:当回合开始时,调度一个带有计时序列的未来事件。超时的 Lambda 检查该序列是否仍然是当前的;如果玩家已经行动,则忽略计时器,否则玩家会被自动弃牌。
Challenge 3: Privacy‑Filtered Broadcasting
每个玩家必须看到个性化的视图(自己的底牌与对手的背面牌)。广播器加载权威状态,针对每个接收者过滤掉私密信息,并发送定制的 WebSocket 消息。
Challenge 4: Inter‑Round Action Queue
玩家可能在一手牌进行中加入、离开或更改设置。这些操作会被存入队列,并在between hands之间原子化处理,既保持游戏状态的一致性,又兼顾真实玩家的行为。
Challenge 5: Complex Game Rules
点数游戏包含许多边缘情况——尤其是涉及边池、分池和多位赢家的摊牌逻辑。将这些规则转化为可靠的代码需要在并发负载下进行细致的状态管理,且全部在没有专用服务器的情况下完成。
为什么这超出行业标准
- 一个 实时分布式系统,使用 WebSocket 状态同步
- 事件驱动架构,配合计划触发和异步处理
- 生产级一致性保证,通过乐观并发实现
- 领域特定游戏逻辑,处理多个同时玩家和游戏的复杂状态机
亲身体验
玩游戏:
加入社区: