共计 1995 个字符,预计需要花费 5 分钟才能阅读完成。
背景与痛点
在游戏开发或技能系统中,Skill 脚本的重复执行是一个常见但危害严重的问题。典型的重复执行场景包括:

- 网络延迟导致的重发 :客户端因未及时收到响应而重复发送请求
- 并发触发 :多个事件同时触发同一技能脚本
- 逻辑分支误判 :条件判断不严谨导致重复进入执行流程
这些情况会导致:
- 游戏状态不一致(如技能效果叠加)
- 资源浪费(CPU/ 内存 / 网络带宽)
- 不可预期的副作用(如成就多次解锁)
技术方案对比
常见的去重方案各有优缺点:
时间戳校验
- 原理 :记录最后一次执行时间
- 优点 :实现简单
- 缺点 :无法处理时间回拨;精度不足时仍会重复
唯一 ID 标记
- 原理 :为每个请求生成唯一 ID
- 优点 :绝对去重
- 缺点 :需要维护 ID 生成器;存储成本高
哈希校验(推荐)
- 原理 :计算脚本内容哈希值作为指纹
- 优点 :内容级精确匹配;无需额外存储
- 缺点 :计算开销较大
核心实现方案
基于哈希值的去重机制
import hashlib
import pickle
from functools import lru_cache
# Python 示例
def get_script_hash(script_obj):
"""生成脚本的 SHA-256 哈希"""
serialized = pickle.dumps(script_obj)
return hashlib.sha256(serialized).hexdigest()
@lru_cache(maxsize=1024)
def is_duplicate(hash_str):
"""检查哈希是否已执行"""
# 实际项目中应替换为 Redis 等持久化存储
return False # 示例返回
// Java 示例
import java.security.MessageDigest;
import java.util.concurrent.ConcurrentHashMap;
public class ScriptDeduplicator {private static final ConcurrentHashMap<String, Boolean> executedScripts = new ConcurrentHashMap<>();
public static String generateHash(String scriptContent) throws Exception {MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hashBytes = digest.digest(scriptContent.getBytes());
return bytesToHex(hashBytes);
}
public static synchronized boolean checkDuplicate(String hash) {return executedScripts.putIfAbsent(hash, true) != null;
}
}
带超时的分布式锁
# Python 分布式锁示例
import redis
from contextlib import contextmanager
REDIS_CLIENT = redis.StrictRedis()
@contextmanager
def script_lock(lock_key, timeout=5):
"""分布式锁上下文管理器"""
acquired = REDIS_CLIENT.set(lock_key, 1, nx=True, ex=timeout)
try:
yield acquired
finally:
if acquired:
REDIS_CLIENT.delete(lock_key)
性能优化策略
混合存储架构
- 内存缓存 :使用 LRU 缓存高频脚本哈希
- 持久化存储 :Redis 记录全量执行记录
- 分层校验 :先查内存再查持久层
哈希计算优化
- 预处理 :对静态部分预计算哈希
- 增量哈希 :仅对变动的脚本片段重新计算
避坑指南
动态变量处理
当脚本包含动态变量时:
- 提取静态部分作为基准哈希
- 对动态部分单独校验
- 使用模板引擎生成最终脚本
高并发优化
- 分段锁 :按脚本 ID 哈希分片
- 乐观锁 :使用版本号替代互斥锁
- 退避策略 :指数退避重试机制
代码实践建议
关键参数调优:
- 锁超时时间:建议设置为平均执行时间的 3 倍
- 哈希缓存大小:根据内存压力调整(通常 1000-10000)
- 日志记录:至少记录首次重复事件
延伸思考
该方案可扩展应用于:
- 消息队列的幂等消费
- API 请求去重
- 定时任务防重执行
核心思想是通过内容指纹 + 状态锁的组合,建立通用的幂等性保障机制。在实际项目中,需要根据具体业务特点调整哈希粒度和锁策略。
总结
Skill 脚本去重是保障系统稳定性的重要手段。本文介绍的哈希校验 + 分布式锁方案,在精确度和性能之间取得了良好平衡。建议开发者在实际应用中:
- 先进行流量分析确定合适的哈希算法
- 通过压力测试验证锁竞争情况
- 建立监控指标(如去重率、锁等待时间)
随着系统规模扩大,可以考虑引入布隆过滤器等概率型数据结构进一步优化。
正文完
