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;
            }
        }
        
    }
}

 


免責聲明!

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



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