灰度发布与热更新
概述
游戏不能随便停服:每停服一分钟都是损失。灰度发布让新版本只影响小部分玩家,问题可控制可回滚;配置热更新让数值调整不用重启;不停服维护让代码升级对玩家无感。本文讲清楚灰度、热更新与优雅关闭的完整方案。
一、灰度发布策略
1.1 灰度方式
灰度维度(选一个或多个):
按玩家:白名单(内测玩家/内部账号)
按比例:随机 N% 玩家走新版本
按群体:新用户走新版本,老用户走旧版本
按渠道:指定渠道/区服灰度
灰度节奏:
1% → 5% → 20% → 50% → 100%(全量)
每档观察指标(异常率/在线/收入)达标再放量
任一档异常 → 立即回滚// 灰度判定(网关路由到新/旧节点)
boolean isGray(long playerId) {
// 白名单优先
if (grayList.contains(playerId)) return true;
// 按比例:hash 取模进灰度池
return (playerId % 100) < grayPercent;
}1.2 灰度发布基础设施
灰度发布需要:
服务编排:K8s / 发布平台(多版本并存)
路由规则:网关按灰度标记转发
数据兼容:新旧版本可共存(字段兼容/双写)
监控对比:新旧节点指标分列(见监控章节)
快速回滚:一键回退(旧版本镜像保留)// 版本兼容原则
// 新旧代码同时跑,协议/数据结构向后兼容
1. 协议字段只增不改(见协议章节)
2. 数据库变更先加字段后启用(兼容读写)
3. 新旧节点共享 Redis/DB(数据无分叉)二、游戏配置热更新
2.1 热更新目标
热更新的意义:
数值调整(活动加成、掉落概率)不用重启
配置错误秒级修复
运营活动即时生效
热更新范围:
数值配置:概率、价格、倍率、上限
功能配置:开关、活动配置、公告
代码:不能热更(需发布流程,见 CI/CD)// 配置读取(每次读取查缓存,避免热更不生效)
public int getDropRate(int itemId) {
Config conf = configCache.get("drop", itemId);
return conf.intVal("rate"); // 缓存实时刷新
}2.2 配置中心
配置中心选型:
Apollo / Nacos:成熟、可视化、推送实时
Redis + 自研:轻量(量小够用)
Apollo 用法:
配置中心管理配置项
修改后推送到各服务(长轮询/消息)
服务本地缓存 + 实时更新
变更留痕 + 灰度发布配置// Apollo 变更监听(热更新)
@ApolloConfigChangeListener("game.config")
public void onConfigChange(ConfigChangeEvent event) {
configCache.reload(event.changedKeys()); // 刷新缓存
log.info("config hot updated: {}", event.changedKeys());
}// 配置正确性保障
1. 配置校验(发布前 schema 校验)
2. 配置版本号(客户端/服务端同步)
3. 配置灰度(按区服/渠道分批下发)
4. 回滚(一键还原上一版本)三、不停服维护方案
3.1 滚桶发布(滚动更新)
不停服更新(滚动):
K8s RollingUpdate:逐批替换 Pod
一批就绪 → 下一批(maxUnavailable 控制)
玩家连接被切 → 自动重连到新节点(网关路由)
关键:
玩家会话要能迁移或重连(见会话章节)
对局中的房间不能中途杀掉// K8s 滚动更新
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 一次最多停 1 个
maxSurge: 1 # 一次最多多起 1 个3.2 对局内玩家保护
对局保护:
对局中的房间延迟释放(更新不杀活跃房间)
强制维护前提前通知(广播维护公告)
维护期间不创建新房间
断线重连(维护后玩家可回房/补偿)
流程:
1. 发公告:维护时间(提前 X 分钟)
2. 停止匹配:新对局不再开
3. 等对局结束:存量对局自然结算
4. 释放剩余连接:优雅关闭四、旧连接优雅关闭
4.1 优雅关闭流程
优雅关闭(应用退出):
1. 停止接收新请求(摘除路由/标记下线)
2. 等待存量请求处理完成(超时上限)
3. 通知在线玩家(推送"维护/重连"提示)
4. 保存玩家状态(落库)
5. 关闭资源(DB 池/Redis/MQ 消费停止)
6. 进程退出// Spring 优雅停机
server.shutdown: graceful
spring.lifecycle.timeout-per-shutdown-phase: 30s
// 或 JVM 钩子手动处理
Runtime.getRuntime().addShutdownHook(() -> {
gateway.drain(); // 停止新请求
playerService.saveAll(); // 保存在线玩家
executor.shutdown(); // 等待任务
});4.2 连接排空
连接排空要点:
网关摘流:从注册中心摘除(不再路由新连接)
存量连接:发维护消息 → 关闭(或等待断开)
重连引导:客户端重连到其他节点
会话状态:全局会话(Redis)让新节点接管
超时兜底:
优雅关闭有超时(如 30s)
超时未完成 → 强制终止(防卡死)// 网关摘流(服务发现下线)
registry.deregister(gatewayNode);
// 新连接不再路由到本节点
// 存量连接走正常退出流程五、实现要点
灰度与热更新核心:
灰度发布:白名单/比例 → 分档放量 → 可回滚
配置热更新:配置中心 + 缓存实时刷新 + 校验回滚
不停服维护:滚动更新 + 对局保护 + 公告引导
优雅关闭:摘流 → 排空 → 保存 → 退出(超时兜底)
常见坑:
灰度比例写死 → 无法分档
配置无校验 → 错误配置全服生效
直接 kill 进程 → 玩家数据丢失
旧节点硬杀 → 对局中断投诉
与其他系统衔接:
服务编排 → 容器化/K8s 章节
配置中心 → 架构配置管理章节
发布流水线 → CI/CD 章节
监控对比 → 实时监控章节