主题: 从实时交互扩展到长期运行、异步事件与内容生态。
目标: 支持定时任务、经济循环、公会系统、UGC 平台化接入。
| 编号 | 原型 | 功能重点 | 核心验证目标 |
|---|---|---|---|
| 21 | 异步远征 | 延迟任务 | DelayQueue、幂等结算 |
| 22 | 公会建设 | 多层权限 | 角色体系、任务贡献 |
| 23 | 跨服战 | 分布式通信 | 全局身份映射、最终一致性 |
| 24 | 动态赛事 | 赛程与积分 | Job + FSM、自动调度 |
| 25 | 市场系统 | 自由经济 | 撮合成交、供需平衡 |
| 26 | 合作解谜 | 并发协作 | 时间窗判定、锁步同步 |
| 27 | 协作建造 | 实时建造 | CRDT、区域锁与快照 |
| 28 | 副本脚本系统 | 可编程副本 | Lua /JS 沙箱、触发器 |
| 29 | UGC 创作 | 玩家内容生态 | 审核、推荐、内容版本化 |
| 30 | 平台大厅 | 多游戏接入 | 单点登录、游戏实例路由 |
阶段目标:
- 验证 异步作业系统与延迟结算
- 构建 公会 / 区服 / 跨服通信模型
- 实现 可热更新的脚本副本框架
- 搭建 UGC 上传 / 审核 / 推荐管线
模块架构
graph TD
A["Scheduler Service"] --> B["Job Queue"]
B --> C["Game Logic"]
C --> D["Economy Service"]
C --> E["Guild Service"]
C --> F["UGC API"]
模块接口定义
| 模块 | 接口 | 说明 |
|---|---|---|
| Scheduler | /enqueueJob /poll | 派发/消费任务 |
| Economy | /order/buy /order/sell | 市场买卖撮合 |
| Guild | /contribute /upgrade | 公会经验与等级 |
| UGC | /upload /review /publish | 内容上传与审核 |
验证流程(以 #25 市场系统为例)
sequenceDiagram
Player->>Economy: PlaceOrder(Buy)
Economy->>JobQueue: MatchTask
JobQueue->>Economy: Matched(Seller)
Economy->>DB: Atomic Commit
DB->>Player: Success + Receipt
指标体系
| 模块 | 指标 |
|---|---|
| Scheduler | 延迟任务执行时间 / 失败重试率 |
| Market | 成交率 / 市场深度 / 滑点 |
| UGC | 内容审核延迟 / 审核通过率 |
| Guild | 活跃贡献度 / 日活公会数 |
技术选型建议
| 模块 | 技术 | 理由 |
|---|---|---|
| Scheduler | RabbitMQ / Redis Stream | 高可靠任务队列 |
| Economy | ACID DB + WAL | 金融级一致性 |
| Guild | PostgreSQL + Cache | 层级数据结构 |
| UGC | MinIO / CDN / 审核服务 | 内容分发 |
扩展方向
- 动态任务 DSL(Lua 定义任务逻辑)
- 经济系统支持 AI 市场调控(政策因子)
- 内容平台化 SDK(统一嵌入各原型游戏)
异步任务系统与幂等结算
异步远征、定时任务、经济结算都依赖一个可靠的异步任务系统。与实时同步不同,异步任务的挑战在于保证执行且只执行一次——既要防止任务丢失,又要避免重复执行导致的经济损失。
Exactly-Once 语义的三要素:
- 任务持久化:任务写入数据库/WAL 后才向客户端返回成功,确保任务不丢失
- 消费者幂等:处理逻辑天然幂等(如更新操作时带版本号校验),或借助唯一键去重
- 确认机制:处理完成后显式确认(ACK),未确认的任务在超时后重新投递
# 幂等结算示例:带版本号校验的乐观锁
class EconomyService:
def settle_order(self, order_id: str, expected_version: int):
with db.transaction():
# 先读取当前版本
order = db.query("SELECT * FROM orders WHERE id = %s", order_id)
if order.status != 'PENDING':
return # 已处理,幂等返回
if order.version != expected_version:
raise ConcurrencyError("版本冲突,请重试")
# 执行结算
self.transfer(order.buyer_id, order.seller_id, order.amount)
db.execute(
"UPDATE orders SET status='SETTLED', version=version+1 WHERE id=%s AND version=%s",
(order_id, expected_version)
)
# 写入结算日志(用于对账和审计)
db.execute(
"INSERT INTO settlement_logs (order_id, amount, settled_at) VALUES (%s, %s, NOW())",
(order_id, order.amount)
)
延迟任务的技术选型:
| 方案 | 精度 | 可靠性 | 适用场景 |
|---|---|---|---|
| Redis ZSET | 秒级 | 中(无 ACK) | 短延迟、可容忍丢失 |
| RabbitMQ Delayed Plugin | 毫秒级 | 高 | 中等规模延迟队列 |
| 数据库轮询 | 分钟级 | 高 | 低频、强一致要求 |
| 自研时间轮 | 毫秒级 | 高 | 超大规模、定制需求 |
生产建议:对于游戏内经济结算,推荐 RabbitMQ + 数据库双写:先写数据库标记状态为 PROCESSING,再投递 MQ;消费者从 MQ 取出后先查数据库确认状态,处理完成后再更新为 SETTLED。这种"本地事务表 + MQ"模式是金融级异步处理的 industry standard。
公会系统与社交图谱设计
公会(Guild)系统不仅是简单的分组,而是包含权限层级、经验值积累、贡献度计算、成员关系管理的复杂社交结构。
权限模型设计:
公会权限层级(RBAC):
┌─────────────┐
│ 会长 Leader │ 所有权限 + 转让/解散
├─────────────┤
│ 副会长 Vice │ 审批成员 + 管理资金
├─────────────┤
│ 官员 Officer│ 踢出普通成员 + 发布公告
├─────────────┤
│ 精英 Elite │ 参与专属活动
├─────────────┤
│ 普通 Member│ 基础参与权限
├─────────────┤
│ 新人 Rookie│ 受限权限(观察期)
└─────────────┘
公会经验值与升级算法:
class GuildLevelingSystem:
"""公会等级经验曲线:指数增长,抑制快速满级"""
@staticmethod
def exp_for_level(level: int) -> int:
"""升到下一级所需经验"""
return int(1000 * (1.5 ** (level - 1)))
@staticmethod
def calculate_contribution(member_actions):
"""综合计算成员贡献度"""
weights = {
'daily_login': 10,
'guild_donation': 50,
'guild_quest_completed': 100,
'guild_war_participation': 200,
'recruit_new_member': 150,
}
return sum(weights.get(action['type'], 0) * action['count'] for action in member_actions)
社交图谱存储:公会成员关系本质上是图结构。当需要查询"某玩家的所有公会好友"或"公会中最活跃的玩家网络"时,关系型数据库的 JOIN 性能急剧下降。Neo4j 等图数据库或 RedisGraph 更适合这类场景。
市场经济系统:订单簿撮合与通胀控制
自由市场经济是游戏长期留存的关键设计。一个健康的虚拟经济需要兼顾玩家自由度和系统稳定性。
订单簿撮合机制:
class OrderBook:
"""限价订单簿:买单按价格降序,卖单按价格升序"""
def __init__(self):
self.bids = [] # 最大堆:价格高优先
self.asks = [] # 最小堆:价格低优先
def place_buy(self, player_id, item_id, price, quantity):
heapq.heappush(self.bids, (-price, time.time(), player_id, item_id, quantity))
self._match()
def place_sell(self, player_id, item_id, price, quantity):
heapq.heappush(self.asks, (price, time.time(), player_id, item_id, quantity))
self._match()
def _match(self):
"""撮合引擎:每次新订单入库后尝试匹配"""
while self.bids and self.asks and -self.bids[0][0] >= self.asks[0][0]:
bid_price, _, bid_player, bid_item, bid_qty = self.bids[0]
ask_price, _, ask_player, ask_item, ask_qty = self.asks[0]
if bid_item != ask_item:
break
trade_qty = min(bid_qty, ask_qty)
trade_price = (ask_price + (-bid_price)) / 2 # 中间价成交
self._execute_trade(bid_player, ask_player, bid_item, trade_qty, trade_price)
# 更新或移除已完成的订单
if bid_qty == trade_qty:
heapq.heappop(self.bids)
else:
self.bids[0] = (-bid_price, self.bids[0][1], bid_player, bid_item, bid_qty - trade_qty)
if ask_qty == trade_qty:
heapq.heappop(self.asks)
else:
self.asks[0] = (ask_price, self.asks[0][1], ask_player, ask_item, ask_qty - trade_qty)
通货膨胀控制策略:
| 策略 | 机制 | 效果 |
|---|---|---|
| 货币回收(Sinks) | 修理费、传送费、税费、销毁合成 | 持续回收流通货币 |
| 供给调控 | NPC 商店无限供应基础物资定价锚 | 防止必需品价格暴涨 |
| 需求刺激 | 赛季更新新装备、外观、稀有道具 | 创造新的消费动机 |
| 公开市场干预 | 系统监控汇率,必要时作为对手方交易 | 抑制短期剧烈波动 |
经济观测指标:基尼系数(财富分配公平度)、货币流通速度(V = GDP / M)、CPI(一篮子商品价格变化)。当基尼系数 > 0.6 时,意味着贫富差距过大,需要推出普惠性活动。
UGC 内容审核管线:AI 预审 + 人工复审
玩家生成内容(UGC)是平台化游戏的核心竞争力,但开放上传带来的内容安全风险不容忽视。一个完善的审核管线需要兼顾效率与准确性。
三级审核架构:
UGC 上传流程:
┌──────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ 用户上传 │───▶│ AI 预审 │───▶│ 人工复审 │───▶│ 正式发布 │
│ (图片/文本)│ │ (OCR/NLP) │ │ (抽检/举报)│ │ (CDN 分发) │
└──────────┘ └────────────┘ └────────────┘ └────────────┘
│
▼
┌────────────┐
│ 明显违规 │
│ 自动拦截 │
└────────────┘
| 风险等级 | 检测方式 | 处理动作 | 延迟 |
|---|---|---|---|
| P0 - 严重违规 | 色情/暴力/政治敏感 ML 模型 | 立即拦截 + 记录日志 + 用户警告 | < 500ms |
| P1 - 疑似违规 | 相似度检测、关键词匹配 | 人工复审队列 + 先屏蔽后审核 | < 5min |
| P2 - 低敏感 | 哈希去重、版权指纹比对 | 抽检机制,放行后随机抽查 | 异步 |
class UGCModerationService:
def moderate_upload(self, content: bytes, content_type: str, user_id: str) -> ModerationResult:
# 1. 内容指纹去重(重复上传秒拒)
fingerprint = self._compute_fingerprint(content)
if self._is_duplicate(fingerprint):
return ModerationResult(rejected=True, reason="DUPLICATE")
# 2. AI 多模态预审
ml_result = self.ml_models.predict(content, content_type)
if ml_result.severity == 'CRITICAL':
self._flag_user(user_id, 'critical_upload')
return ModerationResult(rejected=True, reason=ml_result.category)
if ml_result.severity == 'SUSPICIOUS':
# 进入人工复审队列
self.human_review_queue.enqueue(content, user_id, ml_result.confidence)
return ModerationResult(rejected=True, reason="PENDING_REVIEW")
# 3. 放行并通过 CDN 预热
return ModerationResult(rejected=False, cdn_url=self._publish_to_cdn(content))
数据合规:不同地区对 UGC 内容有不同的法律要求(如欧盟 DSA、中国网络内容生态治理规定)。审核管线需要支持按地区定制规则库,并保留完整的审核日志用于监管审计。
跨服通信与全局数据一致性
跨服战、跨服交易、排行榜等场景需要多个物理服之间共享状态。这在分布式系统中是典型的多数据中心数据同步问题。
全局身份映射:每个玩家的 ID 必须是全局唯一的,通常采用"服前缀 + 本地自增 ID"的复合格式:
玩家 ID 格式:{shard_id}-{local_seq}
示例:S01-1234567(1 服的第 1234567 个玩家)
优势:
1. 无需全局自增 ID 生成器,避免单点瓶颈
2. ID 本身包含位置信息,便于路由
3. 支持后续合服操作
数据同步策略:
| 数据类型 | 一致性要求 | 同步方案 |
|---|---|---|
| 玩家基础信息 | 弱一致 | 异步广播,延迟容忍 5-30 秒 |
| 好友/公会关系 | 最终一致 | CRDT 合并,冲突时取时间戳最新 |
| 排行榜 | 弱一致 | 定时汇总各服数据,中心服排序 |
| 跨服交易 | 强一致 | 两阶段提交 / Saga 事务,分布式锁 |
| 全局活动状态 | 强一致 | 中心 Redis + 发布订阅 |
# 跨服交易 Saga 事务示例
class CrossShardTradeSaga:
def execute(self, buyer_shard, seller_shard, item_id, price):
txn_id = generate_uuid()
try:
# Phase 1: 买家扣款(本地事务)
buyer_shard.deduct_currency(txn_id, buyer_id, price)
# Phase 2: 卖家发货(远程调用)
seller_shard.transfer_item(txn_id, seller_id, buyer_id, item_id)
# Phase 3: 结算完成确认
self._commit(txn_id)
except Exception as e:
# 补偿:回滚已执行的操作
buyer_shard.refund(txn_id, buyer_id, price)
seller_shard.recall_item(txn_id, seller_id, item_id)
raise TradeFailedException(e)
最佳实践:跨服通信优先使用异步消息队列(Kafka /RabbitMQ)而非同步 RPC。同步调用不仅增加延迟,还会将故障级联到调用方。对于必须强一致的操作,使用独立的"协调服"作为 Saga 编排器。
延伸阅读
- 在线联机原型第一章 — 底层同步与状态管理基础
- 在线联机原型第二章 — 实时竞技与协作机制
- minigame06 API 设计 — 后端 API 规范与接口定义
- 分布式 ID 生成 — 全局唯一 ID 生成策略
- Kubernetes 可观测性 — 游戏服务端监控与日志采集
- 事件驱动架构 — 异步消息与 Saga 事务模式
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。