You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.md 5.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. ## spring-boot-demo-distributed-lock-curator
  2. > 此 demo 主要演示了 Spring Boot 如何基于 Curator 实现一个分布式锁
  3. ## 1.开发步骤
  4. 在 `demo-distributed-lock-api` 模块中,已经实现了基于 AOP 的分布式锁注解拦截、简单的扣减库存案例,因此本模块只需要实现以下两个接口即可。
  5. - `com.xkcoding.distributed.lock.api.DistributedLock`
  6. - `com.xkcoding.distributed.lock.api.DistributedLockClient`
  7. ### 1.1.添加依赖
  8. ```xml
  9. <dependencies>
  10. <dependency>
  11. <groupId>com.xkcoding</groupId>
  12. <artifactId>demo-distributed-lock-api</artifactId>
  13. <version>1.0.0-SNAPSHOT</version>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.apache.curator</groupId>
  17. <artifactId>curator-framework</artifactId>
  18. <version>${curator.version}</version>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.apache.curator</groupId>
  22. <artifactId>curator-recipes</artifactId>
  23. <version>${curator.version}</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.projectlombok</groupId>
  27. <artifactId>lombok</artifactId>
  28. <optional>true</optional>
  29. </dependency>
  30. </dependencies>
  31. ```
  32. ### 1.2.代码实现
  33. #### 1.2.1.CuratorDistributedLock
  34. > 基于 Curator 实现分布式锁
  35. ```java
  36. public class CuratorDistributedLock extends DistributedLock {
  37. private final CuratorFramework curatorFramework;
  38. private final InterProcessMutex mutex;
  39. private static final String ROOT_PATH = "/locks";
  40. protected CuratorDistributedLock(CuratorFramework curatorFramework, String lockKey, long lockTime, TimeUnit timeUnit) {
  41. super(lockKey, lockTime, timeUnit);
  42. this.curatorFramework = curatorFramework;
  43. mutex = new InterProcessMutex(curatorFramework, ROOT_PATH + "/" + lockKey);
  44. }
  45. @Override
  46. public void lock() {
  47. try {
  48. mutex.acquire();
  49. } catch (Exception e) {
  50. throw new RuntimeException(e);
  51. }
  52. }
  53. @Override
  54. public boolean tryLock() {
  55. try {
  56. return tryLock(lockTime, timeUnit);
  57. } catch (InterruptedException e) {
  58. return false;
  59. }
  60. }
  61. @Override
  62. public boolean tryLock(long time, @NotNull TimeUnit unit) throws InterruptedException {
  63. try {
  64. return mutex.acquire(time, unit);
  65. } catch (Exception e) {
  66. return false;
  67. }
  68. }
  69. @Override
  70. public void unlock() {
  71. try {
  72. mutex.release();
  73. } catch (Exception e) {
  74. throw new RuntimeException(e);
  75. }
  76. }
  77. }
  78. ```
  79. #### 1.2.2.CuratorDistributedLockClient
  80. > 获取一把 Curator 分布式锁
  81. ```java
  82. @RequiredArgsConstructor
  83. public class CuratorDistributedLockClient implements DistributedLockClient {
  84. private final CuratorFramework curatorFramework;
  85. /**
  86. * 获取一把锁
  87. *
  88. * @param lockKey 锁的标识
  89. * @param lockTime 锁的时间
  90. * @param timeUnit 锁的时间单位
  91. * @return 锁
  92. */
  93. @Override
  94. public DistributedLock getLock(String lockKey, long lockTime, TimeUnit timeUnit) {
  95. return new CuratorDistributedLock(curatorFramework, lockKey, lockTime, timeUnit);
  96. }
  97. }
  98. ```
  99. #### 1.2.3.自动装配
  100. > 替换 `demo-distributed-lock-api` 中的默认实现
  101. ```java
  102. @Slf4j
  103. @Configuration(proxyBeanMethods = false)
  104. public class CuratorDistributedLockAutoConfiguration {
  105. @Bean
  106. public CuratorFramework curatorFramework() {
  107. // 指数重试
  108. RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
  109. // 创建 Curator
  110. CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", retryPolicy);
  111. // 启动 Curator
  112. client.start();
  113. log.info("===========> curator connected <===========");
  114. return client;
  115. }
  116. @Bean
  117. public CuratorDistributedLockClient distributedLockClient(CuratorFramework curatorFramework) {
  118. return new CuratorDistributedLockClient(curatorFramework);
  119. }
  120. }
  121. ```
  122. ## 2.测试
  123. ### 2.1.环境搭建
  124. 主要是 mysql 及 zookeeper 环境的搭建,这里我提供了 docker-compose 文件,方便同学们一键启动测试环境
  125. ```bash
  126. $ cd demo-distributed-lock/demo-distributed-lock-curator
  127. $ docker compose -f docker-compose.env.yml up
  128. ```
  129. ### 2.2.测试流程
  130. 这里我通过 Apache Bench 进行模拟并发场景,我也构建了一个压测镜像 `xkcoding/ab:alpine-3.16.2` ,方便同学们进行快速测试
  131. > 注意:每次启动项目,都会在重置库存,你也可以手动调用 `/demo/stock/reset` 接口重置
  132. #### 2.2.1.测试无分布式锁下高并发请求是否会发生超卖
  133. 1. 把 `CuratorDistributedLockAutoConfiguration` 类全部注释掉,这将不会装配 Curator 分布式锁
  134. 2. 启动 `CuratorDistributedLockApplication`
  135. 3. 模拟 5000 请求数 100 并发的压测环境 `docker run -it --rm xkcoding/ab:alpine-3.16.2 ab -n 5000 -c 100 http://${替换成你电脑的内网IP}:8080/demo/stock/reduce`
  136. 4. 等待压测结束,前往数据库查看库存是否从 5000 减为 0
  137. #### 2.2.2.测试 Curator 分布式锁
  138. 1. 把 `CuratorDistributedLockAutoConfiguration` 类的注释解开,此时 Spring Boot 会自动装配我们的 Curator 分布式锁
  139. 2. 再次启动 `CuratorDistributedLockApplication`
  140. 3. 再次模拟 5000 请求数 100 并发的压测环境 `docker run -it --rm xkcoding/ab:alpine-3.16.2 ab -n 5000 -c 100 http://${替换成你电脑的内网IP}:8080/demo/stock/reduce`
  141. 4. 等待压测结束,前往数据库查看库存是否从 5000 减为 0
  142. ## 3.参考
  143. - [Curator](https://curator.apache.org/)