52 KiB
52 KiB
\n ┌─────────────────────────────────┐\n │ 客户端 (Cocos 3.x) │\n │ WSS / HTTPS / gRPC-Web │\n └──────────────┬──────────────────┘\n │\n ┌──────────────▼──────────────────┐\n │ 接入层 (OpenResty / Traefik) │\n │ TLS 终止 · 限流 · 路由 · 灰度 │\n │ 端口: 443(HTTPS) 8443(WSS) │\n └──────┬──────────┬───────────────┘\n │ │\n ┌───────────────▼──┐ ┌───▼──────────────────┐\n │ Nakama 集群 │ │ Gin HTTP API 网关 │\n │ (实时 + 游戏逻辑) │ │ (RESTful + gRPC-GW) │\n │ 端口: 7350/7351 │ │ 端口: 8080/8443 │\n └───┬──┬──┬────────┘ └──┬──┬──┬─────────────┘\n │ │ │ │ │ │\n ┌──────────────┘ │ └────────┐ │ │ └────────────┐\n ▼ ▼ ▼ ▼ ▼ ▼\n ┌──────────────┐ ┌──────────────┐ ┌────────────────┐ ┌──────────────┐\n │ 战斗模拟服务 │ │ 离线结算服务 │ │ 世界事件服务 │ │ GM/运营服务 │\n │ (Go gRPC) │ │ (Go gRPC) │ │ (Go gRPC) │ │ (Gin HTTP) │\n │ 端口: 9001 │ │ 端口: 9002 │ │ 端口: 9003 │ │ 端口: 9010 │\n └──────┬───────┘ └──────┬───────┘ └───────┬────────┘ └──────┬───────┘\n │ │ │ │\n └────────────────┴────────┬─────────┴─────────────────┘\n │\n ┌────────────────────┼────────────────────────┐\n │ │ │\n ┌───────▼──────┐ ┌────────▼────────┐ ┌──────────▼──────────┐\n │ PostgreSQL 16│ │ Valkey 集群 │ │ Kafka 集群 │\n │ 主从 + PgBnchr│ │ 主从 + Sentinel │ │ 3 Broker / 3 ZK │\n │ 端口: 5432 │ │ 端口: 6379 │ │ 端口: 9092/2181 │\n └──────────────┘ └─────────────────┘ └─────────────────────┘\n │\n ┌───────▼──────┐\n │ Nacos 2.x │\n │ 配置中心/注册 │\n │ 端口: 8848 │\n └──────────────┘\n\n\n### 2.2 各微服务职责边界\n\n| 服务 | 职责 | 技术实现 | 对外协议 | 对内协议 |\n|------|------|----------|----------|----------|\n| Nakama 集群 | 账号认证、会话管理、实时 WebSocket 推送、排行榜、好友、匹配、运行时 Hook(Go 插件) | Nakama 3.x + Go Runtime | WSS + Nakama HTTP API | gRPC ↔ 各微服务 |\n| Gin HTTP API 网关 | RESTful 接口聚合、gRPC-Gateway 反向代理、业务限流、请求签名校验、灰度路由 | Go + Gin + gRPC-Gateway | HTTPS RESTful + gRPC-Web | gRPC ↔ 各微服务 |\n| 战斗模拟服务 | ATB 战斗引擎、PVE/PVP 战斗计算、战报生成、掉落计算、逃跑判定 | Go gRPC | — | gRPC(Nakama/Gin 调用) |\n| 离线结算服务 | 离线时间快进、资源批量结算、弟子代挂结算、游历事件模拟、上线结算面板数据生成 | Go gRPC + Nakama Scheduled Task | — | gRPC + Kafka(结算事件发布) |\n| 世界事件服务 | 随机事件生成、事件池管理、区域广播、奇遇/灵气异动/天象触发、破界遗迹生成 | Go gRPC | — | Kafka(事件发布/订阅) + gRPC |\n| GM/运营服务 | 封号/解封、物品发放/回收、配置热更审计、数据查询、活动管理、公告发布 | Go + Gin HTTP | HTTPS(内部管理) | gRPC ↔ Nakama/DB,Nacos 推送 |\n| 经济监控服务 | 货币流水监控、通胀/通缩预警、异常交易检测、水龙头/下水道统计 | Go | — | Kafka(消费 economy_audit_logs 事件) |\n| 推送通知服务 | 离线推送(APNs/FCM/华为)、游戏内通知中心、WebSocket 消息路由 | Go + Nakama Hook | — | Kafka + Nakama Runtime |\n\n### 2.3 服务间调用关系\n\n\n客户端 ──WSS──► Nakama 集群 ──gRPC──► 战斗模拟服务\n │ │ │\n │──HTTPS──► Gin API ──gRPC──► 离线结算服务\n │ │ │\n │ ├──gRPC──► 世界事件服务 │\n │ │ │\n │ └──gRPC──► GM/运营服务 │\n │ │\n └──Kafka──► 经济监控服务 │\n 推送通知服务 ◄──Kafka─────────┘\n\n\n关键调用链路:\n\n| 调用链路 | 协议 | 超时 | 重试 | 降级策略 |\n|----------|------|------|------|----------|\n| 客户端 → Nakama → 战斗模拟 | WSS → gRPC | 5s | 1 次 | 返回"战斗超时,请稍后重试" |\n| 客户端 → Gin → 离线结算 | HTTPS → gRPC | 10s | 0 | 返回缓存结算结果(Valkey) |\n| Nakama → 世界事件服务 | gRPC | 3s | 1 次 | 降级为预配置事件池随机 |\n| 任意服务 → PostgreSQL | TCP | 3s (查询) / 10s (事务) | 0 (查询) / 1 (事务) | 读请求降级到 Valkey 缓存 |\n| 任意服务 → Valkey | TCP | 500ms | 2 次 | 降级到 DB 直读 |\n| 任意服务 → Nacos | HTTP | 2s | 3 次 | 使用本地缓存配置文件兜底 |\n\n### 2.4 本地端口规划\n\n| 端口 | 服务 | 说明 |\n|------|------|------|\n| 443 | 接入层 (OpenResty/Traefik) | HTTPS 外部入口 |\n| 8443 | 接入层 | WSS 外部入口 |\n| 7350 | Nakama | HTTP API(内部) |\n| 7351 | Nakama | gRPC(内部) |\n| 8080 | Gin API 网关 | HTTP(内部) |\n| 8443 | Gin API 网关 | gRPC(内部) |\n| 9001 | 战斗模拟服务 | gRPC |\n| 9002 | 离线结算服务 | gRPC |\n| 9003 | 世界事件服务 | gRPC |\n| 9010 | GM/运营服务 | HTTP |\n| 5432 | PostgreSQL | 数据库 |\n| 6379 | Valkey | 缓存 |\n| 9092 | Kafka | 消息队列 |\n| 2181 | ZooKeeper | Kafka 协调 |\n| 8848 | Nacos | 配置中心 |\n| 9090 | Prometheus | 指标采集 |\n| 3000 | Grafana | 监控面板 |\n| 9200 | Elasticsearch | 日志存储 |\n| 5601 | Kibana | 日志查询 |\n\n### 2.5 本地开发环境端口偏移\n\n多实例本地开发时,第二套服务端口在基准端口上加 1000(如 Nakama #2: 8350/8351,PostgreSQL #2: 6432)。\n\n---\n\n## 3. 水平扩展方案\n\n### 3.1 Nakama 多实例负载均衡\n\n#### 3.1.1 扩展模型\n\nNakama 3.x 原生支持多实例部署。各实例通过共享 PostgreSQL 和注册中心(Nacos)实现无状态对等节点。\n\n\n ┌──────────────┐\n │ 接入层 LB │\n │ (L4/L7) │\n └──┬───────┬───┘\n │ │\n ┌────────▼──┐ ┌──▼────────┐\n │ Nakama #1 │ │ Nakama #2 │ ← 可水平扩展至 N 个\n │ (Pod) │ │ (Pod) │\n └─────┬──────┘ └──────┬────┘\n │ │\n └───────┬───────┘\n │\n ┌───────▼───────┐\n │ PostgreSQL │\n │ (事实源) │\n └───────────────┘\n\n\n#### 3.1.2 会话亲和性\n\n| 策略 | 说明 |\n|------|------|\n| WebSocket 会话亲和 | 客户端 WSS 连接在接入层按 nakama_session_token 的 SHA256 前 8 位做一致性哈希,路由到固定 Nakama 实例;断线重连时如目标实例不可用则重新哈希 |\n| RESTful 无亲和 | HTTP GET/POST 请求不做会话绑定,由接入层轮询分发;每次请求携带完整 session token,任意实例可独立校验 |\n| gRPC 长连接 | gRPC 客户端与单个后端实例维持 HTTP/2 长连接,连接断开后自动重连到新实例 |\n\n#### 3.1.3 状态同步\n\nNakama 多实例之间不直接通信。状态一致性通过以下机制保证:\n\n| 机制 | 说明 |\n|------|------|\n| PostgreSQL 事实源 | 角色数据、经济数据、战斗结果等所有持久化状态以 PostgreSQL 为唯一事实源 |\n| Valkey 共享缓存 | 排行榜(Sorted Set)、在线状态(Hash)、离线消息队列(List)存储在共享 Valkey 集群,所有 Nakama 实例可读写 |\n| Kafka 事件广播 | 世界事件、经济流水、战斗结算等需要跨实例通知的事件通过 Kafka 发布,各实例订阅后更新本地缓存或推送 |\n| Nakama 内置集群发现 | Nakama 3.x 通过 PostgreSQL runtime_leader 表实现 Leader 选举;定时任务(如离线结算扫描)仅由 Leader 执行 |\n\n#### 3.1.4 扩容触发条件\n\n| 指标 | 阈值 | 动作 |\n|------|------|------|\n| 单实例 WebSocket 连接数 | > 5000 | 新增 Nakama 实例 |\n| 单实例 CPU 使用率 | > 70% 持续 3 分钟 | 新增 Nakama 实例 |\n| 单实例内存使用率 | > 80% | 新增 Nakama 实例 |\n| WSS 连接排队时间 | > 2s | 新增接入层节点 |\n\n### 3.2 微服务水平扩展\n\n| 服务 | 扩展方式 | 最大实例数(单集群) | 无状态 | 说明 |\n|------|----------|----------------------|--------|------|\n| Gin API 网关 | K8s HPA | 10 | 是 | 按 QPS/CPU 扩缩 |\n| 战斗模拟服务 | K8s HPA | 20 | 是 | 战斗为纯计算,无状态 |\n| 离线结算服务 | 固定 2 + Leader 选举 | 2 | 否(Leader) | 仅 Leader 执行定时扫描 |\n| 世界事件服务 | 固定 3 | 3 | 否 | 事件池状态在内存,需固定实例 |\n| GM/运营服务 | 固定 2 | 2 | 是 | 低流量 |\n| 经济监控服务 | 固定 1 | 1 | 否 | 全局单例,消费 Kafka 全量流水 |\n\n---\n\n## 4. 消息队列选型与事件总线设计\n\n### 4.1 消息队列选型:Kafka 3.x\n\n| 维度 | 说明 |\n|------|------|\n| 选型理由 | 世界事件广播需要高吞吐 + 多消费者组;经济审计流水需要持久化 + 回溯能力;Kafka 的分区有序 + 消费组机制天然适配 |\n| 部署模式 | 3 Broker + 3 KRaft Controller(Kafka 3.4+ 去 ZooKeeper) |\n| 副本因子 | replication.factor=3,min.insync.replicas=2,acks=all |\n| 消息保留 | 普通 Topic 保留 7 天;经济审计 Topic 保留 30 天 |\n\n### 4.2 Topic 设计\n\n| Topic 名称 | 分区数 | 生产者 | 消费者 | 说明 |\n|------------|--------|--------|--------|------|\n| honghuang.world.events | 12(按 world_tier 分区) | 世界事件服务 | Nakama(推送)、经济监控(资源影响) | 世界广播事件(破界/异象/BOSS) |\n| honghuang.battle.settled | 24 | 战斗模拟服务 | 离线结算(战后结算)、经济监控(掉落流水)、推送通知(战报通知) | 战斗完成事件 |\n| honghuang.economy.audit | 12 | 所有产生货币变动的服务 | 经济监控、GM 后台 | 货币流水审计 |\n| honghuang.social.events | 6 | Nakama Runtime | 推送通知、世界事件服务 | 关系请求/帮派召集/道侣护法 |\n| honghuang.offline.settlement | 6 | 离线结算服务 | 推送通知(结算完成通知) | 离线结算完成事件 |\n| honghuang.market.trade | 12 | Gin API(交易行/拍卖) | 经济监控、推送通知 | 市场成交/拍卖出价事件 |\n| honghuang.disciple.events | 6 | 离线结算服务 | 推送通知 | 弟子归来/死亡/叛逃事件 |\n| honghuang.config.changed | 3 | Nacos 监听器 | 所有服务 | 配置变更通知 |\n\n### 4.3 消息格式规范\n\n所有 Kafka 消息统一使用 Protobuf 序列化,外层 Envelope 定义:\n\nprotobuf\nmessage EventEnvelope {\n string event_id = 1; // 全局唯一事件 ID (UUID)\n string event_type = 2; // 事件类型枚举\n int64 timestamp_ms = 3; // 生产时间戳(毫秒)\n string source_service = 4; // 生产者服务名\n bytes payload = 5; // 按 event_type 对应的 protobuf 序列化\n map<string, string> headers = 6; // 扩展头(trace_id, character_id 等)\n}\n\n\n### 4.4 消费者组设计\n\n| 消费者组 ID | 订阅 Topic | 消费者实例 | 说明 |\n|-------------|------------|------------|------|\n| nakama-push-group | world.events, battle.settled, social.events, offline.settlement, disciple.events | Nakama 实例数 | 消费后通过 WebSocket 推送给在线玩家 |\n| economy-monitor-group | economy.audit, battle.settled, market.trade | 1(单例) | 经济监控聚合 |\n| settlement-notify-group | offline.settlement | 推送通知服务 | 离线推送 APNs/FCM |\n| config-reload-group | config.changed | 所有服务实例 | 每个服务独立消费,更新本地配置缓存 |\n\n### 4.5 消息可靠性保障\n\n| 策略 | 配置 | 说明 |\n|------|------|------|\n| 生产者幂等 | enable.idempotence=true,max.in.flight.requests.per.connection=5 | 防止网络重试导致消息重复 |\n| 消费者手动提交 | enable.auto.commit=false | 处理成功后手动 commit offset |\n| 死信队列 | 每个 Topic 配置 *.DLQ Topic | 消费失败 3 次后进入 DLQ,人工介入 |\n| 消息去重 | 消费端按 event_id + 业务幂等键在 Valkey 中去重,TTL 24h | 防止重复消费 |\n\n---\n\n## 5. 缓存策略\n\n### 5.1 Valkey 集群部署\n\n| 配置项 | 值 | 说明 |\n|--------|-----|------|\n| 部署模式 | 3 主 3 从 + 3 Sentinel | 高可用,自动故障转移 |\n| 内存上限 | 每节点 8GB | 总可用 24GB |\n| 淘汰策略 | allkeys-lfu | 淘汰最不常用 Key |\n| 持久化 | RDB(每 15 分钟)+ AOF(每秒 fsync) | 数据恢复保障 |\n| Key 命名规范 | {service}:{entity}:{id}:{field} | 如 game:char:c-uuid-101:stats |\n\n### 5.2 Key 设计规范\n\n#### 5.2.1 玩家热数据\n\n| Key 模式 | 类型 | TTL | 说明 |\n|----------|------|-----|------|\n| game:char:{character_id}:profile | Hash | 2h(在线续期) | 角色基础信息快照 |\n| game:char:{character_id}:stats | Hash | 2h | 战斗属性快照(ATB 用) |\n| game:char:{character_id}:currencies | Hash | 30min | 货币余额快照 |\n| game:char:{character_id}:manuals | String (JSON) | 1h | 功法列表快照 |\n| game:char:{character_id}:skills | String (JSON) | 1h | 技能列表快照 |\n| game:char:{character_id}:location | Hash | 2h | 当前位置(world_tier, region_id, zone_id) |\n| game:char:{character_id}:online | String | 2h | 在线状态标记 |\n\n#### 5.2.2 排行榜\n\n| Key 模式 | 类型 | TTL | 说明 |\n|----------|------|-----|------|\n| rank:power:{world_tier}:{realm_tier} | Sorted Set | 5min | 战力排行榜 |\n| rank:wealth:{world_tier} | Sorted Set | 5min | 财富排行榜 |\n| rank:hunter:{world_tier} | Sorted Set | 5min | 猎人威望排行榜 |\n| rank:guild:{world_tier} | Sorted Set | 5min | 帮派声望排行榜 |\n\n#### 5.2.3 会话与消息\n\n| Key 模式 | 类型 | TTL | 说明 |\n|----------|------|-----|------|\n| session:{character_id}:ws_instance | String | 2h | 玩家 WebSocket 所在 Nakama 实例 ID |\n| offline:msg:{character_id} | List | 7d | 离线消息队列,上限 200 条 |\n| idempotent:{character_id}:{idempotency_key} | String | 24h | 幂等键去重 |\n\n#### 5.2.4 配置与全局\n\n| Key 模式 | 类型 | TTL | 说明 |\n|----------|------|-----|------|\n| config:nacos:{config_key} | String | 5min | Nacos 配置本地缓存 |\n| global:unique_skill:{skill_id} | String | 永不过期 | 全服唯一技能持有者 character_id |\n| global:auction:{auction_id}:bids | Sorted Set | 拍卖结束时清理 | 拍卖实时出价列表 |\n| global:world_event:{event_id} | Hash | 事件持续时间 + 1h | 进行中的世界事件 |\n\n#### 5.2.5 限流与防护\n\n| Key 模式 | 类型 | TTL | 说明 |\n|----------|------|-----|------|\n| ratelimit:{character_id}:{path}:{window} | String | 60s | 接口限流计数器 |\n| lock:action:{character_id}:{action_type} | String | 30s | 操作分布式锁(防并发突破/渡劫) |\n| lock:economic:{character_id} | String | 10s | 经济操作串行锁 |\n\n### 5.3 缓存穿透/雪崩/击穿防护\n\n| 问题 | 防护方案 | 实现细节 |\n|------|----------|----------|\n| 缓存穿透 | 布隆过滤器 + 空值缓存 | 对 game:char:{id}:profile 查询前先过布隆过滤器(Valkey Bloom 模块或 Go 端实现);不存在的角色缓存空字符串,TTL 60s |\n| 缓存雪崩 | TTL 随机偏移 + 多级缓存 | 所有 Key 的 TTL 在基础值上加 0~20% 随机偏移(如 2h ± 24min);服务进程内 LRU 缓存(Go sync.Map + ristretto)作为 L1,Valkey 作为 L2 |\n| 缓存击穿 | 分布式互斥锁 + 热点预加载 | 热点 Key(如排行榜、全服唯一技能持有者)失效时,使用 SETNX 互斥锁(TTL 10s),仅一个请求回源 DB;其余请求等待或返回旧值 |\n\n### 5.4 热数据分层策略\n\n\n┌─────────────────────────────────────────────┐\n│ L0: 进程内缓存 (ristretto / sync.Map) │\n│ 范围: 静态配置、种族数据、技能模板、境界配置 │\n│ 容量: 256MB / 实例 │\n│ TTL: 配置版本变更时主动失效 │\n├─────────────────────────────────────────────┤\n│ L1: Valkey 集群 │\n│ 范围: 玩家热数据、排行榜、会话、限流、分布式锁 │\n│ 容量: 24GB 集群 │\n│ TTL: 见 §5.2 各 Key TTL │\n├─────────────────────────────────────────────┤\n│ L2: PostgreSQL 16 │\n│ 范围: 全量持久化数据 │\n│ 容量: 无限制(按需扩容磁盘) │\n│ TTL: 永不过期 │\n└─────────────────────────────────────────────┘\n\n\n读取路径:L0 → L1 → L2,命中即返回并回填上层。\n写入路径:先写 L2(DB 事务),成功后更新 L1(Valkey),异步失效 L0(进程内缓存广播)。\n\n---\n\n## 6. 容灾与故障转移\n\n### 6.1 PostgreSQL 主从切换\n\n| 配置项 | 值 | 说明 |\n|--------|-----|------|\n| 部署模式 | 1 主 + 2 从(同步 + 异步) | 同步从保证零数据丢失,异步从用于读扩展 |\n| 同步模式 | synchronous_commit=on,synchronous_standby_names='pg_sync_standby' | 主库写入需同步从确认 |\n| 故障检测 | PgBouncer + Patroni 健康检查,间隔 3s | 连续 3 次失败触发切换 |\n| 自动切换 | Patroni 自动 Failover,RTO < 30s | 同步从提升为新主,异步从重新指向新主 |\n| 数据一致性 | 同步复制保证零丢失;异步从最多丢失最后 1 个事务 | 可接受 |\n| 手动切换 | patroni switchover 命令 | 计划维护时使用 |\n\n### 6.2 Valkey 故障转移\n\n| 配置项 | 值 | 说明 |\n|--------|-----|------|\n| 部署模式 | 3 主 3 从 + 3 Sentinel | 每个主节点对应 1 个从节点 |\n| 故障检测 | Sentinel down-after-milliseconds=5000 | 5s 无响应判定主观下线 |\n| 自动切换 | Sentinel failover-timeout=60000 | 60s 内完成从提升 |\n| 客户端重连 | Go go-redis 客户端内置 Sentinel 支持 | 自动发现新主 |\n| 数据丢失窗口 | 异步复制,最多丢失最后 1~2 秒的写入 | 可接受(缓存层) |\n\n### 6.3 Kafka 故障转移\n\n| 配置项 | 值 | 说明 |\n|--------|-----|------|\n| 部署模式 | 3 Broker,每个 Topic 副本因子 3 | 任一 Broker 宕机不影响可用性 |\n| 控制器 | KRaft 模式(3 Controller),无需 ZooKeeper | Kafka 3.4+ |\n| ISR 最小副本 | min.insync.replicas=2 | 保证写入至少 2 个副本 |\n| Producer acks | all | 所有 ISR 确认后才返回 |\n| 消费者 Rebalance | session.timeout.ms=30000,heartbeat.interval.ms=10000 | Broker 宕机后 30s 内消费者自动重平衡 |\n\n### 6.4 Nakama 实例故障\n\n| 场景 | 处理方式 | RTO |\n|------|----------|-----|\n| 单实例 OOM/Crash | 接入层健康检查(/healthcheck)30s 检测到,摘除该节点;客户端自动重连到其他实例 | < 30s |\n| Leader 实例宕机 | PostgreSQL runtime_leader 表过期后(TTL 15s),其他实例竞选新 Leader | < 30s |\n| 全部实例不可用 | 接入层返回 503,客户端展示"服务器维护中";Valkey 中保留离线消息 | 人工介入 |\n\n### 6.5 降级策略\n\n| 场景 | 降级方案 | 用户感知 |\n|------|----------|----------|\n| PostgreSQL 主库不可用 | 只读模式:读从库,写请求返回"稍后重试" | 无法进行写操作(突破/交易/战斗),可查看数据 |\n| Valkey 不可用 | 直读 PostgreSQL,性能下降但功能可用 | 响应变慢(200ms → 500ms+) |\n| Kafka 不可用 | 世界事件改为本地定时器触发(降级模式);经济流水写本地文件,恢复后补发 | 世界事件频率降低 |\n| 战斗模拟服务不可用 | 离线挂机战斗暂停结算,上线后补算 | 离线期间无战斗收益 |\n| Nacos 不可用 | 使用本地缓存配置文件(/etc/honghuang/config/) | 无法热更配置 |\n\n### 6.6 数据一致性保障\n\n| 场景 | 方案 | 说明 |\n|------|------|------|\n| 角色数据 | PostgreSQL 强一致性 + Valkey 最终一致 | 写操作先落 DB,再异步更新 Valkey;读操作允许短暂不一致(秒级) |\n| 经济数据 | 乐观锁 + 审计日志 | currency_balances 使用 amount = amount + delta WHERE amount + delta >= 0 原子更新;所有变动写 economy_audit_logs |\n| 唯一技能 | PostgreSQL 行锁 + Valkey 全局锁 | 获取唯一技能时 SELECT ... FOR UPDATE;Valkey global:unique_skill:{skill_id} 双重校验 |\n| 排行榜 | 最终一致 | 每 5 分钟从 DB 聚合刷新到 Valkey Sorted Set;在线玩家实时更新 |\n\n---\n\n## 7. 部署架构\n\n### 7.1 本地开发环境(Docker Compose)\n\n#### 7.1.1 docker-compose.yml 结构\n\nyaml\n# 本地开发用单机全栈部署\nservices:\n # --- 基础设施 ---\n postgres:\n image: postgres:16-alpine\n ports: [\"5432:5432\"]\n environment:\n POSTGRES_DB: honghuang\n POSTGRES_USER: honghuang\n POSTGRES_PASSWORD: ${PG_PASSWORD}\n volumes:\n - pg_data:/var/lib/postgresql/data\n - ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql\n command: >\n postgres\n -c shared_buffers=512MB\n -c effective_cache_size=1536MB\n -c max_connections=200\n -c wal_level=replica\n\n valkey:\n image: valkey/valkey:7-alpine\n ports: [\"6379:6379\"]\n command: >\n valkey-server\n --maxmemory 1gb\n --maxmemory-policy allkeys-lfu\n --appendonly yes\n --appendfsync everysec\n\n kafka:\n image: apache/kafka:3.7\n ports: [\"9092:9092\"]\n environment:\n KAFKA_NODE_ID: 1\n KAFKA_PROCESS_ROLES: broker,controller\n KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093\n KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093\n KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER\n KAFKA_LOG_RETENTION_HOURS: 168\n\n nacos:\n image: nacos/nacos-server:v2.3.0\n ports: [\"8848:8848\", \"9848:9848\"]\n environment:\n MODE: standalone\n SPRING_DATASOURCE_PLATFORM: \"\"\n\n # --- 游戏服务 ---\n nakama:\n image: heroiclabs/nakama:3.22\n ports: [\"7350:7350\", \"7351:7351\"]\n depends_on: [postgres, valkey, nacos]\n environment:\n DATABASE_URL: postgres://honghuang:${PG_PASSWORD}@postgres:5432/honghuang\n VALKEY_URL: valkey://valkey:6379\n volumes:\n - ./nakama_data:/nakama/data\n\n gin-api:\n build: ./services/gin-api\n ports: [\"8080:8080\"]\n depends_on: [postgres, valkey, nacos]\n\n battle-service:\n build: ./services/battle\n ports: [\"9001:9001\"]\n depends_on: [postgres, valkey, kafka]\n\n settlement-service:\n build: ./services/settlement\n ports: [\"9002:9002\"]\n depends_on: [postgres, valkey, kafka]\n\n world-event-service:\n build: ./services/world-event\n ports: [\"9003:9003\"]\n depends_on: [postgres, valkey, kafka]\n\n # --- 监控 ---\n prometheus:\n image: prom/prometheus:v2.52\n ports: [\"9090:9090\"]\n volumes:\n - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml\n\n grafana:\n image: grafana/grafana:11.0\n ports: [\"3000:3000\"]\n depends_on: [prometheus]\n\nvolumes:\n pg_data:\n\n\n#### 7.1.2 本地环境资源需求\n\n| 资源 | 最低配置 | 推荐配置 |\n|------|----------|----------|\n| CPU | 8 核 | 16 核 |\n| 内存 | 16 GB | 32 GB |\n| 磁盘 | 50 GB SSD | 100 GB SSD |\n\n### 7.2 测试/Staging 环境(Docker Compose + 多实例)\n\n在本地开发环境基础上:\n\n- PostgreSQL: 1 主 + 1 从(Docker Compose 多实例)\n- Valkey: 1 主 + 1 从 + 1 Sentinel\n- Kafka: 1 Broker(测试环境足够)\n- Nakama: 2 实例(验证负载均衡与会话亲和)\n- 各微服务: 单实例\n\n### 7.3 生产环境(Kubernetes)\n\n#### 7.3.1 集群规格\n\n| 节点类型 | 数量 | 规格 | 用途 |\n|----------|------|------|------|\n| Master | 3 | 4C 8G | K8s 控制面 |\n| Worker (通用) | 6 | 8C 16G | 无状态微服务(Nakama, Gin API, 战斗, 事件, GM) |\n| Worker (DB) | 3 | 8C 32G, 500G SSD | PostgreSQL + Valkey |\n| Worker (MQ) | 3 | 4C 8G, 200G SSD | Kafka |\n| Worker (监控) | 2 | 4C 16G, 200G SSD | Prometheus, Grafana, ELK |\n\n#### 7.3.2 K8s 命名空间划分\n\n| Namespace | 用途 |\n|-----------|------|\n| honghuang-game | 游戏核心服务(Nakama, Gin API, 战斗, 结算, 事件) |\n| honghuang-infra | 基础设施(PostgreSQL Operator, Valkey Operator, Kafka Operator) |\n| honghuang-monitor | 监控(Prometheus, Grafana, ELK) |\n| honghuang-gm | GM/运营后台 |\n| ingress-nginx | 接入层 |\n\n#### 7.3.3 生产环境关键 Deployment 配置\n\nyaml\n# Nakama Deployment (示例)\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: nakama\n namespace: honghuang-game\nspec:\n replicas: 3\n strategy:\n type: RollingUpdate\n rollingUpdate:\n maxSurge: 1\n maxUnavailable: 0\n template:\n spec:\n containers:\n - name: nakama\n image: registry.example.com/honghuang/nakama:3.22.x\n resources:\n requests:\n cpu: \"2\"\n memory: \"4Gi\"\n limits:\n cpu: \"4\"\n memory: \"8Gi\"\n ports:\n - containerPort: 7350\n name: http\n - containerPort: 7351\n name: grpc\n readinessProbe:\n httpGet:\n path: /healthcheck\n port: 7350\n initialDelaySeconds: 10\n periodSeconds: 5\n livenessProbe:\n httpGet:\n path: /healthcheck\n port: 7350\n initialDelaySeconds: 30\n periodSeconds: 10\n env:\n - name: DATABASE_URL\n valueFrom:\n secretKeyRef:\n name: honghuang-secrets\n key: database-url\n - name: VALKEY_URL\n valueFrom:\n secretKeyRef:\n name: honghuang-secrets\n key: valkey-url\n\n\n#### 7.3.4 演进路径\n\n| 阶段 | 部署方式 | 规模 | 时间节点 |\n|------|----------|------|----------|\n| Phase 1: 开发/内测 | Docker Compose 单机 | 100 并发 | 开发期 |\n| Phase 2: 公测 | K8s 小集群(3 Worker) | 5,000 并发 | 公测前 |\n| Phase 3: 正式上线 | K8s 全集群(14 节点) | 50,000 并发 | 上线 |\n| Phase 4: 规模扩展 | K8s 扩 Worker 节点 + 读写分离 | 200,000+ 并发 | 用户增长后 |\n\n---\n\n## 8. 监控与告警\n\n### 8.1 指标采集(Prometheus)\n\n#### 8.1.1 指标暴露端口\n\n| 服务 | 指标端口 | 路径 | 说明 |\n|------|----------|------|------|\n| Nakama | 7350 | /metrics | 内置 Prometheus 指标 |\n| Gin API | 8080 | /metrics | 自定义业务指标 |\n| 战斗模拟服务 | 9001 | /metrics | gRPC 拦截器指标 |\n| 离线结算服务 | 9002 | /metrics | 结算耗时/批次大小 |\n| 世界事件服务 | 9003 | /metrics | 事件生成频率 |\n| PostgreSQL | 9187 | /metrics | postgres_exporter |\n| Valkey | 9121 | /metrics | valkey_exporter |\n| Kafka | 9308 | /metrics | kafka_exporter |\n| Nacos | — | /nacos/actuator/prometheus | Nacos 内置 |\n\n#### 8.1.2 核心业务指标\n\n| 指标名 | 类型 | 说明 |\n|--------|------|------|\n| honghuang_online_players | Gauge | 当前在线玩家数 |\n| honghuang_ws_connections | Gauge | WebSocket 连接数(per instance) |\n| honghuang_battle_total | Counter | 战斗总次数(label: type, result) |\n| honghuang_battle_duration_seconds | Histogram | 战斗计算耗时 |\n| honghuang_settlement_batch_size | Histogram | 离线结算批次大小 |\n| honghuang_settlement_duration_seconds | Histogram | 离线结算耗时 |\n| honghuang_economy_flow_total | Counter | 经济流水条数(label: currency, flow_type) |\n| honghuang_api_request_duration_seconds | Histogram | API 请求耗时(label: path, method, status) |\n| honghuang_api_request_total | Counter | API 请求总数 |\n| honghuang_kafka_consumer_lag | Gauge | Kafka 消费者延迟 |\n| honghuang_valkey_hit_rate | Gauge | Valkey 缓存命中率 |\n| honghuang_world_event_active | Gauge | 当前活跃世界事件数 |\n\n#### 8.1.3 基础设施指标\n\n| 指标来源 | 关键指标 |\n|----------|----------|\n| PostgreSQL | pg_stat_activity_count, pg_locks_count, pg_replication_lag, pg_database_size_bytes, pg_stat_user_tables_* |\n| Valkey | valkey_connected_clients, valkey_used_memory_bytes, valkey_keyspace_hits/misses, valkey_evicted_keys, valkey_repl_backlog_* |\n| Kafka | kafka_server_BrokerTopicMetrics_MessagesInPerSec, kafka_server_ReplicaManager_UnderReplicatedPartitions, kafka_consumergroup_lag |\n| K8s Node | node_cpu_seconds_total, node_memory_MemAvailable_bytes, node_filesystem_avail_bytes |\n\n### 8.2 日志聚合(ELK)\n\n#### 8.2.1 日志格式规范\n\n所有服务统一使用 JSON 格式输出日志到 stdout/stderr:\n\njson\n{\n \"level\": \"info\",\n \"ts\": \"2026-07-02T12:00:00.123Z\",\n \"caller\": \"battle/engine.go:142\",\n \"msg\": \"battle completed\",\n \"trace_id\": \"0190a1b2-c3d4-7e8f-9a0b-1c2d3e4f5a6b\",\n \"battle_id\": \"b-uuid-505\",\n \"attacker_id\": \"c-uuid-101\",\n \"defender_id\": \"npc-ghost-01\",\n \"duration_ms\": 45,\n \"winner\": \"attacker\"\n}\n\n\n#### 8.2.2 日志级别规范\n\n| 级别 | 用途 | 示例 |\n|------|------|------|\n| debug | 开发调试,生产环境关闭 | SQL 查询详情、缓存命中/未命中 |\n| info | 正常业务流程 | 战斗完成、结算批次、配置加载 |\n| warn | 异常但可恢复 | 重试成功、降级触发、接近阈值 |\n| error | 错误需关注 | 战斗计算异常、DB 写入失败、Kafka 发送失败 |\n| fatal | 致命错误,进程退出 | DB 连接池耗尽、Nacos 不可达且无本地缓存 |\n\n#### 8.2.3 ELK 部署\n\n| 组件 | 规格 | 说明 |\n|------|------|------|\n| Filebeat | DaemonSet,每节点一个 | 采集容器 stdout 日志 |\n| Elasticsearch | 3 节点,每节点 100G SSD | 日志存储,保留 30 天 |\n| Kibana | 单实例 | 日志查询与可视化 |\n\n#### 8.2.4 日志索引策略\n\n| 索引模式 | 生命周期 | 说明 |\n|----------|----------|------|\n| honghuang-game-{yyyy.MM.dd} | 热 3 天 → 温 7 天 → 冷 30 天 → 删除 | 游戏服务日志 |\n| honghuang-infra-{yyyy.MM.dd} | 热 7 天 → 温 14 天 → 冷 60 天 → 删除 | 基础设施日志 |\n| honghuang-audit-{yyyy.MM.dd} | 热 30 天 → 温 90 天 → 冷 365 天 → 删除 | 审计/安全日志 |\n\n### 8.3 链路追踪\n\n#### 8.3.1 方案选型\n\n采用 OpenTelemetry + Jaeger 方案:\n\n| 组件 | 用途 |\n|------|------|\n| OpenTelemetry SDK | Go 服务中埋点,生成 Trace/Span |\n| OTel Collector | 采集、采样、导出 |\n| Jaeger | 存储与可视化链路 |\n\n#### 8.3.2 采样策略\n\n| 场景 | 采样率 | 说明 |\n|------|--------|------|\n| 普通读接口 | 1% | 低优先级 |\n| 写接口(交易/拍卖) | 100% | 全量采集 |\n| 战斗接口 | 50% | 高频但需排查 |\n| 错误请求 | 100% | 全量采集 |\n| Kafka 消费 | 5% | 异步链路 |\n\n#### 8.3.3 Trace Context 传播\n\n所有服务间调用(gRPC / HTTP / Kafka Headers)统一传播 traceparent + tracestate header,格式遵循 W3C Trace Context。\n\n### 8.4 告警规则\n\n#### 8.4.1 紧急告警(P0,立即响应)\n\n| 告警名 | 条件 | 通知方式 |\n|--------|------|----------|\n| PostgreSQL 主库宕机 | pg_up == 0 持续 30s | 电话 + 企微 |\n| Valkey 全部不可用 | valkey_up == 0 所有实例持续 30s | 电话 + 企微 |\n| Nakama 全部实例不可用 | up{job=\"nakama\"} == 0 所有实例持续 30s | 电话 + 企微 |\n| 在线人数突降至 0 | honghuang_online_players == 0 且上一分钟 > 100 | 电话 + 企微 |\n| Kafka 所有 Broker 宕机 | kafka_brokers_up == 0 | 电话 + 企微 |\n\n#### 8.4.2 警告告警(P1,30 分钟内响应)\n\n| 告警名 | 条件 | 通知方式 |\n|--------|------|----------|\n| PostgreSQL 复制延迟 > 10s | pg_replication_lag > 10 | 企微 |\n| Valkey 内存 > 80% | valkey_used_memory / valkey_maxmemory > 0.8 | 企微 |\n| API P99 延迟 > 2s | histogram_quantile(0.99, api_request_duration) > 2 | 企微 |\n| Kafka 消费者 Lag > 10000 | kafka_consumergroup_lag > 10000 | 企微 |\n| 战斗服务错误率 > 5% | rate(battle_errors_total) / rate(battle_total) > 0.05 | 企微 |\n| 磁盘使用率 > 85% | node_filesystem_avail / node_filesystem_size < 0.15 | 企微 |\n\n#### 8.4.3 信息告警(P2,工作时间处理)\n\n| 告警名 | 条件 | 通知方式 |\n|--------|------|----------|\n| 异常货币产出 | rate(economy_faucet_total) > Nacos 配置阈值 | 企微 |\n| 排行榜刷新失败 | honghuang_rank_refresh_errors > 0 | 企微 |\n| 离线结算队列积压 | honghuang_settlement_queue_size > 1000 | 企微 |\n| Nacos 配置同步失败 | honghuang_config_sync_errors > 0 | 企微 |\n\n---\n\n## 9. 数据库连接池与读写分离\n\n### 9.1 PgBouncer 连接池\n\n| 配置项 | 值 | 说明 |\n|--------|-----|------|\n| 部署模式 | 独立 Pod,每服务端实例就近部署或共享 Pool | K8s 中以 Sidecar 或独立 Deployment 部署 |\n| 池模式 | transaction | 事务级连接复用,事务结束后归还 |\n| 默认池大小 | default_pool_size=50 | 每个 user/database 组合的最大连接数 |\n| 最大客户端连接 | max_client_conn=500 | 支持 500 个并发客户端连接 |\n| 最小空闲连接 | min_pool_size=10 | 保持 10 个预热连接 |\n| 连接超时 | connect_timeout=5s | 连接后端超时 |\n| 空闲超时 | idle_timeout=300s | 空闲连接回收 |\n| 查询超时 | query_timeout=30s | 单查询超时限制 |\n| 事务超时 | query_timeout=60s | 长事务超时(仅 transaction 模式生效) |\n| 服务端连接数上限 | PostgreSQL max_connections=400 | 留 100 给管理连接 |\n\n### 9.2 读写分离方案\n\n#### 9.2.1 架构\n\n\n ┌──────────────┐\n │ 应用服务 │\n └────┬────┬────┘\n │ │\n ┌──────────▼┐ ┌▼──────────┐\n │ PgBouncer │ │ PgBouncer │\n │ (Writer) │ │ (Reader) │\n │ 端口: 6432 │ │ 端口: 6433 │\n └─────┬──────┘ └─────┬──────┘\n │ │\n ┌───────▼──────┐ ┌─────▼──────────┐\n │ PG 主库 │ │ PG 同步从库 │\n │ (Writer) │ │ (Reader) │\n │ 192.168.1.10 │ │ 192.168.1.11 │\n └──────────────┘ └────────────────┘\n\n\n#### 9.2.2 读写分离策略\n\n| 操作类型 | 连接目标 | 说明 |\n|----------|----------|------|\n| 所有写操作(INSERT/UPDATE/DELETE) | 主库(PgBouncer Writer) | 经济变动、战斗结果、角色状态变更 |\n| 强一致读(交易确认前余额校验) | 主库(PgBouncer Writer) | 读已提交的最新数据 |\n| 普通查询(排行榜、背包列表、战报历史) | 从库(PgBouncer Reader) | 允许秒级延迟 |\n| 离线结算批量查询 | 从库(PgBouncer Reader) | 大批量扫描不影响主库 |\n| GM 后台查询 | 从库(PgBouncer Reader) | 运营查询不走主库 |\n\n#### 9.2.3 Go 代码层读写分离\n\n在 Go 服务中通过两个 *sql.DB 实例实现透明读写分离:\n\ngo\n// 数据库连接管理器\ntype DBManager struct {\n Writer *sql.DB // PgBouncer Writer (6432)\n Reader *sql.DB // PgBouncer Reader (6433)\n}\n\n// 读操作使用 Reader\nfunc (m *DBManager) QueryCharacter(ctx context.Context, id uuid.UUID) (*Character, error) {\n row := m.Reader.QueryRowContext(ctx, \"SELECT * FROM characters WHERE id = $1\", id)\n // ...\n}\n\n// 写操作使用 Writer\nfunc (m *DBManager) UpdateCurrency(ctx context.Context, charID uuid.UUID, code string, delta decimal.Decimal) error {\n _, err := m.Writer.ExecContext(ctx,\n \"UPDATE currency_balances SET amount = amount + $1 WHERE character_id = $2 AND currency_code = $3 AND amount + $1 >= 0\",\n delta, charID, code)\n // ...\n}\n\n\n#### 9.2.4 连接池监控指标\n\n| 指标 | 来源 | 告警阈值 |\n|------|------|----------|\n| PgBouncer 当前活跃连接 | SHOW POOLS → cl_active | > 400 |\n| PgBouncer 等待队列 | SHOW POOLS → cl_waiting | > 50 |\n| PostgreSQL 活跃查询 | pg_stat_activity WHERE state = 'active' | > 100 |\n| PostgreSQL 长事务 | pg_stat_activity WHERE duration > 60s | > 0 |\n| PostgreSQL 死锁 | pg_stat_database.deadlocks | > 0 |\n\n### 9.3 数据库连接配置\n\n#### 9.3.1 PostgreSQL postgresql.conf 关键参数\n\n| 参数 | 值 | 说明 |\n|------|-----|------|\n| max_connections | 400 | 最大连接数 |\n| shared_buffers | 8GB | 内存的 25% |\n| effective_cache_size | 24GB | 内存的 75% |\n| work_mem | 64MB | 排序/哈希操作内存 |\n| maintenance_work_mem | 2GB | VACUUM/CREATE INDEX 内存 |\n| wal_level | replica | 支持复制 |\n| max_wal_size | 4GB | WAL 上限 |\n| checkpoint_completion_target | 0.9 | 平滑 checkpoint |\n| random_page_cost | 1.1 | SSD 优化 |\n| effective_io_concurrency | 200 | SSD 并发 IO |\n| log_min_duration_statement | 200 | 慢查询日志阈值(ms) |\n\n#### 9.3.2 分区表自动维护\n\nsql\n-- 使用 pg_partman 自动管理分区\nCREATE EXTENSION pg_partman;\n\n-- battle_logs 按周分区\nSELECT partman.create_parent(\n p_parent_table := 'public.battle_logs',\n p_control := 'created_at',\n p_type := 'native',\n p_interval := '1 week',\n p_premake := 4 -- 预创建 4 周未来分区\n);\n\n-- 自动保留 8 周\nUPDATE partman.part_config\nSET retention = '8 weeks',\n retention_keep_table = false\nWHERE parent_table = 'public.battle_logs';\n\n\n---\n\n## 10. 已确认决策记录表\n\n| 编号 | 决策内容 | 关联 GDD/TDD | 日期 | 状态 |\n|------|----------|--------------|------|------|\n| TDD-01 ✅1 | 采用 Nakama 3.x 作为游戏服务器框架,承载认证/会话/实时推送/排行榜 | TDD-05 §2 | 2026-07-02 | 确认 |\n| TDD-01 ✅2 | Gin HTTP API 网关独立部署,承载 RESTful + gRPC-Gateway,与 Nakama 职责分离 | TDD-05 §2.1 | 2026-07-02 | 确认 |\n| TDD-01 ✅3 | 战斗模拟服务独立为 gRPC 微服务,支持水平扩展至 20 实例 | TDD-05 §3.3 | 2026-07-02 | 确认 |\n| TDD-01 ✅4 | 离线结算服务采用 Leader 选举模式,仅 Leader 执行定时扫描 | TDD-06 §2.1 | 2026-07-02 | 确认 |\n| TDD-01 ✅5 | 世界事件服务固定 3 实例,事件池状态在内存中维护 | GDD-22 | 2026-07-02 | 确认 |\n| TDD-01 ✅6 | 选用 Kafka 3.x KRaft 模式作为消息队列,3 Broker + 3 Controller | — | 2026-07-02 | 确认 |\n| TDD-01 ✅7 | Kafka Topic 按 world_tier 分区(12 分区),保证同层级事件顺序 | — | 2026-07-02 | 确认 |\n| TDD-01 ✅8 | 消息序列化统一使用 Protobuf,外层 Envelope 包含 event_id/trace_id | — | 2026-07-02 | 确认 |\n| TDD-01 ✅9 | Valkey 部署 3 主 3 从 + 3 Sentinel,淘汰策略 allkeys-lfu | — | 2026-07-02 | 确认 |\n| TDD-01 ✅10 | 缓存分三层:L0 进程内 ristretto / L1 Valkey / L2 PostgreSQL | — | 2026-07-02 | 确认 |\n| TDD-01 ✅11 | Key 命名规范 {service}:{entity}:{id}:{field},TTL 加 0~20% 随机偏移 | — | 2026-07-02 | 确认 |\n| TDD-01 ✅12 | 缓存穿透防护:布隆过滤器 + 空值缓存(TTL 60s) | — | 2026-07-02 | 确认 |\n| TDD-01 ✅13 | 缓存击穿防护:热点 Key 分布式互斥锁(SETNX,TTL 10s) | — | 2026-07-02 | 确认 |\n| TDD-01 ✅14 | PostgreSQL 部署 1 主 + 2 从(1 同步 + 1 异步),Patroni 自动 Failover | TDD-04 §2 | 2026-07-02 | 确认 |\n| TDD-01 ✅15 | 同步复制模式 synchronous_commit=on,零数据丢失 | — | 2026-07-02 | 确认 |\n| TDD-01 ✅16 | PgBouncer 事务级连接池,Writer/Reader 分离,Writer pool=50, Reader pool=100 | — | 2026-07-02 | 确认 |\n| TDD-01 ✅17 | 读写分离:写操作 + 强一致读走主库,普通查询/批量扫描走从库 | — | 2026-07-02 | 确认 |\n| TDD-01 ✅18 | Nakama 多实例通过 Valkey 共享状态,不直接互连 | — | 2026-07-02 | 确认 |\n| TDD-01 ✅19 | WebSocket 会话亲和性:按 session token SHA256 一致性哈希路由 | — | 2026-07-02 | 确认 |\n| TDD-01 ✅20 | 部署路径:Docker Compose (开发) → K8s 小集群 (公测) → K8s 全集群 (生产) | — | 2026-07-02 | 确认 |\n| TDD-01 ✅21 | K8s 命名空间隔离:honghuang-game / honghuang-infra / honghuang-monitor / honghuang-gm | — | 2026-07-02 | 确认 |\n| TDD-01 ✅22 | 监控方案:Prometheus + Grafana + ELK + Jaeger (OpenTelemetry) | — | 2026-07-02 | 确认 |\n| TDD-01 ✅23 | 日志格式统一 JSON,写入 stdout/stderr,Filebeat 采集 | — | 2026-07-02 | 确认 |\n| TDD-01 ✅24 | 链路追踪采样:写接口 100%,战斗 50%,读接口 1%,错误 100% | — | 2026-07-02 | 确认 |\n| TDD-01 ✅25 | 告警分级:P0 电话+企微 / P1 企微 / P2 企微(工作时间) | — | 2026-07-02 | 确认 |\n| TDD-01 ✅26 | 降级策略:DB 不可用 → 只读模式;Valkey 不可用 → 直读 DB;Kafka 不可用 → 本地定时器 | — | 2026-07-02 | 确认 |\n| TDD-01 ✅27 | 经济数据强一致:乐观锁原子更新 + economy_audit_logs 全量审计 | TDD-04 §5.4 | 2026-07-02 | 确认 |\n| TDD-01 ✅28 | 分区表自动维护使用 pg_partman,保留策略见 TDD-04 §6.2 | TDD-04 §6.2 | 2026-07-02 | 确认 |\n| TDD-01 ✅29 | 接入层使用 OpenResty/Traefik,TLS 终止 + L4/L7 路由 + 限流 | TDD-05 §2.5 | 2026-07-02 | 确认 |\n| TDD-01 ✅30 | 本地端口规划遵循本文 §2.4,多实例偏移 +1000 | — | 2026-07-02 | 确认 |\n\n---\n\n## 11. 验收标准\n\n| # | 验收条目 | 测试方法 | 通过标准 |\n|---|----------|----------|----------|\n| 1 | Docker Compose 一键启动全部服务 | docker compose up -d 后执行健康检查 | 所有服务 healthy,Nakama /healthcheck 返回 200 |\n| 2 | Nakama 双实例负载均衡 | 启动 2 个 Nakama 实例,客户端连接后检查 WebSocket 分布 | 连接分布在两个实例上 |\n| 3 | Nakama 单实例故障后客户端自动重连 | 手动 kill 一个 Nakama 容器 | 客户端 30s 内自动重连到存活实例 |\n| 4 | PostgreSQL 主从切换 | 停止主库容器 | Patroni 在 30s 内将同步从提升为新主,应用自动重连 |\n| 5 | Valkey 故障转移 | 停止 Valkey 主节点 | Sentinel 在 60s 内完成切换,客户端透明重连 |\n| 6 | Kafka Broker 宕机不影响生产/消费 | 停止一个 Kafka Broker | 其余 Broker 正常处理消息,消费者自动重平衡 |\n| 7 | 缓存穿透防护 | 请求不存在的 character_id | 布隆过滤器拦截,不回源 DB;后续请求命中空值缓存 |\n| 8 | 缓存击穿防护 | 大量并发请求同一热点 Key(如排行榜) | 仅 1 个请求回源 DB,其余等待或返回旧值 |\n| 9 | 读写分离正确性 | 写入后立即从从库读取 | 强一致读走主库返回最新数据;普通读允许秒级延迟 |\n| 10 | 经济操作并发安全 | 并发执行 100 次货币扣减 | 最终余额正确,无超扣;所有操作写入 economy_audit_logs |\n| 11 | 链路追踪完整性 | 发起一次战斗请求,检查 Jaeger | 从客户端请求到 DB 写入的完整 Trace 链路可见 |\n| 12 | Prometheus 指标采集 | 访问 http://localhost:9090/targets | 所有 target 状态为 UP |\n| 13 | 告警触发 | 模拟 Nakama 全部实例不可用 | 30s 内收到企微/电话告警 |\n| 14 | 日志聚合 | 执行一次战斗,检查 Kibana | 可搜索到对应 trace_id 的日志链路 |\n| 15 | 分区表自动创建 | 等待 pg_partman 调度或手动执行 | battle_logs 新分区自动创建,旧分区自动清理 |\n| 16 | 降级模式验证 | 停止 Valkey,发起 API 请求 | 功能正常但响应变慢(500ms+),日志记录降级事件 |\n\n---\n\n## 12. 版本记录\n\n| 版本 | 日期 | 作者 | 变更说明 |\n|------|------|------|---------|\n| 1.0 | 2026-07-02 | 技术架构师 | 初稿:完成服务拓扑、水平扩展、消息队列、缓存策略、容灾、部署、监控、连接池、决策记录、验收标准等 10 大章节 |\n\n---\n\nTDD-01 v1.0 | 2026-07-02 | 服务端整体架构设计\n```\n\n---\n\nThe complete TDD-01 document is provided above. Key highlights of what was produced:\n\nSection 2 - Service Topology: Full ASCII topology diagram showing all services (Nakama cluster, Gin HTTP API gateway, battle simulation, offline settlement, world events, GM/operations), their ports, call relationships, and degradation strategies. Port planning table covers 20+ ports from 443 to 9200.\n\nSection 3 - Horizontal Scaling: Nakama multi-instance deployment with session affinity (SHA256 consistent hashing on session token), state synchronization via PostgreSQL/Valkey/Kafka (no direct inter-instance communication), and scaling trigger conditions (5000 WS connections, 70% CPU, etc.).\n\nSection 4 - Message Queue: Kafka 3.x KRaft mode with 8 Topic designs (world.events, battle.settled, economy.audit, etc.), Protobuf message envelope format, 4 consumer groups, and reliability guarantees (idempotent producer, manual commit, DLQ).\n\nSection 5 - Cache Strategy: 3-layer caching (L0 in-process ristretto, L1 Valkey, L2 PostgreSQL), 20+ Key patterns with naming convention {service}:{entity}:{id}:{field}, protection against cache penetration (bloom filter + null caching), avalanche (TTL randomization), and breakdown (distributed mutex).\n\nSection 6 - Disaster Recovery: PostgreSQL Patroni auto-failover (RTO < 30s), Valkey Sentinel failover (RTO < 60s), Kafka 3-broker replication, and 5 degradation scenarios with specific user-facing behavior.\n\nSection 7 - Deployment: Full Docker Compose YAML for local dev, K8s production spec (14 nodes across 4 worker types), namespace separation, and 4-phase evolution path from 100 to 200,000+ concurrent users.\n\nSection 8 - Monitoring: Prometheus metrics (12 business + infrastructure metrics), ELK log aggregation (JSON format, 3 index tiers), OpenTelemetry + Jaeger tracing with differentiated sampling rates, and 3-tier alerting (P0/P1/P2).\n\nSection 9 - Database Connection Pool: PgBouncer transaction-mode pooling (Writer/Reader separation), Go code-level read/write routing, PostgreSQL 16 postgresql.conf tuning parameters, and pg_partman automated partition maintenance.\n\nSection 10 - Decision Records: 30 confirmed decisions (TDD-01 1 through TDD-01 30).\n\nSection 11 - Acceptance Criteria: 16 verifiable items covering one-click startup, load balancing, failover, cache protection, read/write splitting, tracing, alerting, and degradation."}],"usage":{"input_tokens":1993,"cache_creation_input_tokens":0,"cache_read_input_tokens":54208,"output_tokens":16518,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"stop_reason":"end_turn","stop_details":null},"attributionAgent":"Explore","type":"assistant","uuid":"5cbf5c05-49a9-416e-ac11-c8e8c2c07d64","timestamp":"2026-07-02T00:16:56.010Z","userType":"external","entrypoint":"cli","cwd":"/Users/xuqinmin/Projects/NewsProject/lawless","sessionId":"e62c4dc2-f8c6-4de1-bb50-390f2075d2b9","version":"2.1.197","gitBranch":"main"}