zoukankan      html  css  js  c++  java
  • asp.net core mvc基于Redis实现分布式锁,C# WebApi接口防止高并发重复请求,分布式锁的接口幂等性实现

    使用背景:在使用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;
                }
            }
            
        }
    }
  • 相关阅读:
    Python基础
    thinkphp中session跨域问题
    thinkphp实现短信验证注册
    微信公众号支付流程(Node实现)
    支付宝手机网站支付流程(Node实现)
    浏览器打开URL的方式
    Jmeter取样器之Java Request
    获取Tomcat更详细的日志
    使用PowerDesigner转换不同数据库的表结构
    NameValuePair在API22过时问题
  • 原文地址:https://www.cnblogs.com/davies/p/11998895.html
Copyright © 2011-2022 走看看