redis 業務鎖 not exist 模式


背景:

業務核心模塊只能提交一次,原實現方案 前端加提交限制、后端加數據庫業務邏輯判定,結果失效,api站點部署多台負載,切方法需要強求第三方接口 響應時間較慢 ,故放棄lock。

解決方案:redis業務鎖。

一、原理

1:利用redis原子性解決並發問題

2:利用redis集群署解決分布式部署問題

3:利用redis性能快解決時間消耗問題

4:利用redis過期時間解決死鎖問題

5:利用rediskey唯一性解決互斥問題

 

問題:超時時間存在誤差

二、基礎方法

2.1RedisManager 中重構Set,可以設置When 屬性,Always 總是保存,Exists 存在時保存,NotExists 不存在時保存。返回值中truefalse代表是否操作。

設置notExists模式可以判定redis中是否存在值

 

 1 public static bool Set<T>(string key, T objectValue, long lNumofSeconds = 0, StackExchange.Redis.When when =When.Always)
 2         {
 3             if (!Enum.IsDefined(typeof(When), when))
 4                 throw new InvalidEnumArgumentException(nameof(when), (int) when, typeof(When));
 5             bool result = false;
 6             try
 7             {
 8                 key = redisConfigInfo.KeySuffix + key;
 9                 if (lNumofSeconds > 0L)
10                 {
11                     return ManagerMaster.GetDatabase(-1, null).StringSet(key, ConvertJson<T>(objectValue), new TimeSpan?(TimeSpan.FromSeconds((double)lNumofSeconds)), when, CommandFlags.None);
12                 }
13                 return ManagerMaster.GetDatabase(-1, null).StringSet(key, ConvertJson<T>(objectValue), null, when, CommandFlags.None);
14             }
15             catch (Exception) { result = false; }
16             return result;
17         }

 

namespace StackExchange.Redis
{
  public enum When
  {
    Always,
    Exists,
    NotExists,
  }
}

 

 

2.2:判定是否存在redis緩存 ,如果存在則返回true 如果不存在就返回false並保存值

 1 /// <summary>
 2         /// 判定緩存是否存在
 3         /// 不存在就添加緩存
 4         /// </summary>
 5         /// <param name="redisKey"></param>
 6         /// <param name="inputValue">redis值</param>
 7         /// <param name="timeSecond">過期時間/秒</param>
 8         /// <param name="cacheType">{0:cache;2=redis};默認redis</param>
 9         /// <returns>true 代表存在redis false 代表不存在redis 自動寫入</returns>
10         public static bool CheckRedisNoExistSet(string redisKey, string inputValue, int timeSecond = 120,int cacheType=1)
11         {
12             //redis寫 NX-- Only set the key if it does not already exist.
13             //true寫成功 無數據 寫入,false 沒寫 或者異常  
14             return !RedisManager.Set(redisKey, inputValue, timeSecond, When.NotExists);
15         }

 

 

三、應用

通過redis 來實現業務鎖功能

1:最小單位可是精確到某一個表的ID ,例如:reportID

2:如果正在處理這個案件則阻止其他並發操作

3:自動過期時間為120秒,方法執行完畢自動釋放

 

/// <summary>
        /// 正式全部提交
        /// 1.返回code=0表示存在重復案件
        /// 2.首次IsContinue傳0,繼續提交IsContinue傳1
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost, Log("全部提交")]
        public BaseResponse CenterSubmitAllSimpleCase([FromBody]CenterSubmitAllSimpleCaseRequest request)
        {
            var redisKey = string.Format(ConfigurationManager.AppSettings["CenterSubmitAllSimpleCase"], request.ReportId.ToString());
            if (CacheProvider.CheckRedisNoExistSet(redisKey, request.ReportId.ToString()))
            {
                return BaseResponse.GetBaseResponse(BusinessStatusType.Failed, "請勿重復提交");
            }
            var centerFlow = _centerFlowService.QueryCenterFlowByReportId(request.ReportId).Any(e => e.Status == (int)SubmitCenterStatus.提交中);
            if (centerFlow)
                return BaseResponse.GetBaseResponse(BusinessStatusType.Failed, "請勿重復提交");
            request.CenterSubmitType = CenterSubmitType.全部提交;
            BaseResponse result = _callBackService.SubmitCompleteToCenter(request);
            CacheProvider.Remove(redisKey);
            return result;
        }
<!--全部提交業務鎖-->
  <add key="CenterSubmitAllSimpleCase" value="fc_centerSubmitAllSimpleCase_{0}_feiCheRedis20"/>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM