zoukankan      html  css  js  c++  java
  • 分享一个nginx流量限制脚本

    针对接口进行总流量限制(熔断)

    有些朋友可能会联想到用Nginx自带的limit_req功能来限制访问频率, 这种方案通常是基于IP限制, 是为了防止用户恶意的刷请求量访问. 这里我要介绍的是另一种情况, 接口的qps已经很高, 后端无法接受更多的请求. 这个是时候需要的就是针对整个接口进行限速.

    我贴一种比较简单的实现:

    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
    local limit = {}

    local function safe_incr(dict, key, timeout)
    local ok
    local newval, err = dict:incr(key, 1)
    if not newval and err == "not found" then
    newval = 1
    ok, err = dict:safe_add(key, newval, timeout)
    if not ok then
    if err == "exists" then
    newval, err = dict:incr(key, 1)
    elseif err == "no memory" then
    dict:add(key .. "|no memory", 0, timeout)
    end
    end
    end
    return newval
    end

    function limit.limit(dict, key, freq, err_code, err_msg, content_type)
    dict:set(key .. '|freq', freq)

    local time = ngx.time()
    local k = key .. '|' .. tostring(time)
    local newval = safe_incr(dict, k, 70)

    if newval > freq then
    -- local limit_info = ngx.shared.limit_info
    -- safe_incr(limit_info, k, 70)

    ngx.sleep(1)
    ngx.status = err_code
    ngx.header.content_type = content_type or 'application/json'
    ngx.print(err_msg)
    ngx.exit(ngx.status)
    end
    end

    return limit

    然后在Nginx的配置中这样使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    lua_shared_dict xxx_0 10M;
    server {
    listen 80;
    server_name aaa.bbb.com;

    location = /redis/incr {
    access_by_lua_block {
    local limit = require("limit")
    limit.limit(ngx.shared.xxx_0, 'PSAvcmVkaXMvaW5jcg==', 5, ngx.HTTP_FORBIDDEN, '{"reason": "请求排队中,请稍后重试……", "code": 500}', 'application/json')
    }
    proxy_pass http://xxxxx;
    }
    }

    强制重定向https功能的实现

    对于一般的网站, 重定向https一般是通过rewrite来实现的, 比如下面这样的配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    server {
    listen 80;
    ...
    return 301 https://$server_name$request_uri;
    }

    server {
    listen 443;
    ...
    }

    这样的配置只适合放在最外层的Nginx, 假如没有放在用户访问的的入口Nginx, 那么会出现类似下图所示的循环重定向问题.

    图片

    所以, 出现多层Nginx的情况, 最简单的方案就是在首层Nginx进行https重定向, 内部全部使用http流量.

    但是考虑下面一种情况:

    而且对于一个PaaS平台来说, 并不是所有的应用都想要强制https, 首层的Nginx也不由我们来控制, 不过它会给我们传递一个这样的header, 表明请求为https的形式:X-Forwarded-Proto: https,

    这种时候比较合适的选择是在平台的这一层Nginx中增加对于请求方法的判断, 根据header中的forwarded-proto, 有两种方案在中间层解决:

    1. 一种使用Nginx的if语句

    1
    2
    3
    4
    5
    6
    7
    8
    9
    server{
    listen *:80;
    server_name mydomain.com www.mydomain.com;

    if ($http_x_forwarded_proto = "http") {
    return 301 https://$server_name$request_uri;
    }
    // location xxx
    }
    1. 一种更加优雅的方案(使用Lua):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    server {
    listen 80;
    add_header Strict-Transport-Security "max-age=31536000" always;
    # 使用lua能使得逻辑更加清晰
    rewrite_by_lua_block {
    local _request_uri = ngx.var.request_uri
    local _host = ngx.var.host
    if ngx.var.http_x_forwarded_proto == nil or ngx.var.http_x_forwarded_proto == 'http' then
    return ngx.redirect('https://'.._host.._request_uri, ngx.HTTP_MOVED_PERMANENTLY)
    end
    }
    // location xxx
    }

    由于我们的项目本身已经用了Nginx+Lua, 所以直接采用了第二种方案, 如果你使用的是普通的Nginx, 就用if语句吧

  • 相关阅读:
    【转载】关于sql server 代理(已禁用代理xp)
    Silverlight中将WriteableBitmap互转byte数组
    思迅Pay PC ,WIN7 ,KB3042058
    微软新Edge浏览器 WIN7 无法登录
    List<SelectListItem> 转为 SelectList
    图片jpg,png转为BASE64编码
    “Newtonsoft.Json”已拥有为“Microsoft.CSharp”定义的依赖项。
    mac os 10.15.1 懒人 .CDR
    微信刷脸SDK获取sub_openid
    win7 安装 visual studio 2019 时闪退(VS2019)
  • 原文地址:https://www.cnblogs.com/cheyunhua/p/14636170.html
Copyright © 2011-2022 走看看