zoukankan      html  css  js  c++  java
  • resty-limit-multiple-strategy.lua

    --[[
    执行过载限流策略
    --]]
    
    -- 当执行限流时,Nginx 返回的状态码
    err_code = 403
    
    local limit_config = {
      user_limit = {rate = 15, brust = 5},     --用户限流维度桶设置
      priority_uri_limit = {      --指定 URI 限流维度桶设置
        ['/elis_smp_portal_dmz/do/cms/getLittleRedDotInfo'] = {rate = 400, brust = 50},
        ['/elis_smp_portal_dmz/do/esa/portal.msgcenter.unreadv2'] = {rate = 400, brust = 50},
        ['/elis_smp_portal_dmz/do/home/getUpgradeReminder'] = {rate = 400, brust = 50},
        ['/elis_smp_portal_dmz/do/userLogin/checkPluginVersion'] = {rate = 400, brust = 50},
        ['/elis_smp_portal_dmz/do/createRYMSession'] = {rate = 400, brust = 50},
        ['/elis_smp_portal_dmz/do/zone/queryZoneConfig'] = {rate = 400, brust = 50}
      },
      error_status = err_code,     --请求被限流时返回状态码
      nodelay = no    --是否需要不延迟处理
    }
    
    --定义限流策略方法名称
    local limit_user_method = "limit_by_user"
    local limit_uri_method = "limit_by_priority_uri"
    
    local limit_req = require "resty.limit.req"
    
    ngx.req.read_body()
    
    --过载保护策略总开关,若开关关闭,则全部策略失效
    local limit_req_store = ngx.shared.limit_req_store
    local overload_protection_switch = limit_req_store:get("overload_protection_switch")
    if (overload_protection_switch ~= nil and overload_protection_switch == "N") then
            ngx.log(ngx.INFO, "nginx limit strategy has been shutdown.")
        return
    end
    
    -- 获取当前请求 URI
    local cur_uri = ngx.var.uri
    
    -- 执行过载操作
    local is_in_black_list = limit_req_store:get("black_list:"..cur_uri)
    local is_rejected_uri = reject_uri_tab["rejected"..cur_uri]
    if (is_in_black_list ~= nil or is_rejected_uri ~= nil) then
      -- 拦截比例,默认全部拦截
      local request_limit_percent = limit_req_store:get("reject_request_percent")
      if request_limit_percent == nil then
        request_limit_percent = 100
      end
      local random_num = math.random(100)
      if random_num <= tonumber(request_limit_percent)  then
          ngx.log(ngx.ERR,"nginx limit strategy current uri=",cur_uri," has been rejected.")
          ngx.exit(ngx.HTTP_FORBIDDEN)
      end
    end
    
    -- 执行限流策略,入参:key 和 commit,commit 默认为 true
    local function execute_limit_strategy(lim, key, commit, method)
      --  请求流入,如果你的请求需要被延迟则返回delay>0
      local delay, err = lim:incoming(key, commit)
      if (not delay and err == "rejected") then
        ngx.log(ngx.ERR, "nginx limit strategy: ",method,", key: ", key, " request rate was exceeded, current request was rejected.")
        ngx.exit(limit_config.error_status)
      end
    
      -- 根据需要决定延迟或者不延迟处理
      if delay > 0 then
        if limit_config.nodelay then
          -- 直接突发处理
          -- ngx.log(ngx.ERR, "nginx limit strategy: ", method, ", key: ", key, " request rate was exceeded, current request was rejected. delay")
          -- ngx.exit(error_status)
        else
          --延迟处理
          ngx.sleep(delay)
        end
      end
    end
    
    -- 获取限流策略的共享内存
    local function get_shared_dict(shared_dict_name, rate, burst)
      local limit_shared_dict, err = limit_req.new(shared_dict_name, rate, burst)
      if not limit_shared_dict then --没定义共享字典
        ngx.log(ngx.ERR, "Nginx limit shared dict:", shared_dict_name, " has not been set.")
        ngx.exit(error_status)
      end
      return limit_shared_dict
    end
    
    
    -- 初始化 URL 限流策略 table
    local uri_limit_tab = {}
    
    local user_lim
    
    if limit_config == nil then
      ngx.log(ngx.ERR, "nginx request limit has no config info.")
      return
    else
      local user_limit_config = limit_config.user_limit
      ngx.log(ngx.DEBUG,"limit config user rate:", user_limit_config.rate, ", brust:", user_limit_config.brust)
      user_lim = get_shared_dict("limit_req_store",user_limit_config.rate, user_limit_config.brust)
      local priority_uri_limit_config = limit_config.priority_uri_limit
      for key, value in pairs(priority_uri_limit_config) do
        local rate = value.rate
        local brust = value.brust
        ngx.log(ngx.DEBUG,"limit config uri:", key, ", rate:", rate,", brust:",brust)
        local lim = get_shared_dict("limit_req_store",rate,brust)
        uri_limit_tab[key]=lim
      end
    end
    
    -- 执行指定 URI 限流策略
    if uri_limit_tab[cur_uri] ~= nil then
      execute_limit_strategy(uri_limit_tab[cur_uri], cur_uri , true , limit_uri_method)
    end
    
    -- 获取客户端请求 IP
    local remote_ip = ngx.var.remote_addr
    local user_id
    local device_id
    local key_by_user
    
    --  获取用户ID 或 设备号
    local request_method = ngx.var.request_method
    if "GET" == request_method then
      user_id = ngx.req.get_uri_args()["uid"]
      device_id = ngx.req.get_uri_args()["deviceId"]
      ngx.log(ngx.DEBUG, "nginx request limit module GET parameter user_id: ",user_id, " header:",device_id)
    elseif "POST" == request_method then
      -- 获取请求头信息,如果缺少请求头信息判断,遇到上传文件操作时,会引起ngx.req.get_post_args()操作异常。
      local receive_headers = ngx.req.get_headers()
      local body_data = ngx.req.get_body_data()
      if not body_data or (receive_headers["content-type"] ~= nil and string.sub(receive_headers["content-type"],1,20) == "multipart/form-data;") then
        ngx.log(ngx.WARN,"nginx request limit module uri: ",cur_uri, " header:",receive_headers["content-type"],", body data:",body_data)
        return
      end
      user_id = ngx.req.get_post_args()['uid'];
      device_id = ngx.req.get_post_args()['deviceId'];
      ngx.log(ngx.DEBUG, "nginx request limit module POST parameter user_id: ",user_id, " device_id:",device_id)
    end
    
    -- 调试日志
    ngx.log(ngx.ERR, "nginx request limit module cur_uri:",cur_uri, ", user_id: ",user_id)
    
    if (user_id ~= nil or device_id ~= nil) then
      if user_id ~= nil then
        key_by_user = user_id
      else
        key_by_user = device_id
      end
      execute_limit_strategy(user_lim,key_by_user..":"..remote_ip, true, limit_user_method)
    end
  • 相关阅读:
    pyCharm报错"your evaluation license has expired, pycharm will now exit"解决方法(实测)
    (转)python selenium-webdriver 元素操作之鼠标和键盘事件
    转载:PICT使用教程(设计测试用例工具)
    转载:小米电视怎么安装爱奇艺
    关于VMware 15搭建MacOS 10.14后无法播放在线视频和客户端视频的问题
    Reference resources
    centos7 启用iptables
    disabling IPv6 name/address support: Address family not supported by protocol
    rngd.service 启动失败的处理
    mdadm Raid5 /dev/md0 lost a disk and recovery from another machine
  • 原文地址:https://www.cnblogs.com/koushr/p/5873416.html
Copyright © 2011-2022 走看看