zoukankan      html  css  js  c++  java
  • .NET-高并发及限流方案

    前言:高并发对我们来说应该都不陌生,特别想淘宝秒杀,竞价等等,使用的非常多,如何在高并发的情况下,使用限流,保证业务的进行呢。以下是一个实例,不喜勿喷!

    总体思路:

    1.  用一个环形来代表通过的请求容器。

    2.  用一个指针指向当前请求所到的位置索引,来判断当前请求时间和当前位置上次请求的时间差,依此来判断是否被限制。

    3.  如果请求通过,则当前指针向前移动一个位置,不通过则不移动位置

    4.  重复以上步骤 直到永远.......

    以下代码的核心思路是这样的:指针当前位置的时间元素和当前时间的差来决定是否允许此次请求,这样通过的请求在时间上表现的比较平滑。

    实例使用.net写的,仅供参考,了解思路和原理,需要者完全可以用其他方式语言来实现,很简单:

     public class LimitService
        {
            /// <summary>
            /// 当前指针位置
            /// </summary>
            public int currentIndex = 0;
    
            //限制的时间的秒数,即:x秒允许多少请求
            public int limitTimeSencond = 1;
    
            /// <summary>
            /// 请求环的数组容器
            /// </summary>
            public DateTime?[] requstRing { get; set; } = null;
    
            /// <summary>
            /// 容器改变或者移动指针时的锁;
            /// </summary>
            object obj = new object();
    
            public LimitService(int countPerSecond, int _limitTimeSencond)
            {
                limitTimeSencond = _limitTimeSencond;
                requstRing = new DateTime?[countPerSecond];
            }
    
            /// <summary>
            /// 程序是否可以继续
            /// </summary>
            /// <returns></returns>
            public bool IsContinue()
            {
                lock (obj)
                {
                    var currentNode = requstRing[currentIndex];
                    if (currentNode != null && currentNode.Value.AddSeconds(limitTimeSencond) > DateTime.Now)
                    {
                        return false;
                    }
    
                    //当前节点设置为当前时间
                    requstRing[currentIndex] = DateTime.Now;
                    //指针移动一个位置
                    MoveNextIndex(ref currentIndex);
                }
    
                return true;
            }
    
            /// <summary>
            /// 改变每秒可以通过的请求数
            /// </summary>
            /// <param name="countPerSecond"></param>
            /// <returns></returns>
            public bool ChangeCountPerSecond(int countPerSecond)
            {
                lock (obj)
                {
                    requstRing = new DateTime?[countPerSecond];
    
                    currentIndex = 0;
                }
    
                return true;
            }
    
            /// <summary>
            /// 指针往前移动一个位置
            /// </summary>
            /// <param name="currentIndex"></param>
            public  void  MoveNextIndex (ref int currentIndex)
            {
                if(currentIndex!= requstRing.Length - 1)
                {
                    currentIndex = currentIndex + 1;
                }
                else
                {
                    currentIndex = 0;
                }
            }
    

      

    测试程序如下:

     1  public class Program
     2     {
     3         static LimitService l = new LimitService(1000, 1);
     4         public static void Main(string[] args)
     5         {
     6 
     7             int threadCount = 50;
     8 
     9             while (threadCount >= 0)
    10             {
    11                 Thread t = new Thread(s => {
    12                     Limit();
    13 
    14                 });
    15 
    16                 t.Start();
    17 
    18                 threadCount--;
    19             }
    20 
    21             Console.ReadKey();
    22         }
    23 
    24         public static void Limit()
    25         {
    26             int i = 0;
    27             int okCount = 0;
    28             int noCount = 0;
    29             Stopwatch w = new Stopwatch();
    30             w.Start();
    31             while (i < 1000000)
    32             {
    33                 var ret = l.IsContinue();
    34                 if (ret)
    35                 {
    36                     okCount++;
    37                 }
    38                 else
    39                 {
    40                     noCount++;
    41                 }
    42                 i++;
    43             }
    44             w.Stop();
    45             Console.WriteLine($"共用{w.ElapsedMilliseconds},允许:{okCount},  拦截:{noCount}");
    46         }
    47     }

    测试结果:

    最大用时7秒,共处理请求1000000*50=50000000 次

    并未发生GC操作,内存使用率非常低,每秒处理 300万次+请求 。以上程序修改为10个线程,大约用时4秒之内

     如果是强劲的服务器或者线程数较少情况下处理速度将会更快!!!

    以上就是测试的限制高并发的一种简单方案,当然还有其他方式比如:令牌桶算法,漏桶算法等等,可以去研究下!

    以上仅为个人观点,如果错误,请大家指针,谢谢!

  • 相关阅读:
    iOS 2D绘图 (Quartz2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)
    iOS 2D绘图 (Quartz 2D) 概述
    HTML 学习笔记 JavaScript(创建对象)
    iOS NSFileManager 使用详解
    iOS 中 const static extern 关键字总结
    Tornado WEB服务器框架 Epoll
    Windows 数据盘自动分区脚本
    跨域请求测试代码-图片视频自动播放
    mail如何在linux中发送邮件,使用163邮箱发信。
    Linux系统CPU频率调整工具使用
  • 原文地址:https://www.cnblogs.com/skyfreedom/p/10746905.html
Copyright © 2011-2022 走看看