分佈式鎖----Redis實現

   分佈式鎖

  爲何須要有分佈式鎖呢,在單點的時候synchronized 就能解決,可是服務拆分以後,每一個服務都是單獨的機器,沒法解決,因此出現了分佈式鎖,其實也就是用各類手段,實現獲取惟一鎖,別人沒法獲得。html

  其實在作分佈式鎖的前提,須要先明白,synchronized  爲啥不能使用了,啥原理讓他在一個機器上能夠使用。java

  


      synchronized 的原理   

      衆所周知 Synchronize 關鍵字是解決併發問題經常使用解決方案,有如下三種使用方式:redis

  • 同步靜態方法,鎖的是當前 Class 對象。
  • 同步塊,鎖的是 {} 中的對象。
  •  同步普通方法,鎖的是當前對象。

  實現原理:
  JVM 是經過進入、退出對象監視器( Monitor )來實現對方法、同步塊的同步的。併發

  具體實現是在編譯以後在同步方法調用前加入一個 monitor.enter 指令,在退出方法和異常處插入 monitor.exit 的指令。分佈式

  其本質就是對一個對象監視器( Monitor )進行獲取,而這個獲取過程具備排他性從而達到了同一時刻只能一個線程訪問的目的。spa

  而對於沒有獲取到鎖的線程將會阻塞到方法入口處,直到獲取鎖的線程 monitor.exit 以後才能嘗試繼續獲取鎖。線程

 

能夠經過使用 javap -c Synchronize 能夠查看編譯以後的具體信息 ,這裏我就再也不粘貼了。code

因此能夠知道,單獨的Java虛擬機是可實現鎖的,可是多臺手就伸不到了,只能在依賴外部的形式去產生一個惟一鎖。htm

以上是參考別人的博客拿到的信息,親自試用獲得,準確   :連接:https://www.jianshu.com/p/2ba154f275ea對象


  Redis實現的分佈式鎖

  主要是利用了redis的set NX的原理,以及對redis的script腳本原子性利用。(我的見解,其實後面一步就看各自的程序邏輯如何去斷定到底要不要這一步了)

  簡單的說一下主要流程:

  1. 首先設置一個全局惟一的key和一個惟一性的value(value是一個解鎖的保障,刪除以前判斷一下值是否一致)
  2. 使用Redis的set 方法 以多參數形式配置key,value,nx,px,過時時間 (參數 NX:只有鍵不存在時,才能對其進行設置操做)
  3. 利用Redis的script腳原本對key的刪除操做,只能本身刪除本身的value(刪除以前先判斷一下value是不是我以前的value,是否被改過,沒有就刪了)
   這是腳本的主要 內容  if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else  return 0 end  
   對其解釋: 根據 get 獲取到 key 的值 ,判斷key的值是否跟你傳的值相等,相等則 執行del  key 不然返回0 結束
   對此推薦去看一下redis的Lua腳本,給個簡單的:http://redisdoc.com/script/eval.html
  
  在實際場景中能夠利用AOP的切點切面形式,實現具體是什麼地方須要分佈式鎖,搭配分佈式鎖,再搭配註解方式,來實現想要的自定義設置那裏須要就點哪裏
  AOP的主要實現是
  1. @pointcut 切註解類
  2. 在使用@around環繞對先後作處理
  3. 前面加鎖
  4. 後面解鎖del  使用script腳本
  

  代碼主要實現

   註解類 DistributedLock

  

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DistributedLock {

    /**
     * 自定義形式添加你對分佈式鎖的對外配置屬性  
     * 例如:key的規則,鎖的超時時間,獲取鎖的等待時間,等一系列的屬性配置
     * 
     */

}
  切面類 DistributedLockAspect
@Aspect
@Component
public class DistributedLockAspect {
    
     /**
     * 層切點
     */
    @Pointcut("@annotation(com.creditease.hardess.common.annotation.DistributedLock)")
    public void distributedLockAspect() {}

/**
     * @param joinPoint 切點
     * @return Object 添加分佈式鎖後,實際調用業務邏輯部分代碼的返回值
     * @throws Throwable 產生的全部異常,爲了不對異常處理流程產生干擾,全部異常都應該繼續拋出
     */
    @Around("distributedLockAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
     /**
      *主要寫一些鎖的獲取,和業務邏輯執行,鎖的刪除等
      *
     */
     return returnObject;
    }

   /**
     * 獲取 DistributedLock 註解
     * 
     * @param joinPoint
     * @return 代碼中定義的註解
     * @throws NoSuchMethodException
     */
    private static DistributedLock getDistributedLock(ProceedingJoinPoint joinPoint)
            throws NoSuchMethodException {
        String methodName = joinPoint.getSignature().getName();

        Class<?> classTarget = joinPoint.getTarget().getClass();
        Class<?>[] par = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
        Method objMethod = classTarget.getMethod(methodName, par);

        return objMethod.getAnnotation(DistributedLock.class);
    }

}




}
相關文章
相關標籤/搜索