cursor-init/docs/distributed-lock-guide.md
expressgy ed92f32389 feat: 优化分布式锁自动续期机制
- 添加进程退出时的自动清理逻辑

- 优化锁配置策略,短期操作不续期,长期操作续期

- 添加完整的分布式锁使用指南文档

- 修复自动续期可能导致死锁的问题
2025-07-06 18:39:25 +08:00

266 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 分布式锁使用指南
## 概述
本文档介绍了项目中分布式锁的使用策略和最佳实践,帮助开发者正确使用分布式锁来保护关键业务操作。
## 分布式锁的作用
分布式锁主要用于解决以下问题:
1. **防止并发冲突**:避免多个进程同时操作同一资源
2. **保证数据一致性**:确保关键操作的原子性
3. **防止重复操作**:避免重复执行相同的业务逻辑
## 使用策略
### 1. 短期操作(推荐不开启自动续期)
**适用场景**
- 用户登录
- Token刷新
- 数据查询
- 简单的数据更新
**配置建议**
```typescript
const lock = await DistributedLockService.acquire({
key: 'user:login:username',
ttl: 15, // 15秒过期
timeout: 8000, // 8秒超时
autoRenew: false // 不开启自动续期
});
```
**优点**
- 简单可靠,不会出现死锁
- 性能开销小
- 适合快速操作
### 2. 长期操作(需要开启自动续期)
**适用场景**
- 用户注册(包含邮件发送)
- 密码重置(包含邮件发送)
- 文件上传
- 复杂的数据处理
**配置建议**
```typescript
const lock = await DistributedLockService.acquire({
key: 'user:register:username:email',
ttl: 60, // 60秒过期
timeout: 15000, // 15秒超时
autoRenew: true, // 开启自动续期
renewInterval: 20000 // 20秒续期一次
});
```
**注意事项**
- 必须确保在操作完成后手动释放锁
- 进程退出时会自动清理锁
- 续期失败时会记录警告日志
## 锁键名设计规范
### 1. 命名规则
```
{业务模块}:{操作类型}:{关键标识}
```
### 2. 示例
```typescript
// 用户注册锁
'user:register:username:email'
// 用户登录锁
'user:login:username'
// 密码重置锁
'password:reset:email'
// Token刷新锁
'token:refresh:token_value'
```
### 3. 注意事项
- 键名要具有唯一性
- 避免使用过长的键名
- 使用有意义的标识符
## 最佳实践
### 1. 锁的粒度控制
**好的做法**
```typescript
// 针对特定用户加锁
const lock = await DistributedLockService.acquire({
key: `user:login:${username}`,
ttl: 15,
autoRenew: false
});
```
**避免的做法**
```typescript
// 锁的粒度太粗,影响其他用户
const lock = await DistributedLockService.acquire({
key: 'user:login', // 所有用户登录都被阻塞
ttl: 15,
autoRenew: false
});
```
### 2. 超时时间设置
**原则**
- 超时时间应该大于预期的操作时间
- 但不要设置过长,避免长时间阻塞
**建议**
```typescript
// 快速操作
timeout: 5000 // 5秒
// 中等操作
timeout: 10000 // 10秒
// 慢速操作
timeout: 30000 // 30秒
```
### 3. TTL设置
**原则**
- TTL应该大于操作时间
- 对于自动续期的锁TTL可以设置得相对较短
**建议**
```typescript
// 快速操作
ttl: 10 // 10秒
// 中等操作
ttl: 30 // 30秒
// 慢速操作
ttl: 60 // 60秒
```
### 4. 错误处理
**必须使用 try-finally**
```typescript
const lock = await DistributedLockService.acquire(config);
try {
// 执行业务逻辑
await doSomething();
} finally {
// 确保锁被释放
await lock.release();
}
```
### 5. 监控和日志
**监控指标**
- 锁获取成功率
- 锁等待时间
- 锁释放情况
- 死锁检测
**日志记录**
```typescript
Logger.info(`获取分布式锁成功: ${lockKey}`);
Logger.warn(`锁续期失败: ${lockKey}`);
Logger.error(`获取锁超时: ${lockKey}`);
```
## 常见问题
### 1. 死锁问题
**原因**
- 进程崩溃但锁未释放
- 网络中断导致无法续期
- 业务逻辑异常导致锁未释放
**解决方案**
- 设置合理的TTL
- 使用try-finally确保锁释放
- 进程退出时自动清理锁
- 定期检查并清理过期锁
### 2. 性能问题
**原因**
- 锁的粒度太粗
- 锁的持有时间过长
- 频繁的锁竞争
**解决方案**
- 细化锁的粒度
- 优化业务逻辑,减少锁持有时间
- 使用读写锁分离
- 考虑使用乐观锁
### 3. 一致性问题
**原因**
- 锁释放时机不当
- 业务逻辑异常
- 并发控制不当
**解决方案**
- 确保锁的原子性操作
- 使用事务保证数据一致性
- 添加业务层面的幂等性检查
## 工具函数
### 1. 装饰器使用
```typescript
class UserService {
@withDistributedLock('user:register', 30, 10000)
async register(userData: UserData) {
// 业务逻辑
}
}
```
### 2. 手动管理锁
```typescript
async function complexOperation() {
const lock = await DistributedLockService.acquire({
key: 'complex:operation',
ttl: 60,
autoRenew: true
});
try {
// 复杂业务逻辑
await step1();
await step2();
await step3();
} finally {
await lock.release();
}
}
```
## 总结
分布式锁是保证系统一致性的重要工具,但使用不当也会带来问题。遵循以下原则:
1. **合理选择锁策略**:短期操作不续期,长期操作要续期
2. **控制锁粒度**:避免锁的粒度过粗
3. **设置合理超时**:避免无限等待
4. **确保锁释放**使用try-finally模式
5. **监控和日志**:及时发现问题
6. **定期清理**:防止死锁积累
通过合理使用分布式锁,可以有效保证系统的数据一致性和业务正确性。