这个系列是我对「一套游戏发行技术平台该怎么设计」的完整梳理,基于我在游戏发行公司实际做过的系统整理而成(已脱敏,不含任何公司数据与配置)。

每章按四段展开:业务背景 → 方案设计 → 关键取舍 → 真实经验。最后一段是我实际踩过的坑,也是这份方案区别于模板的地方。

本篇是第一篇:总体架构。


一、业务背景

发行业务的技术链路

游戏发行不是「把游戏做出来」,而是「把游戏卖出去」。技术侧要支撑的是一条从投放开始的完整链路:

flowchart LR
    A[广告投放<br/>巨量 / 腾讯 / 快手] --> B[落地页 / 渠道包]
    B --> C[激活]
    C --> D[注册 / 登录]
    D --> E[创角]
    E --> F[充值]
    C -.归因回传.-> A
    D -.归因回传.-> A
    F -.归因回传.-> A

这条链路上,技术要解决四类问题:

# 诉求 为什么重要
1 低延迟 注册 / 登录接口直接影响转化率——用户多等一秒,可能就流失了
2 不丢不重 归因回传决定投放结算,少回传一条就是白花的钱,重复回传是脏数据
3 数据要快 投放团队要按天(甚至按小时)看 ROI 来调整计划,报表慢了就没意义
4 成本可控 发行公司技术团队通常很小,要的是「少组件、少运维」而不是「架构炫技」

另外还有一类刚性约束:合规。国内游戏必须做实名认证与防沉迷,这不是可选项。

一个关键的认知

发行系统的复杂度不在并发量,而在业务链路的完整性。

一家日活几千的发行公司,接口量可能只有每天几十万次请求——这个量级随便一台机器都扛得住。但链路上一环断了(比如支付回调没收到、归因没回传),业务就直接受损。

所以设计的重心应该放在「链路完整、可追溯、可配置」,而不是「极限性能」。 这个判断贯穿整个方案。


二、方案设计

2.1 系统分层

flowchart TB
    subgraph "接入层"
        SDK[游戏客户端 SDK<br/>Android / iOS]
        PAGE[SDK 页面<br/>支付页 / 协议页 / 授权页]
    end

    subgraph "网关层"
        LB[Nginx / 负载均衡]
    end

    subgraph "应用层"
        SAPI[SDK API<br/>注册登录 / 支付 / 日志上报 / 配置]
        EAPI[对外 API<br/>CP 会话验证 / 点击监控 / 支付回调]
        AAPI[管理后台 API<br/>游戏配置 / 数据查询 / 权限]
        QW[队列任务<br/>发货通知 / 异常告警 / 数据回传]
        TS[定时任务<br/>日报统计 / 数据聚合]
    end

    subgraph "数据层"
        MYSQL[(MySQL<br/>OLTP 业务库)]
        REDIS[(Redis<br/>缓存 / 队列)]
        DORIS[(Doris<br/>OLAP 分析层)]
    end

    SDK --> LB
    PAGE --> LB
    LB --> SAPI
    LB --> EAPI
    LB --> AAPI
    SAPI --> MYSQL
    SAPI --> REDIS
    EAPI --> MYSQL
    EAPI --> REDIS
    AAPI --> MYSQL
    QW --> MYSQL
    TS --> MYSQL
    MYSQL -->|实时同步| DORIS

分层的核心思路:业务接口和管理接口分开,交易和分析分开。

  • SDK API 面向玩家,要求低延迟、高可用;管理后台 API 面向内部运营,可以复杂查询但绝不能影响玩家侧
  • MySQL 扛交易,Doris 扛分析——两者的查询模式完全不同,混在一套库里,报表一跑就把交易接口拖慢
  • Redis 同时承担缓存和队列——规模没到需要独立消息中间件的程度,少一个组件就少一份运维成本

2.2 业务模块划分

系统按业务域拆成六个模块,每个模块有独立的文档入口和唯一的数据/接口源头:

模块 职责 关键设计
auth 登录、注册、SDK 初始化、游戏用户创建 游戏级用户 ID;注册 / 支付开关(可按游戏关闭)
payment H5 支付、渠道路由、结算、原生内购与退款账本 多渠道可路由,后台可切换
attribution 广告点击追踪、归因匹配、转化回传 缓存优先归因,降低回传延迟
analytics 日报、ROI、留存、LTV、事实表 宽表事实表 + 分层报表
game-config 游戏开关、扩展配置、广告包、落地页 全部配置化,运营自助,不发版
admin-rbac 角色、权限、菜单树、数据权限 RBAC + 数据域隔离

这里有个容易被忽略的设计:auth 和 payment 都挂了「游戏开关」——disable_reg、disable_pay 这类标记位。

为什么?因为发行运营中经常需要临时关掉某款游戏的注册或支付(版号问题、渠道问题、活动结束)。如果每次都要发版改代码,响应速度根本跟不上。做成配置开关后,运营在后台点一下就能生效。

2.3 规格驱动的设计方法

这是整套方案里我认为最有价值的部分。

系统有 17 个 API 端点(7 个日志上报、注册登录、支付、实名认证、广告等),如果每个功能各写各的,很快就会出现同名字段不同含义、重复定义、契约漂移。

所以采用了分层规格约束:

flowchart TB
    C["Level 0 宪法级<br/>全局约束与原则"]
    S["Level 0 系统级<br/>统一数据模型 / API 契约 / 技术标准"]
    F1["Level 1 功能级<br/>端点 A"]
    F2["Level 1 功能级<br/>端点 B"]
    F3["Level 1 功能级<br/>端点 C"]

    C --> S
    S --> F1
    S --> F2
    S --> F3
    F1 -. "新增定义同步回全局" .-> S
    F2 -. "新增定义同步回全局" .-> S

规则很硬:

  1. 数据模型和 API 契约只能有一个源头——一个 schema 文件 + 一份 OpenAPI 契约
  2. 功能规格严禁定义新表、新接口——只能引用全局定义,或扩展后同步回全局
  3. 同步必须在实现之前完成——不允许「先写代码,回头再补契约」

这条约束在多端点并行开发(尤其是有 AI 参与开发)时价值最大:契约不漂移,多个实现才不会互相打架。

2.4 技术选型

层 选型 选择理由
后端框架 Laravel 11(PHP 8.2) 生态成熟、开发效率高;配合常驻内存运行时解决 PHP 的性能短板
业务库 MySQL 8.0 OLTP 场景的标准选择,事务可靠
分析引擎 Apache Doris 列存 + MPP,适合宽表聚合;运维复杂度远低于自建 Hadoop 体系
缓存 / 队列 Redis 缓存和队列用同一套,少一个组件
Web 服务器 Nginx JSON 格式访问日志,便于采集
管理后台 React 18 + Vite + TDesign 中台组件库,表格和表单场景开箱即用
客户端 SDK Kotlin(Android)/ Swift(iOS) 原生语言,渠道 SDK 对接友好
数据同步 云厂商 DTS 实时同步 业务代码零侵入

三、关键取舍

决策 选择 放弃的方案 理由
交易与分析 MySQL + Doris 分离 一套库跑所有 报表聚合会拖慢交易接口,且分析查询不可控
数据同步 云厂商 DTS 实时同步 业务代码双写 双写要在每个写入点加代码,容易漏;同步是配置级的
事实表位置 *_facts 只在 Doris MySQL 也建一份 分析表放 OLAP,MySQL 不背这个包袱
消息队列 Redis list 独立消息中间件 当前规模不需要,少一个组件少一份运维
配置管理 游戏开关 + 扩展配置 每次改代码发版 运营自助,响应速度差一个数量级
日志策略 全量请求 / 响应审计 只记错误日志 API 业务「请求过了就什么都没有」,日志是唯一现场
错误码 分段编码(1xxx 认证 / 2xxx 参数 / 3xxx 业务 / 4xxx 权限 / 5xxx 系统) 单一通用错误码 客户端能按段做统一处理,定位更快

关于「不用独立消息中间件」这个取舍值得多说一句:这不是说 Redis 队列比专业 MQ 好,而是说在日活几千的规模下,多引入一个组件的运维成本大于它带来的收益。如果哪天量级上来了,换成专业 MQ 只是替换队列驱动,不影响业务代码结构。


四、真实经验

设计做完不算完,这几条是实际做下来才真正体会到的:

1. 契约先行不是形式主义,是并行开发的前提

一开始觉得「先写文档再写代码」拖节奏。但端点数量一多(再加上 AI 参与编码),问题立刻暴露:同一个概念在两个端点里字段名不一样、同一个字段两处定义类型不同。

把 schema 和 API 契约定为唯一源头之后,冲突基本消失——因为所有人都只能从同一个地方取定义。这个约束对 AI 辅助开发尤其重要:AI 不会「记得」上一次的约定,但会严格按你给的契约写。

2. 审计日志要一开始就做,不能事后补

后期的日志最大的问题是串不起来:出了问题想看「这个用户从请求到落库发生了什么」,结果发现关键路径没有统一的 request_id。

所以正确的做法是一开始就强制:所有接口带 request_id,请求参数和响应数据全量落 JSONL 审计文件。代价是存储和一点性能,收益是任何业务问题都能回溯。

3. 「同步」比「双写」省事得多

最早考虑过业务写入时双写分析库,后来改成数据库层实时同步。差别很大:

  • 双写:每个业务写入点都要加代码,漏一处就是数据不一致,且事务边界很难处理
  • 同步:配置级,业务代码零侵入,出问题只查同步链路

能用基础设施解决的问题,不要用业务代码解决。

4. 配置化是小团队的救命稻草

发行运营的需求变化极快:今天要关某款游戏的注册,明天要切支付渠道,后天要上新的落地页。

如果这些都走「提需求 → 开发 → 测试 → 发版」,一个需求就是几天。做成配置后,运营自己就能搞定。小团队的人力,必须花在真正需要写代码的地方。


下一篇

(二)SDK 接入层:两级身份模型、游戏级开关、多端登录、支付链路的可靠性设计 → 继续阅读


本文基于实际项目整理,已脱敏。文中不含任何公司业务数据、配置或凭据。