Files
game_server/DEVICE_ALLOCATION_IMPROVEMENTS.md

4.2 KiB
Raw Permalink Blame History

设备分配并发竞争问题解决方案

问题描述

在游戏平台服务器中发现了设备分配的并发竞争条件问题,导致多个用户同时选区时可能被分配到同一个设备。

具体表现

  • 两个用户L789AT98、LPUEL6XM几乎同时相差400ms进行选区操作
  • 都被分配到了相同的设备 xx1
  • 由于时序问题,冷却机制未能有效防止重复分配

根本原因分析

  1. 并发竞争条件:设备检查和占用不是原子操作
  2. 选择算法单一:总是选择第一个可用设备,增加了冲突概率
  3. 时序问题:冷却机制在设备分配之后才生效
  4. 缺少验证机制:分配后没有冲突检测和回滚

解决方案

1. 原子设备分配机制

新增方法:MemoryMachineCooldownService.tryAllocateDevice()

  • 功能:原子方式检查设备状态并立即加入冷却队列
  • 特点:使用设备级锁确保线程安全
  • 效果:防止多个请求同时分配同一设备
public boolean tryAllocateDevice(String machineId, String reason, Long linkTaskId)

新增方法:MemoryMachineCooldownService.releaseDeviceAllocation()

  • 功能:释放设备分配(用于失败回滚)
  • 验证:确保只有原分配任务才能释放

2. 设备分配服务 (DeviceAllocationService)

核心功能

  • 负载均衡:随机打乱设备列表,避免总是选择第一个设备
  • 原子分配:使用新的原子分配方法
  • 冲突检测:过滤被其他任务占用的设备
  • 验证机制:分配后双重检查是否存在冲突

关键方法

public String allocateDevice(List<String> availableDevices, Long linkTaskId, String reason)
public boolean validateDeviceAllocation(String deviceId, Long linkTaskId)
public void releaseDeviceAllocation(String deviceId, Long linkTaskId)

3. 增强的安全检查

多层防护机制

  1. 分配前检查:过滤冷却期和被占用设备
  2. 原子分配:确保分配操作的原子性
  3. 分配后验证:检测是否存在分配冲突
  4. 异常回滚:失败时自动释放设备分配

异常处理改进

  • 脚本调用失败时自动释放设备分配
  • 数据库更新失败时回滚设备状态
  • 冲突检测失败时完整回滚操作

改进效果

性能优化

  • 负载均衡:设备选择更均匀,减少热点设备竞争
  • 并发安全:使用设备级锁,避免全局锁竞争
  • 快速失败:原子检查快速排除不可用设备

可靠性提升

  • 原子操作:消除设备分配的竞争条件
  • 冲突检测:多层验证确保分配唯一性
  • 自动回滚:异常情况下自动恢复一致状态

可维护性增强

  • 清晰日志:详细记录分配过程和冲突检测
  • 模块化设计:设备分配逻辑独立为专门服务
  • 故障恢复:支持手动释放设备分配

使用场景

首次选区

  1. 获取空闲设备列表
  2. 调用 DeviceAllocationService.allocateDevice() 进行原子分配
  3. 进行脚本调用和数据库更新
  4. 验证分配结果,失败时自动回滚

重复选区

  • 复用已分配设备,不重复分配
  • 验证设备是否仍然可用

测试验证

并发测试

  • 模拟多个用户同时选区
  • 验证不会出现设备重复分配
  • 检查冲突检测和回滚机制

异常测试

  • 脚本调用失败场景
  • 数据库更新失败场景
  • 验证回滚机制有效性

监控建议

关键指标

  • 设备分配成功率
  • 冲突检测次数
  • 回滚操作频率
  • 设备利用率分布

告警设置

  • 设备分配冲突告警
  • 回滚操作频繁告警
  • 设备池不足告警

注意事项

  1. 向后兼容:保留了原有的冷却机制
  2. 性能影响:增加了验证步骤,但提升了可靠性
  3. 内存管理:定期清理过期的冷却记录
  4. 并发限制:基于内存的锁机制,适用于单实例部署

后续优化建议

  1. 分布式锁如需多实例部署考虑使用Redis分布式锁
  2. 设备预分配:预先为用户分配设备,减少实时分配压力
  3. 智能调度:基于历史数据和设备负载进行智能分配
  4. 故障转移:设备故障时自动切换到备用设备