MeteorCat / 记录一次T0事故现场

Created Sat, 01 Mar 2025 00:24:07 +0800 Modified Wed, 29 Oct 2025 23:25:05 +0800
956 Words

事故起源其他游戏服务端开发程序开发的时候, 可能为了测试游戏功能临时屏蔽数据上报模块代码从而导致上报数据不完整, 但是在提交游戏功能的时候连带将这部分屏蔽上功能一起同步; 而负责 Code Review 的老司机在更新业务代码的时候没有留意到这部分异常的上报模块, 随即同步到正式服上导致代码同步正式服务器差不多两天的时候上报统计数据模块服务直接告警数据全部关联不上数据.

我们数据上报采用第三方私有部署的 kafka 服务, 主要上报数据问题集中在屏蔽的那部分上报代码缺失玩家 player_id, 体现在统计系统上面就是数据异常归因从而影响整个运营统计功能的正常运行.

不过不幸中的万幸就是上报虽然丢失 玩家ID(player id) 的唯一关联, 但是幸好内部还有 服务器ID(sid) + account(账号信息), 通过两个字段可以反查 玩家ID(player id) 将数据修改重新修正更新上报应该就没有太大问题了, 但是事情真的能够这么顺利吗?

当时计划采用的修复方案如下:

  • 创建 kafka 结果保存临时表
  • 通过匹配字段JSON关键字导出数据到临时表
  • 最后本地导出这些临时表下载本地用脚本修复重新补充 player_id 上报

看起来很理想的方案但实际操作就是一场灾难, 从上报事件的设计到导出数据都充满了苦涩, 总结起来就是以下问题:

  1. 导出丢失的游戏单天道具流水记录将近快 100GB+, 甚至都快把服务器硬盘空间撑爆
  2. 字段内部采用 JSON 格式保存, 只能采用 LIKE '%event:item_change%' 方式模糊匹配筛选数据
  3. 数据散乱在 kafka 不同节点上联合查询, 没办法直接单体数据这样 UPDATE, 只能重新上报附带 uuid 让其更新数据, 上报数据量惊人

另外必须要说下我最讨厌的命名方式: change_itemchange_items 类似事件单复数命名, 在文本和日志做匹配如 WHERE field LIKE '%change_item%'file.log| grep change_item 简直就是大灾难,

最开始还以为能够轻松解决, 直到去趟厕所回来服务器提示 No space left on device, 服务器告警直接硬盘空间快满了.

游戏道具变动数据是很惊人, 一分钟都可能产生 GB 级别的数据, 这个时候就知道修复这些异常数据没这么简单了:

  1. 重新网络提交上报走 Web 请求, 网络单次上报差不多 2M 的数据量, 这堆丢失数据按照每次 2M 上报的情况不知道什么时候修复上报完
  2. 导出的临时表数据拉回本地(不压缩)也是个大文件, 哪怕疯狂压缩在导出本地都是在占用本地空间和CPU

这次问题就是标准的 T0级别事故, 目前只能没什么太好办法, 只能蚂蚁搬家一样慢慢对数据进行修复;
得亏及时发现, 要不然等到 TB 级别的数据异常的情况, 那时候修复真的就是超级大工程.