C# --- 使用Redis分布式锁实现初始化任务
C# --- 使用Redis分布式锁实现初始化任务
- 背景
- 解决方案 --- 分布式锁
背景
- service A 在启动时需要读取一些配置文件,并根据配置文件的内容对数据库进行更新
- service A有多个实例,所以在启动时会重复进行初始化,浪费资源
解决方案 — 分布式锁
可以使用分布式锁 + version number的方式实现只让一个实例进行初始化任务
- version number: .Net应用在编译时(不管代码有没有改变)都会生成一个assembly module version id
- version number存在数据库里,用于对比
具体步骤:
- 多个实例同时启动,不断尝试获取分布式锁
- 实例A拿到锁,使用自身的version number和数据库里的进行对比,如果不一致则说明初始化任务还未进行,则执行初始化任务,完成后释放锁
- 实例B获取锁,使用自身的version number和数据库里的进行对比,发现version number一致,则说明已执行完初始化任务,跳过初始化任务
//.Net的 Redis library
using RedLockNet private async Task<IRedLock> AcquireLock()
{//时间分别为:expireTime,waitTime,retryTimevar dLock= await _lockFactory.CreateLockAsync(LockKey, TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(70), TimeSpan.FromSeconds(2),if (dLock.IsAcquired){return dLock}await dLock.Dispose();throw Exception("Cannot get lock within wait time")
}
public async DoInitTask()
{await using var distributedLock = await AcquireLock()var newVersion = GetNewVersion();var curVersion = GetVersionFromDB();if (newVersion = curVersion) {log("already init")return }//do init task
}