• Nginx + LUA下流量拦截算法


    前言

    每逢大促必压测,每逢大促必限流,这估计是电商人的常态。每次大促期间,业务流量是平时的几倍十几倍,大促期间大部分业务都会集中在购物车结算,必须限流,才能保证系统不宕机。

    限流算法

    限流算法一般有三种:令牌桶,漏桶,计数器。本文介绍最粗暴的计数器算法,其他算法请自行google、百度,讲的应该比我好。(能解决问题的算法都是好算法)

    lua 限流

    业务结构

    在大促期间由于流量过高,现有服务器无法承受那么大的流量,租用云服务是很好的选择。

    业务架构图可以看出 ,我们的服务器有自有服务器,首都在线云,金山云。自有服务器由于采购时间原因,每个批次的服务器性能不是很一致,首都在线云、金山云的服务器性能又有很大的差别,

    lvs在权重设置上也有很大的不同,这对我们使用lua限流又造成了一定的困扰。当然这只是小问题,既然lvs只是权重,那么我们的lua限流也支持权重即可。

    nginx+lua

    使用nginx+lua的原因很简单,我们服务架构nginx+fastcgi+php,为了防止php进程被打满,我们只需要在nginx加一层限制,就可以简单粗暴的解决问题,而lua正好满足这个条件。业务场景的不同,我们选择的算法也不同,越是复杂的东西,越希望最简单话的解决方案。引入越多的东西,就会造成更多的不确定性。

    话不多说上代

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    ngx.header.content_type = "text/html; charset=utf-8";
    local method=ngx.req.get_method()
    local curl=ngx.md5(ngx.var.request_uri);
    local request_uri_without_args = ngx.re.sub(ngx.var.request_uri, "\?.*", "");
    local match = string.match
    local ngxmatch=ngx.re.match
     
     
    --限流计数
    function limit_url_check(key,s,m)
           local localkey=key;
           local yyy_limit=ngx.shared.url_limit
            --每分钟限制
            local key_m_limit=  localkey..os.date("%Y-%m-%d %H:%M", ngx.time()) 
                --每秒限制
            local key_s_limit=  localkey..os.date("%Y-%m-%d %H:%M:%S", ngx.time())
            local req_key,_=yyy_limit:get(localkey);
            local req_key_s,_=yyy_limit:get(key_s_limit);
            local req_key_m,_=yyy_limit:get(key_m_limit);
            --每秒处理
            if req_key_s then
                     yyy_limit:incr(key_s_limit,1)
                     if req_key_s>s then 
                        --return true 
                   return false
                     end
           else
             yyy_limit:set(key_s_limit,1,60)
           end
            --每分钟处理
            if req_key_m then
                     yyy_limit:incr(key_m_limit,1)
                     if req_key_m>m then 
                        --return true
                        return false
                     end
            else
             yyy_limit:set(key_m_limit,1,85)
            end
            return false
    end

    代码很简单,但是很实用,看一下调用

    1
    2
    3
    4
    5
    6
    7
    if   ngx.re.match(request_uri_without_args,"/cart/inf(.*)") then
          if limit_url_check("appcartinfo",24,3200) then
              ngx.say('{"code": 524,"msg": "啊啊啊,每逢大促,排队结账。当前访问的用户过多,请稍后再试!","alert": "啊啊啊,每逢大促,排队结账。当前访问的用户过多,请稍后再试!"}')
              ngx.exit(200);
                   return
          end
    end

    调用的代码秒,分钟的限制数可以放到cjson中配置。

  • 相关阅读:
    UI/UE对个性化推荐的影响
    毫秒转换为天、小时、分、秒
    查生字
    探秘推荐引擎之协同过滤算法小综述
    给文献添加上标
    雅可比迭代和高斯赛德尔迭代
    广义二项式定理求解系数
    关于最大流的EdmondsKarp算法详解
    海量数据处理利器之布隆过滤器
    [leetcode] Path sum路径之和
  • 原文地址:https://www.cnblogs.com/sessionbest/p/9074955.html
Copyright © 2020-2023  润新知