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
  • 相关阅读:
    949. Largest Time for Given Digits
    450. Delete Node in a BST
    983. Minimum Cost For Tickets
    16. 3Sum Closest java solutions
    73. Set Matrix Zeroes java solutions
    347. Top K Frequent Elements java solutions
    215. Kth Largest Element in an Array java solutions
    75. Sort Colors java solutions
    38. Count and Say java solutions
    371. Sum of Two Integers java solutions
  • 原文地址:https://www.cnblogs.com/koushr/p/5873416.html
Copyright © 2011-2022 走看看