<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【Redis分布式鎖實現】基于 Redis 單節點保姆級教程(Spring Boot 示例)

      下面我將詳細介紹基于 Redis 單節點實現分布式鎖的原理,并提供一個完整的 Spring Boot 實現示例。

      實現原理

      核心機制

      1. 原子獲取鎖:使用 SET key unique_value NX PX milliseconds 命令

        • NX:僅當 key 不存在時設置值
        • PX:設置過期時間(毫秒)
        • unique_value:唯一標識客戶端(防止誤刪其他客戶端的鎖)
      2. 安全釋放鎖:使用 Lua 腳本保證原子性

        if redis.call("get", KEYS[1]) == ARGV[1] then
            return redis.call("del", KEYS[1])
        else
            return 0
        end
        
      3. 鎖續期機制:可選的看門狗(Watchdog)機制,定期延長鎖的有效期

      關鍵特性

      • 互斥性:同一時刻只有一個客戶端能持有鎖
      • 防死鎖:自動過期機制確保鎖最終釋放
      • 容錯性:客戶端崩潰后鎖會自動釋放
      • 安全性:只有鎖的持有者才能釋放鎖

      Spring Boot 實現示例

      1. 添加依賴 (pom.xml)

      <dependencies>
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-data-redis</artifactId>
          </dependency>
          <dependency>
              <groupId>org.apache.commons</groupId>
              <artifactId>commons-pool2</artifactId>
          </dependency>
      </dependencies>
      

      2. 配置 Redis (application.yml)

      spring:
        redis:
          host: localhost
          port: 6379
          password: 
          lettuce:
            pool:
              max-active: 8
              max-idle: 8
              min-idle: 0
              max-wait: -1ms
      

      3. Redis 分布式鎖工具類

      import org.springframework.data.redis.core.RedisTemplate;
      import org.springframework.data.redis.core.script.DefaultRedisScript;
      import org.springframework.data.redis.core.script.RedisScript;
      import org.springframework.stereotype.Component;
      
      import java.util.Collections;
      import java.util.UUID;
      import java.util.concurrent.TimeUnit;
      
      @Component
      public class RedisDistributedLock {
      
          private final RedisTemplate<String, String> redisTemplate;
          
          // 鎖鍵前綴
          private static final String LOCK_PREFIX = "lock:";
          // 解鎖Lua腳本
          private static final String UNLOCK_SCRIPT = 
              "if redis.call('get', KEYS[1]) == ARGV[1] then " +
              "   return redis.call('del', KEYS[1]) " +
              "else " +
              "   return 0 " +
              "end";
          // 續期Lua腳本
          private static final String RENEW_SCRIPT = 
              "if redis.call('get', KEYS[1]) == ARGV[1] then " +
              "   return redis.call('pexpire', KEYS[1], ARGV[2]) " +
              "else " +
              "   return 0 " +
              "end";
      
          public RedisDistributedLock(RedisTemplate<String, String> redisTemplate) {
              this.redisTemplate = redisTemplate;
          }
      
          /**
           * 嘗試獲取分布式鎖
           * 
           * @param lockKey    鎖的key
           * @param requestId  請求標識(可使用UUID)
           * @param expireTime 鎖的過期時間(毫秒)
           * @param waitTime   等待時間(毫秒)
           * @return 是否獲取成功
           */
          public boolean tryLock(String lockKey, String requestId, long expireTime, long waitTime) {
              String fullKey = LOCK_PREFIX + lockKey;
              long end = System.currentTimeMillis() + waitTime;
              
              while (System.currentTimeMillis() < end) {
                  // 嘗試獲取鎖
                  Boolean success = redisTemplate.opsForValue()
                      .setIfAbsent(fullKey, requestId, expireTime, TimeUnit.MILLISECONDS);
                  
                  if (Boolean.TRUE.equals(success)) {
                      return true;
                  }
                  
                  // 等待隨機時間后重試,避免活鎖
                  try {
                      Thread.sleep(50 + (long) (Math.random() * 100));
                  } catch (InterruptedException e) {
                      Thread.currentThread().interrupt();
                      return false;
                  }
              }
              return false;
          }
      
          /**
           * 釋放分布式鎖
           * 
           * @param lockKey   鎖的key
           * @param requestId 請求標識
           * @return 是否釋放成功
           */
          public boolean unlock(String lockKey, String requestId) {
              String fullKey = LOCK_PREFIX + lockKey;
              
              // 使用Lua腳本保證原子性
              RedisScript<Long> script = new DefaultRedisScript<>(UNLOCK_SCRIPT, Long.class);
              Long result = redisTemplate.execute(script, Collections.singletonList(fullKey), requestId);
              
              return result != null && result == 1;
          }
      
          /**
           * 鎖續期(看門狗機制)
           * 
           * @param lockKey    鎖的key
           * @param requestId  請求標識
           * @param expireTime 新的過期時間(毫秒)
           * @return 是否續期成功
           */
          public boolean renewLock(String lockKey, String requestId, long expireTime) {
              String fullKey = LOCK_PREFIX + lockKey;
              
              // 使用Lua腳本保證原子性
              RedisScript<Long> script = new DefaultRedisScript<>(RENEW_SCRIPT, Long.class);
              Long result = redisTemplate.execute(script, 
                  Collections.singletonList(fullKey), 
                  requestId, 
                  String.valueOf(expireTime));
              
              return result != null && result == 1;
          }
      
          /**
           * 獲取鎖(簡化版,帶自動續期)
           * 
           * @param lockKey    鎖的key
           * @param expireTime 鎖的過期時間(毫秒)
           * @param waitTime   等待時間(毫秒)
           * @param task       需要執行的任務
           * @return 任務執行結果
           */
          public <T> T lockAndExecute(String lockKey, long expireTime, long waitTime, LockTask<T> task) {
              String requestId = UUID.randomUUID().toString();
              boolean locked = false;
              
              try {
                  // 嘗試獲取鎖
                  locked = tryLock(lockKey, requestId, expireTime, waitTime);
                  
                  if (!locked) {
                      throw new RuntimeException("獲取分布式鎖失敗");
                  }
                  
                  // 啟動看門狗線程定期續期
                  WatchDog watchDog = new WatchDog(lockKey, requestId, expireTime);
                  watchDog.start();
                  
                  try {
                      // 執行業務邏輯
                      return task.execute();
                  } finally {
                      // 停止看門狗
                      watchDog.stop();
                  }
              } finally {
                  // 確保鎖被釋放
                  if (locked) {
                      unlock(lockKey, requestId);
                  }
              }
          }
      
          // 看門狗線程實現
          private class WatchDog {
              private final String lockKey;
              private final String requestId;
              private final long expireTime;
              private volatile boolean running = true;
              private Thread thread;
      
              public WatchDog(String lockKey, String requestId, long expireTime) {
                  this.lockKey = lockKey;
                  this.requestId = requestId;
                  this.expireTime = expireTime;
              }
      
              public void start() {
                  thread = new Thread(() -> {
                      // 在過期時間的1/3時進行續期
                      long sleepTime = expireTime / 3;
                      
                      while (running) {
                          try {
                              Thread.sleep(sleepTime);
                              if (!renewLock(lockKey, requestId, expireTime)) {
                                  // 續期失敗,可能是鎖已被釋放或過期
                                  break;
                              }
                          } catch (InterruptedException e) {
                              Thread.currentThread().interrupt();
                              break;
                          }
                      }
                  }, "RedisLock-WatchDog");
                  thread.setDaemon(true);
                  thread.start();
              }
      
              public void stop() {
                  running = false;
                  if (thread != null) {
                      thread.interrupt();
                  }
              }
          }
      
          // 鎖任務接口
          @FunctionalInterface
          public interface LockTask<T> {
              T execute();
          }
      }
      

      4. 業務服務中使用分布式鎖

      import org.springframework.stereotype.Service;
      
      @Service
      public class OrderService {
      
          private final RedisDistributedLock redisLock;
          
          public OrderService(RedisDistributedLock redisLock) {
              this.redisLock = redisLock;
          }
          
          /**
           * 創建訂單(使用分布式鎖保護)
           */
          public void createOrder(String orderId) {
              // 使用鎖執行關鍵操作
              redisLock.lockAndExecute("order_create:" + orderId, 30000, 5000, () -> {
                  // 在這里執行需要加鎖的業務邏輯
                  try {
                      // 1. 檢查訂單是否已存在
                      if (checkOrderExists(orderId)) {
                          throw new RuntimeException("訂單已存在");
                      }
                      
                      // 2. 執行創建訂單的核心業務
                      processOrderCreation(orderId);
                      
                      // 3. 記錄訂單日志
                      logOrderCreation(orderId);
                      
                      return null;
                  } catch (Exception e) {
                      throw new RuntimeException("訂單創建失敗", e);
                  }
              });
          }
          
          private boolean checkOrderExists(String orderId) {
              // 實際業務邏輯
              return false;
          }
          
          private void processOrderCreation(String orderId) {
              // 實際業務邏輯
              System.out.println("處理訂單創建: " + orderId);
              // 模擬耗時操作
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  Thread.currentThread().interrupt();
              }
          }
          
          private void logOrderCreation(String orderId) {
              // 實際業務邏輯
              System.out.println("記錄訂單日志: " + orderId);
          }
      }
      

      5. 控制器示例

      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.RestController;
      
      @RestController
      public class OrderController {
      
          private final OrderService orderService;
      
          public OrderController(OrderService orderService) {
              this.orderService = orderService;
          }
      
          @GetMapping("/order/{orderId}")
          public String createOrder(@PathVariable String orderId) {
              try {
                  orderService.createOrder(orderId);
                  return "訂單創建成功: " + orderId;
              } catch (Exception e) {
                  return "訂單創建失敗: " + e.getMessage();
              }
          }
      }
      

      關鍵注意事項

      1. 鎖過期時間

        • 設置合理的時間(略大于業務執行時間)
        • 過短:業務未完成鎖已釋放 → 數據不一致
        • 過長:客戶端崩潰后鎖釋放延遲 → 系統可用性降低
      2. 唯一標識(requestId)

        • 必須保證全局唯一(使用UUID)
        • 確保只有鎖的持有者才能釋放鎖
      3. 看門狗機制

        • 解決業務執行時間超過鎖過期時間的問題
        • 定期續期(建議在1/3過期時間時續期)
        • 業務完成后立即停止看門狗
      4. 異常處理

        • 使用try-finally確保鎖最終被釋放
        • 避免因異常導致鎖無法釋放
      5. 重試機制

        • 設置合理的等待時間和重試策略
        • 使用隨機退避避免活鎖

      潛在缺陷及解決方案

      缺陷 解決方案
      鎖提前過期 實現看門狗續期機制
      非原子操作風險 使用Lua腳本保證原子性
      單點故障 主從復制(但有數據丟失風險)或改用RedLock
      GC暫停導致鎖失效 優化JVM參數,減少GC暫停時間
      時鐘漂移問題 使用NTP同步時間,監控時鐘差異
      鎖被誤刪 使用唯一標識驗證鎖持有者

      最佳實踐建議

      1. 鎖粒度:盡量使用細粒度鎖(如訂單ID而非整個系統鎖)
      2. 超時設置:根據業務壓力動態調整鎖超時時間
      3. 監控報警:監控鎖等待時間、獲取失敗率等關鍵指標
      4. 熔斷機制:當Redis不可用時提供降級方案
      5. 壓力測試:模擬高并發場景驗證鎖的正確性
      6. 避免長時間持鎖:優化業務邏輯減少鎖持有時間

      這個實現提供了生產環境中使用Redis分布式鎖的完整解決方案,包含了基本的鎖獲取/釋放、看門狗續期機制、以及易用的API封裝。在實際使用中,可以根據具體業務需求調整參數和實現細節。

      posted @ 2025-07-28 09:20  佛祖讓我來巡山  閱讀(527)  評論(0)    收藏  舉報

      佛祖讓我來巡山博客站 - 創建于 2018-08-15

      開發工程師個人站,內容主要是網站開發方面的技術文章,大部分來自學習或工作,部分來源于網絡,希望對大家有所幫助。

      Bootstrap中文網

      主站蜘蛛池模板: 亚洲精品麻豆一二三区| 内射干少妇亚洲69xxx| 无遮挡aaaaa大片免费看| 久久一日本综合色鬼综合色| 亚洲人成色777777老人头| 三级黄色片一区二区三区| 日韩国产中文字幕精品| 亚洲熟妇av综合一区二区| 少妇xxxxx性开放| 中文国产成人精品久久不卡| 野花香视频在线观看免费高清版| 亚洲一区二区视频在线观看| 久久97超碰色中文字幕| 她也色tayese在线视频 | 国产91精品一区二区麻豆| 邢台县| 九九热在线精品视频免费| 日本一区二区三区专线| 99久久国产一区二区三区| 久久久精品2019中文字幕之3| 亚洲最大的成人网站| 日韩无矿砖一线二线卡乱| 亚洲一区二区约美女探花| 亚洲精品成人综合色在线| 2021亚洲国产精品无码| 成人无遮挡裸免费视频在线观看| 国产精品一区二区国产馆| 无码人妻丝袜在线视频| 中文国产人精品久久蜜桃| 国产精品自在线拍国产| 中文字幕国产精品资源| 国产亚洲精品久久久久久久久| 免费人成视频网站在线18| 朔州市| 天堂网av成人在线观看| 久久精品免视看国产成人| 国内揄拍国内精品对久久| 欧美亚洲一区二区三区在线| 亚洲精品国产综合久久一线| 且末县| 护士张开腿被奷日出白浆|