業務核心模塊只能提交一次,原實現方案 前端加提交限制、後端加數據庫業務邏輯斷定,結果失效,api站點部署多臺負載,切方法須要強求第三方接口 響應時間較慢 ,故放棄lock。前端
解決方案:redis業務鎖。redis
1:利用redis原子性解決併發問題數據庫
2:利用redis集羣署解決分佈式部署問題後端
3:利用redis性能快解決時間消耗問題api
4:利用redis過時時間解決死鎖問題緩存
5:利用rediskey惟一性解決互斥問題併發
問題:超時時間存在偏差分佈式
2.1:RedisManager 中重構Set,能夠設置When 屬性,Always 老是保存,Exists 存在時保存,NotExists 不存在時保存。返回值中true與false表明是否操做。ide
設置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"/>