分布式分段锁 解决高并发情况锁导致请求处理慢的问题

470 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

分布式分段锁 解决高并发情况锁导致请求处理慢的问题

使用redisson 分布式锁 会导致 线程并行执行,在秒杀系统中导致并发下降,此时可以对库存进行分段 如 stockCount = 40 分成四十段,分段的段数和总库存 相关, 用户请求时,随机分配一个段,若获取失败再重试几次,以保证尽可能购买到,详细代码如下
book 不使用锁 本机测试 20000/分钟
bookWithLock:使用分布式锁 但是没有分段 测试结果 1000/分钟
bookWithLock2 使用分布式锁 分段20时测试结果12000/分钟 分段40时测试结果 16000/分钟

  1. @Slf4j
  2. @Service
  3. public class OrderServiceImpl implements OrderService {
  4. ``
  5. private static String key = "count";
  6. private static int stockCount = 40;
  7. ``
  8. @Autowired
  9. private RedissonClient redissonClient;
  10. ``
  11. @Autowired
  12. private StringRedisTemplate stringRedisTemplate;
  13. ``
  14. @Override
  15. public String book() {
  16. return this.decrementOrder();
  17. }
  18. ``
  19. ``
  20. @Override
  21. public String bookWithLock() {
  22. RLock lock = this.redissonClient.getLock("lock");
  23. Boolean result = false;
  24. try {
  25. ``
  26. result = lock.tryLock(10, TimeUnit.SECONDS);
  27. if (result) {
  28. return this.decrementOrder();
  29. } else {
  30. log.info("==================获取锁失败================");
  31. }
  32. ``
  33. // Boolean result = lock.tryLock(10, TimeUnit.SECONDS);
  34. // if (result) {
  35. // return this.decrementOrder();
  36. // } else {
  37. // log.info("获取锁失败");
  38. // return "获取锁失败";
  39. // }
  40. ``
  41. } catch (Exception e) {
  42. log.error(e.getMessage());
  43. return "预定失败";
  44. } finally {
  45. if (result) {
  46. lock.unlock();
  47. }
  48. }
  49. return "0";
  50. }
  51. ``
  52. ``
  53. private String decrementOrder() {
  54. Long count = Long.valueOf(this.stringRedisTemplate.opsForValue().get(key));
  55. if (count > 0) {
  56. count = this.stringRedisTemplate.opsForValue().decrement(key);
  57. log.info("==================库存还剩{}个================", count);
  58. return String.valueOf(count);
  59. } else {
  60. log.info("库存不足");
  61. }
  62. return "库存不足";
  63. }
  64. ``
  65. ``
  66. @Override
  67. public Long initCount(Long count) {
  68. count = count == null ? 100000 : count;
  69. if (count < stockCount) {
  70. stockCount = 1;
  71. this.stringRedisTemplate.opsForValue().set(key + "_0", count.toString());
  72. } else {
  73. for (int i = 0; i < stockCount; i++) {
  74. this.stringRedisTemplate.opsForValue().set(key + "_" + i, String.valueOf(count / stockCount));
  75. }
  76. if (count % stockCount != 0) {
  77. this.stringRedisTemplate.opsForValue().set(key + "_" + 0, String.valueOf(count / stockCount + count % stockCount));
  78. }
  79. }
  80. this.stringRedisTemplate.opsForValue().set(key, count.toString());
  81. return Long.valueOf(this.stringRedisTemplate.opsForValue().get(key));
  82. }
  83. ``
  84. @Override
  85. public String bookWithLock2() {
  86. ``
  87. RLock lock = null;
  88. Boolean result = false;
  89. //尝试三次
  90. for (int i = 0; i < 3; i++) {
  91. try {
  92. int index = getRandom(stockCount);
  93. lock = this.redissonClient.getLock("lock" + index);
  94. result = lock.tryLock(10, TimeUnit.SECONDS);
  95. if (result) {
  96. String count = decrementOrder2(index);
  97. //如果没获取到(某个段的库存不足)则释放锁
  98. if ("-1".equals(count)) {
  99. lock.unlock();
  100. } else {
  101. return count;
  102. }
  103. }
  104. } catch (Exception ex) {
  105. log.error("执行失败", ex);
  106. } finally {
  107. if (result && lock != null) {
  108. try {
  109. lock.unlock();
  110. } catch (IllegalMonitorStateException e) {
  111. }
  112. }
  113. }
  114. ``
  115. }
  116. log.info("预定失败");
  117. ``
  118. return "0";
  119. ``
  120. ``
  121. }
  122. ``
  123. ``
  124. private String decrementOrder2(Integer index) {
  125. index = index == null ? 0 : index;
  126. //尝试获取次数
  127. ``
  128. String keyTemp = key + "_" + index;
  129. ``
  130. Long count = Long.valueOf(this.stringRedisTemplate.opsForValue().get(keyTemp));
  131. if (count > 0) {
  132. count = this.stringRedisTemplate.opsForValue().decrement(keyTemp);
  133. log.info("==================库存还剩{}个================", count);
  134. return String.valueOf(count);
  135. }
  136. ``
  137. log.info("获取是失败.......");
  138. return "-1";
  139. }
  140. ``
  141. ``
  142. private int getRandom(int count) {
  143. return new Random().nextInt(count);
  144. }
  145. ``
  146. ``
  147. }