使用背景:在使用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; } } } }