文章

Bug:积分存盘域扩容导致7321个用户读写存档失败

Bug:积分存盘域扩容导致7321个用户读写存档失败

合理更新流程的梳理见文档《2025-07-04-积分域扩容流程梳理.md》

背景:

班车赛存盘积分域为 22 位,2025年6月要上线 “挥镐掘金” 业务,在该业务场景下,22 位的存盘积分域不能满足需求,需要对班车赛存盘域进行扩容。

经讨论,汇总了 687 个存盘积分域 id(班车赛的),需从 22 位扩容至 50 位(50 是为了一步到位,避免以后重复操作)。

在扩容过程中,因为历史原因,出现了一些报错,现将存档积分扩容的流程和注意事项总结在此,方便以后操作时参阅。

操作日志:

  • 2025年6月20日周五下午 在内网操作更新并获得了扩容后的 define_nostag_jgbc 的 csv 表。
  • 2025年6月20日周五19:26 外网使用 DELETE 语句清空目标表,然后再导入 csv ,但9个积分域校验未通过
  • 2025年6月20日周五19:36 外网的 define_nostag_jgbc 中的配置问题解决了,更新成功
  • 2025年6月20日周五21:06 唐成龙给我打电话说他那边在疯狂打日志,是扩容导致的
  • 2025年6月20日周五21:17 外网的 jgbc 都回退了
  • 2025年6月20日周五晚上 统计出来受影响的用户名单,一共有 7321 个用户。
  • 2025年6月21日周六上午 给所有用户退费成功
  • 2025年6月24日周二11:50 更新了 define_nosdata_jgbc,添加了所有需要新增的存盘积分
  • 2025年6月25日周三16:18 与唐成龙沟通,测试了 11 个积分域,evt扩容 + cmt增加映射
  • 2025年6月26日周四09:59 扩容了剩下的所有积分域,evt扩容 + cmt增加映射
  • 2025年6月26日周四15:03 客服反馈有一些比赛存档进入游戏有问题,经查是因为客户端存在存盘域积分映射数量检查导致的,evt 与 cmt 同时回退。
  • 2025年6月26日周四15:33 客服反馈有的用户存档丢失,经查是因为 evt 回退后,cmt 还会按照 50 个积分向里写入,导致写入失败。唐成龙提取了用户失败名单,向用户退费。

EVT的问题和现象:

  • 有一台 NOS 刚好在 define_nostag_jgbc 表为空时拉取了一下 CVS;
  • 这台 NOS 获取到了格式正确、但是数量为 0 的 tag 配置;
  • 此时,外部仍需要读写存盘积分域;
  • 但因为 tag 配置是空的,所以会有 “无目标 tag” 的报错,错误码 509;
  • 最终一共导致 7321 个用户请求失败。
  • 造成损失折合人民币大概 8W 左右。

反思:

  • 以后 不要删表!尤其是线上正在使用的表!这是非常危险的操作!!
  • 以后需要通过 csv 覆盖式更新 MySQL 表时,选择 “REPLACE INTO” 选项即可。

相关内容:直接用 csv 插入到 MySQL 表格时的选项:

选项介绍

  • <None>:(默认选项)

    • 行为:遇到重复主键或唯一索引时,整批插入失败并回滚。
    • 适用场景:确保数据严格唯一,不允许任何冲突。
    • 风险:若数据中存在一条重复记录,所有插入都会失败。
  • ON DUPLICATE KEY UPDATE

    • 行为:冲突时执行 UPDATE,用新数据覆盖旧记录。

    • 适用场景:需要定期同步数据,更新已有记录的部分字段。

    • 示例:

      1
      2
      
      INSERT INTO users (id, name, age) VALUES (1, 'Alice', 25)
      ON DUPLICATE KEY UPDATE name = 'Alice', age = 25;
      
  • INSERT IGNORE
    • 行为:冲突时跳过当前行,继续处理后续数据(静默忽略错误)。
    • 适用场景:批量导入中允许部分重复数据,如日志记录、临时表。
    • 示例:

      1
      
      INSERT IGNORE INTO users (id, name) VALUES (1, 'Alice'), (2, 'Bob');
      
  • REPLACE INTO
    • 行为:冲突时先删除旧记录,再插入新数据(主键不变,其他字段被覆盖)。
    • 适用场景:需要完全替换旧记录,而非部分更新。
    • 示例:

      1
      
      REPLACE INTO users (id, name, age) VALUES (1, 'Alice', 25);
      

对比表格

选项 冲突时操作 数据保留 性能影响
NONE 整批失败 所有旧数据保留 最低
ON DUPLICATE KEY 更新冲突行 保留旧数据中未更新字段 中等
INSERT IGNORE 跳过冲突行 所有旧数据保留 较低(需唯一索引)
REPLACE INTO 删除+插入 仅保留新数据 较高(涉及两次操作)

选择建议

  • 数据同步:用 ON DUPLICATE KEY UPDATE,只更新变化的字段。
  • 日志/临时数据:用 INSERT IGNORE,允许重复记录存在。
  • 全量覆盖:用 TRUNCATE TABLE + 导入,确保数据一致性。
  • 严格唯一:用 NONE,配合事务回滚保证原子性。

注意事项

  1. 性能考量REPLACETRUNCATE 会触发索引重建,大数据量时慎用。
  2. 外键约束TRUNCATE 会清空表,可能影响关联表数据。
  3. 唯一索引:除主键外,其他唯一索引冲突也会触发替换逻辑。

相关内容:

(1)评估结论:

将 700 个存盘积分域中的积分从 22 个扩容至 50 个,不会产生明显的读写延迟下降等异常现象。

(2)jgbc 集群现状:

redis 集群现状:(matchsave-001-redis)(2025年6月6日)

image-20250606145324658

redis 集群表现:(24h内)

image-20250606145446321

EVT-HEB 时延表现:(24h内)

image-20250606145011148

EVT-HEB 查询量统计:(24h内)

image-20250606145052292

本文由作者按照 CC BY 4.0 进行授权