持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
分布式分段锁 解决高并发情况锁导致请求处理慢的问题
使用redisson 分布式锁 会导致 线程并行执行,在秒杀系统中导致并发下降,此时可以对库存进行分段 如 stockCount = 40 分成四十段,分段的段数和总库存 相关, 用户请求时,随机分配一个段,若获取失败再重试几次,以保证尽可能购买到,详细代码如下
book 不使用锁 本机测试 20000/分钟
bookWithLock:使用分布式锁 但是没有分段 测试结果 1000/分钟
bookWithLock2 使用分布式锁 分段20时测试结果12000/分钟 分段40时测试结果 16000/分钟
@Slf4j@Servicepublic class OrderServiceImpl implements OrderService {- ``
private static String key = "count";private static int stockCount = 40;- ``
@Autowiredprivate RedissonClient redissonClient;- ``
@Autowiredprivate StringRedisTemplate stringRedisTemplate;- ``
@Overridepublic String book() {return this.decrementOrder();}- ``
- ``
@Overridepublic String bookWithLock() {RLock lock = this.redissonClient.getLock("lock");Boolean result = false;try {- ``
result = lock.tryLock(10, TimeUnit.SECONDS);if (result) {return this.decrementOrder();} else {log.info("==================获取锁失败================");}- ``
// Boolean result = lock.tryLock(10, TimeUnit.SECONDS);// if (result) {// return this.decrementOrder();// } else {// log.info("获取锁失败");// return "获取锁失败";// }- ``
} catch (Exception e) {log.error(e.getMessage());return "预定失败";} finally {if (result) {lock.unlock();}}return "0";}- ``
- ``
private String decrementOrder() {Long count = Long.valueOf(this.stringRedisTemplate.opsForValue().get(key));if (count > 0) {count = this.stringRedisTemplate.opsForValue().decrement(key);log.info("==================库存还剩{}个================", count);return String.valueOf(count);} else {log.info("库存不足");}return "库存不足";}- ``
- ``
@Overridepublic Long initCount(Long count) {count = count == null ? 100000 : count;if (count < stockCount) {stockCount = 1;this.stringRedisTemplate.opsForValue().set(key + "_0", count.toString());} else {for (int i = 0; i < stockCount; i++) {this.stringRedisTemplate.opsForValue().set(key + "_" + i, String.valueOf(count / stockCount));}if (count % stockCount != 0) {this.stringRedisTemplate.opsForValue().set(key + "_" + 0, String.valueOf(count / stockCount + count % stockCount));}}this.stringRedisTemplate.opsForValue().set(key, count.toString());return Long.valueOf(this.stringRedisTemplate.opsForValue().get(key));}- ``
@Overridepublic String bookWithLock2() {- ``
RLock lock = null;Boolean result = false;//尝试三次for (int i = 0; i < 3; i++) {try {int index = getRandom(stockCount);lock = this.redissonClient.getLock("lock" + index);result = lock.tryLock(10, TimeUnit.SECONDS);if (result) {String count = decrementOrder2(index);//如果没获取到(某个段的库存不足)则释放锁if ("-1".equals(count)) {lock.unlock();} else {return count;}}} catch (Exception ex) {log.error("执行失败", ex);} finally {if (result && lock != null) {try {lock.unlock();} catch (IllegalMonitorStateException e) {}}}- ``
}log.info("预定失败");- ``
return "0";- ``
- ``
}- ``
- ``
private String decrementOrder2(Integer index) {index = index == null ? 0 : index;//尝试获取次数- ``
String keyTemp = key + "_" + index;- ``
Long count = Long.valueOf(this.stringRedisTemplate.opsForValue().get(keyTemp));if (count > 0) {count = this.stringRedisTemplate.opsForValue().decrement(keyTemp);log.info("==================库存还剩{}个================", count);return String.valueOf(count);}- ``
log.info("获取是失败.......");return "-1";}- ``
- ``
private int getRandom(int count) {return new Random().nextInt(count);}- ``
- ``
}