分布式系统中,幂等性是一个重要的概念,它确保同一操作执行多次,结果仍然是一致的。这在处理网络请求、分布式事务等场景中尤为重要。作为一个广泛使用的分布式工具库,Redisson 提供了许多帮助实现幂等性的方法和工具。然而,在实际使用中,幂等性失效的问题仍然可能发生。本文将探讨一些可能导致 Redisson 幂等性失效的原因,并提出相应的解决思路。
什么是幂等性?
幂等性(Idempotency)是指某个操作无论执行多少次,结果都应当相同。比如,在电商系统中,如果用户重复提交支付请求,最终应该只扣除一次款项,这样才能避免多次扣款的情况。
Redisson 和幂等性
Redisson 是 Redis 的一个 Java 客户端,它提供了许多高级特性,例如分布式锁、分布式集合、分布式队列等。这些特性使得开发者可以更容易地在分布式环境中实现幂等操作。例如,通过使用 Redisson 提供的分布式锁,开发者可以确保某个资源在同一时间只能被一个线程访问,从而避免并发操作导致的幂等性问题。
失效场景
失效案例
@RestController
public class IdempotentController {
@Autowired
private TestDataService testDataService;
@PostMapping("/idempotent")
public void test(@RequestParam("mobile") String mobile) {
testDataService.testIdempotentFail(mobile);
}
}
@Autowired
private RedissonClient redissonClient;
@Transactional(rollbackFor = Exception.class)
public void testIdempotentFail(String mobile) {
RLock rLock = redissonClient.getLock("testIdempotent");
LambdaQueryWrapper<TestData> lambdaQuery = Wrappers.lambdaQuery();
lambdaQuery.eq(TestData::getMobile, mobile);
try {
//加锁
rLock.lock();
Long count = testDataMapper.selectCount(lambdaQuery);
//根据手机号查询 不存在新增
if (count == 0) {
TestData testData = buildData(1).get(0);
testData.setMobile(mobile);
testDataMapper.insert(testData);
testMapper.insert(new Test().setParam(JSONUtil.toJsonStr(testData)));
}
} finally {
//释放锁
rLock.unlock();
}
}
下面使用jmeter进行压测:
配置100个线程并发请求
所有请求全部成功
同样的手机号 数据库出现重复数据
至此,redisson锁使用不正确导致锁失效。
下面介绍修改后的代码:
@RestController
public class IdempotentController {
@Autowired
private TestDataService testDataService;
@PostMapping("/idempotent/success")
public void testSuccess(@RequestParam("mobile") String mobile) {
testDataService.testIdempotentSuccess(mobile);
}
}
@Autowired
private RedissonClient redissonClient;
public void testIdempotentSuccess(String mobile) {
RLock rLock = redissonClient.getLock("testIdempotentSuccess");
try {
//事务外进行加锁
rLock.lock();
TestDataService testDataService = (TestDataService) AopContext.currentProxy();
testDataService.testIdempotent(mobile);
} finally {
//事务结束释放锁
rLock.unlock();
}
}
@Transactional(rollbackFor = Exception.class)
public void testIdempotent(String mobile) {
LambdaQueryWrapper<TestData> lambdaQuery = Wrappers.lambdaQuery();
lambdaQuery.eq(TestData::getMobile, mobile);
Long count = testDataMapper.selectCount(lambdaQuery);
if (count == 0) {
TestData testData = buildData(1).get(0);
testData.setMobile(mobile);
testDataMapper.insert(testData);
testMapper.insert(new Test().setParam(JSONUtil.toJsonStr(testData)));
}
}
使用jmeter进行压测,通用配置100个线程并发请求
没有出现数据重复的情况
确保分布式锁的使用正确,避免锁提前释放。
引发思考:
事务与锁的独立性:分布式锁和数据库事务是独立的两个机制。即使在事务中获取了分布式锁,锁的生命周期不受事务管理器的控制。这意味着,事务还未提交锁也可能释放导致锁提起释放,从而引起幂等性失效问题。
总结
在分布式系统中实现幂等性是一个复杂但重要的任务。即使使用了像 Redisson 这样的高级工具库,仍然需要在设计和实现过程中注意各种细节,以避免幂等性失效。通过正确使用分布式锁、处理网络延迟、设计冗余机制以及在业务层面增加幂等操作标识,可以有效提高系统的可靠性和一致性。
希望这篇文章能够引发您对幂等性和 Redisson 使用的深入思考,从而在实际项目中更好地实现幂等性,确保系统的稳定运行。