使用背景:在使用app或者pc網頁時,可能由於網絡原因,api接口可能被前端調用一個接口重復2次的情況,但是請求內容是一樣的。這樣在同一個短暫的時間內,就會有兩個相同請求,而程序只希望處理第一個請求,第二個請求是重復的。比如創建訂單,相同內容可能出現兩次, 這樣如果接口不處理,可能用戶會創建2個訂單。
分布式鎖的接口冪等性實現
基於Redis實現分布式鎖(前提是單台Redis),如果是多台Redis集群,可能有非同步的異常情況。
實現思路:
利用redis的setnx(key, value):“set if not exits”,若該key-value不存在,則成功加入緩存,並且重新設置緩存時間,並且返回1,否則返回0。
這里超過緩存時間,系統會自動釋放緩存。
在有效時間內如果設置成功則獲取執行限權,沒有那就獲取權限失敗。
下面貼一個示例代碼。
新建一個控制台程序,通過NuGet 添加引用 NServiceKit.Redis 。然后把以下代碼copy過去。就可以跑示例。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace RedisCheckTest { using NServiceKit.Redis;// 通過nuget添加redis庫 class Program { static void Main(string[] args) { var m = 0; while (m < 1000000) { m++; ///模擬重復發送3次請求 for (var j = 1; j <= 3; j++) { CreateOrderApi(j); } //for (var i = 1; i <= 3; i++) //{//模擬重復發送3次請求 // Thread t2 = new Thread(CreateOrderApi); // t2.Start(); //} Thread.Sleep(8000); } Console.ReadLine(); } /// <summary> /// 比如說這是創建訂單方法, /// </summary> /// <param name="id"></param> /// <returns></returns> private static void CreateOrderApi(int request_id) { string parmaterid = "p2";//假設這是api請求參數id var nxkey = "cnx" + parmaterid; var value = parmaterid; bool setnx = SetNX(nxkey, value); if (!setnx) { Console.WriteLine("requestid: " + request_id.ToString() + " " + "請求太頻繁,請10秒后再試。"); return; } //todo: 這里寫訂單邏輯 Console.WriteLine("requestid: " + request_id.ToString() + " " + "Success"); } const string host = "127.0.0.1"; const int port = 6379; public static bool SetNX(string cachekey, string value, int secondsTimeout = 5) { string NamespacePrefix = "api01_"; string key = NamespacePrefix + cachekey; using (var client = new RedisClient(host, port)) { var byts = System.Text.Encoding.UTF8.GetBytes(value); var result = client.SetNX(key, byts); var setnx = (result == 1) ? true : false; client.Set(key, value, DateTime.Now.AddSeconds(secondsTimeout));//將Key緩存5秒 return setnx; } } } }
