zoukankan      html  css  js  c++  java
  • QPS

    接口限流预案

    一、限流前提

    限制资源使用速率,在互联网中一般是:

    限制请求总量(秒杀)或某段时间内请求总量(攻击/服务资源有限)

    1. 访问耗时
      接口响应速度

      时间 描述
      <500ms
      >1.5s 慢(优化)
      >3s
    2. 访问频次

      名词 含义
      QPS 每秒查询
      TPS 每秒事务
      RT 响应时间
      PV 一次刷新或一次请求
      并发数 系统同时能处理的请求数量
      吞吐量 单个request 对CPU消耗越高,外部系统接口、IO速度越慢,系统吞吐能力越低,反之越高

      公式:按二八定律来看,如果每天 80% 的访问集中在 20% 的时间里,这 20% 时间就叫做峰值时间。

      • QPS(TPS)= 并发数/平均响应时间
      • 并发数 = QPS*平均响应时间
      • ( 总PV数 * 80% ) / ( 每天秒数 * 20% ) = 峰值时间每秒请求数(QPS)
      • 峰值时间每秒QPS / 单台机器的QPS = 需要的机器
    3. 实施方法

      • 先通过JMeter测出接口的 QPS
      • 根据接口请求数统计算出 峰值QPS

      峰值QPS>QPS 可能就需要限流

    二、限流方式

    1. 接口内部限制线程数

      private readonly static Semaphore _semaphore = new Semaphore(4, 8);
      try
      {
          _semaphore.WaitOne();
          // Do Something
      }
      finally
      {
          _semaphore.Release();
      }
      

      这种只是限制并发的线程数,外部请求是处于等待状态,最终都会返回,除非客户端超时处理。

    2. IP同源限流

      借助AspNetCoreRateLimit中间件实现IP同源限流,先安装中间件

      Install-Package AspNetCoreRateLimit
      Install-Package Microsoft.Extensions.Caching.Redis // Redis分布式缓存
      
      services.AddDistributedRedisCache(options =>
          {
              options.Configuration = "127.0.0.1:6379,password=123456,connectTimeout=5000,syncTimeout=10000";
              options.InstanceName = "WebRatelimit";
          });
      //从appsettings.json获取相应配置
      services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
      //注入计数器和规则存储
      services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>();
      services.AddSingleton<IRateLimitCounterStore, DistributedCacheRateLimitCounterStore>();
      services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
      //配置(计数器密钥生成器)
      services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
      
      //启用限流,需在UseMvc前面
      app.UseIpRateLimiting();
      
    3. Nginx限流

      • 限制访问频率

        Nginx中使用ngx_http_limit_req_module模块来限制的访问频率

        http {
            limit_req_zone $binary_remote_addr zone=myLimit:10m rate=5r/s;
        }
        
        server{
            location / {
                limit_req zone=myLimit burst=5 nodelay;
                rewrite / http://www.xxx.com permanent;
            }
        }
        

        上面binary_remote_addr就是key,表示基于客户端ip(remote_addr)进行限流,binary_表示压缩内存占用量。定义了一个大小为10M,名称为myLimit的内存区,用于存储IP地址访问信息。rate设置IP访问频率,rate=5r/s表示每秒只能处理每个IP地址的5个请求。Nginx限流是按照毫秒级为单位的,也就是说1秒处理5个请求会变成每200ms只处理一个请求。如果200ms内已经处理完1个请求,但是还是有有新的请求到达,这时候Nginx就会拒绝处理该请求。burst=5 nodelay,如果没有添加nodelay参数,则可以理解为预先在内存中占用了5个请求的位置,如果有5个突发请求就会按照200ms去依次处理请求,也就是1s内把5个请求全部处理完毕。如果1s内有新的请求到达也不会立即进行处理,因为紧急程度更低。这样实际上就会将额外的5个突发请求以200ms/个去依次处理,保证了处理速率的稳定,所以在处理突发流量的时候也一样可以正常处理。如果添加了nodelay参数则表示要立即处理这5个突发请求。

      • 限制并发连接数

        Nginx中的ngx_http_limit_conn_module模块提供了限制并发连接数的功能

        http {
            limit_conn_zone $binary_remote_addr zone=myip:10m;
            limit_conn_zone $server_name zone=myServerName:10m;
        }
        
        server{
            location / {
                limit_conn myip 10;
                limit_conn myServerName 100;
                rewrite / http://www.xxx.com permanent;
            }
        }
        

        上面配置了单个IP同时并发连接数最多只能10个连接,并且设置了整个虚拟服务器同时最大并发数最多只能100个链接。当然,只有当请求的header被服务器处理后,虚拟服务器的连接数才会计数。刚才有提到过Nginx是基于漏桶算法原理实现的,实际上限流一般都是基于漏桶算法令牌桶算法实现的。

    4. RabbitMq限流/消峰

      如秒杀场景,有50000份,根据RabbitMq限制接受6000/8000请求,其他拒绝。

    三、实施计划

    1. 目前采用第二种方案,原因:

      第一种用户交互会不太友好,当访问量满的时候,后面的用户需要持续等待直至超时;
      第三种需要运维配置,没有自己配置灵活;
      第四种一般用于限流消峰处理。

    2. 测试监听限流配置(11-10)

      通过监听配置文件,限制接口频次,不用重启应用

    3. 找出需要限流的接口(11-11)

      • 统计访问量前十接口
      • 统计响应慢前十接口
    4. 测出合适限流频次(11-12/13)

      灰度环境测试这些接口的吞吐量,然后设定限流频次

    四、实施

    1. 配置初始化时加载,无法动态配置,修改配置后还需重启。

    2. 接口统计

      • 高流量接口

        url rate count
        /api/services/app/BasicSet/GetBasicsetThemecolor 5.38% 2,098,111
        /api/TokenAuth/AuthenticateMobile 5.32% 2,074,173
        /api/services/app/SuspendedWindow/GetSuspendedWindowResp 4.11% 1,603,795
        /promotion/offer-service/app/activity/getMeetGiftList 3.96% 1,545,701
        /promotion/offer-service/app/activity/getActivityProductList 3.91% 1,523,793
        /promotion/offer-service/app/activity/getBatchActivityProductStock 3.87% 1,508,272
        /api/services/app/Advertise/GetInfo 3.72% 1,451,478
        /api/services/app/VipInfo/GetBasicSetDto 3.27% 1,277,221
        /OperAtion/t?operation=viptypesyncnew 2.86% 1,116,057
        /api/TokenAuth/IsRefresh 2.66% 1,037,517
      • 响应耗时

        request_time rate count
        0.01600000075995922 13.79% 290,258
        0.004000000189989805 11.20% 235,863
        0.017000000923871994 9.97% 209,867
        0.014999999664723873 8.97% 188,790
        0.003000000026077032 7.62% 160,481
        0.017999999225139618 5.97% 125,772
        0.014000000432133675 5.00% 105,281
        0.01899999938905239 4.10% 86,272
        0.007000000216066837 3.30% 69,393
        0.004999999888241291 2.78% 58,457

        响应都很快了

    3. 灰度测试

      频繁访问前十接口QPS测试

      url rate count 峰值QPS QPS T-QPS1 T-QPS2 T-QPS3
      /api/services/app/BasicSet/GetBasicsetThemecolor 5.38% 2,098,111 97.13476852 82.6 40.9 41.6 47.1
      /api/TokenAuth/AuthenticateMobile 5.32% 2,074,173 96.02652778 49.2 50.9 51
      /api/services/app/SuspendedWindow/GetSuspendedWindowResp 4.11% 1,603,795 74.24976852 71.9 118.6 186
      /promotion/offer-service/app/activity/getMeetGiftList 3.96% 1,545,701 71.56023148
      /promotion/offer-service/app/activity/getActivityProductList 3.91% 1,523,793 70.54597222
      /promotion/offer-service/app/activity/getBatchActivityProductStock 3.87% 1,508,272 69.82740741
      /api/services/app/Advertise/GetInfo 3.72% 1,451,478 67.19805556 178.3 175.1 184.3
      /api/services/app/VipInfo/GetBasicSetDto 3.27% 1,277,221 59.13060185 26.9 12.6 12.5
      /OperAtion/t?operation=viptypesyncnew 2.86% 1,116,057 51.66930556 40.2 83 56.8
      /api/TokenAuth/IsRefresh 2.66% 1,037,517 48.03319444 125.9 125.8 117.2
    4. 限流建议

  • 相关阅读:
    阿里消息队列中间件 RocketMQ 源码分析 —— Message 拉取与消费(上)
    数据库中间件 ShardingJDBC 源码分析 —— SQL 解析(三)之查询SQL
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 解析(六)之删除SQL
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 解析(五)之更新SQL
    消息队列中间件 RocketMQ 源码分析 —— Message 存储
    源码圈 300 胖友的书单整理
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 路由(一)分库分表配置
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 解析(四)之插入SQL
    数据库分库分表中间件 ShardingJDBC 源码分析 —— SQL 路由(二)之分库分表路由
    C#中Math类的用法
  • 原文地址:https://www.cnblogs.com/Nine4Cool/p/13959662.html
Copyright © 2011-2022 走看看