OpenResty使用漏桶算法实现限流

2023-09-20 10:57:26

前言

其它项目组需要调用接口,添加接口限流,防止项目被狂掉宕机。生产用了openresty,所以在openresty上添加按接口限流,同时,需按照不同接口有不同的限流规则,使用openresty中内置的漏桶算法方式限流。

漏桶算法

漏桶算法思路简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水,当水流入速度过大会直接溢出,可以看出漏桶算法能强行限制数据的传输速率。

通俗解释。

比如设置rate为100,burst为50,即允许1s放进来100个请求,桶大小为50。

那么1s内:

第1-100个请求会访问成功。

第101-150个请求会进入burst。

第150个请求之后的会直接失败返回。

openresty的说明文档:https://github.com/openresty/lua-resty-limit-traffic/blob/master/lib/resty/limit/req.md

限流配置

使用OpenResty的漏桶算法进行限流配置,不同接口配置不同的标准,所以测试了两个接口test1和test2

主要分两步:

  1. 添加限流使用的lua脚本
  2. 在反向代理中配置限流的lua脚本

ps: 因为大多数使用情况还是会反向代理,所以直接在反向代理中配置lua

添加lua脚本01和02的区别,仅限于漏桶的参数配置不同

添加lua脚本01

lualib\utils 路径下创建lua脚本

lua脚本内容:

-- utils/limit_req_leaky_bucket.lua
local limit_req = require "resty.limit.req"

-- rate:  5/s即为每秒3个请求,增加桶容量为1/s,超过5/s不到(5+1)/s的delay,排队等候
local lim, err = limit_req.new("my_limit_req_store1", 5, 1)
if not lim then
    ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)
    return ngx.exit(500)
end

local _M = {}


function _M.incoming()
    local key = ngx.var.binary_remote_addr
    local delay, err = lim:incoming(key, true)
    if not delay then
        if err == "rejected" then
            return ngx.exit(503) -- 超过的请求直接返回503
        end
        ngx.log(ngx.ERR, "failed to limit req: ", err)
        return ngx.exit(500)
    end
    
    -- 此方法返回,当前请求需要delay秒后才会被处理,和他前面对请求数
    -- 所以此处对桶中请求进行延时处理,让其排队等待,就是应用了漏桶算法
    -- 此处也是与令牌桶的主要区别
    if delay >= 0.001 then
        ngx.sleep(delay)
    end
end

return _M

添加lua脚本02

lualib\utils 路径下创建lua脚本

lua脚本内容:

-- utils/limit_req_leaky_bucket.lua
local limit_req = require "resty.limit.req"

-- rate:  3/s即为每秒3个请求,增加桶容量为1/s,超过3/s不到(3+1)/s的delay,排队等候
local lim, err = limit_req.new("my_limit_req_store2", 3, 1)
if not lim then
    ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)
    return ngx.exit(500)
end

local _M = {}


function _M.incoming()
    local key = ngx.var.binary_remote_addr
    local delay, err = lim:incoming(key, true)
    if not delay then
        if err == "rejected" then
            return ngx.exit(503) -- 超过的请求直接返回503
        end
        ngx.log(ngx.ERR, "failed to limit req: ", err)
        return ngx.exit(500)
    end
    
    -- 此方法返回,当前请求需要delay秒后才会被处理,和他前面对请求数
    -- 所以此处对桶中请求进行延时处理,让其排队等待,就是应用了漏桶算法
    -- 此处也是与令牌桶的主要区别
    if delay >= 0.001 then
        ngx.sleep(delay)
    end
end

return _M

在nginx.conf中添加配置文件

# --- 限流 ---
worker_processes  1;

events {
    worker_connections  1024;
}
# ------------


http {
    # --- 反向代理 ---
    include       /etc/nginx/conf.d/*.conf;
    # -----------------------


    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    # --- 限流 ---
    lua_code_cache on;
   
    # 共享内存
    lua_shared_dict my_limit_req_store1 100M;
    lua_shared_dict my_limit_req_store2 100M;
    # -----------

    # --- 反向代理 ---
    upstream backend_server {
        server 127.0.0.1:8080;
    }
    # -----------------------

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }



        location /test1 {
            
            # --- 限流 ---
            access_by_lua_block {
                local limit_count = require "utils.limit_req_leaky_bucket1"
                -- 对于内部重定向或子请求,不进行限制。因为这些并不是真正对外的请求。
                if ngx.req.is_internal() then
                    return
                end
                limit_count.incoming()
            }
            # ------------

            # --- 反向代理 ---
            # 如果内容源是反向代理
            proxy_pass http://backend_server;
            proxy_set_header Host $host;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_connect_timeout 60;
            proxy_read_timeout 600;
            proxy_send_timeout 600;
            # -----------------------

        }

        location /test2 {
            
            # --- 限流 ---
            access_by_lua_block {
                local limit_count = require "utils.limit_req_leaky_bucket2"
                -- 对于内部重定向或子请求,不进行限制。因为这些并不是真正对外的请求。
                if ngx.req.is_internal() then
                    return
                end
                limit_count.incoming()
            }
            # ------------

            # --- 反向代理 ---
            # 如果内容源是反向代理
            proxy_pass http://backend_server;
            proxy_set_header Host $host;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_connect_timeout 60;
            proxy_read_timeout 600;
            proxy_send_timeout 600;
            # -----------------------

        }

    }

}

参考

http://www.guanshanw.com/post/67951.html

更多推荐

【Oracle】Oracle系列之四--用户管理

文章目录往期回顾前言1.创建/删除用户(1)创建用户(2)修改口令(3)删除用户2.用户授权管理(1)对用户直接授权(2)通过角色对用户授权往期回顾【Oracle】Oracle系列–Oracle数据类型【Oracle】Oracle系列之二–Oracle数据字典【Oracle】Oracle系列之三–Oracle字符集前言

【Java 基础篇】Java 文件及文件夹操作详解

在Java编程中,文件和文件夹操作是常见的任务之一。你可能需要读取、写入、创建、删除文件或文件夹,以及遍历文件系统中的内容。本文将详细介绍Java中如何执行这些常见的文件和文件夹操作,适用于初学者和基础用户。1.文件操作读取文件内容在Java中,你可以使用FileInputStream或BufferedReader来读

蓝桥杯2023年第十四届省赛真题-买瓜--C语言题解

目录蓝桥杯2023年第十四届省赛真题-买瓜题目描述输入格式输出格式样例输入样例输出提示【思路解析】【代码实现】蓝桥杯2023年第十四届省赛真题-买瓜时间限制:3s内存限制:320MB提交:796解决:69题目描述小蓝正在一个瓜摊上买瓜。瓜摊上共有n个瓜,每个瓜的重量为Ai。小蓝刀功了得,他可以把任何瓜劈成完全等重的两份

Linux磁盘管理:最佳实践

🌷🍁博主猫头虎(🐅🐾)带您GotoNewWorld✨🍁🦄博客首页——🐅🐾猫头虎的博客🎐🐳《面试题大全专栏》🦕文章图文并茂🦖生动形象🐅简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》🐾学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》🐅学会Gol

算法通关村第14关【白银】| 堆的经典问题

1.数组中的第k个最大元素思路:最直观的就是选择法,遍历一k次找到第k大的数之前使用快速排序的思想每次找出一个位置,会超时这里使用堆(优先队列),找最大用小堆,找最小用大堆。例如找第k大的数,新建一个空间为k的最小优先队列,只要比当前优先队列最小值大就替换进去,这样全部的数遍历一遍,里面留下的就是前k大的数了,其他的全

科目二倒车入库

调整座位和后视镜离合踩到底大腿小腿成130-140°上半身90-100°座椅高度能看到前方全部情况后视镜调节到能看到后门把手,且后门把手刚好在后视镜上方边缘、离车1/3处。保持直线:前进:车仪表盘中央的原点和地面上的黄线擦边,这就是离右侧30-40cm倒车:右后视镜中一个手指的宽度对应地面15cm倒车观察右后视镜,车门

1.什么是jwt?jwt的作用是什么?2.jwt的三个部分是什么?三者之间的关系如何?3.JWT运行的流程是什么

1.**什么是JWT?JWT的作用是什么?**JWT(JSONWebToken)是一种用于在不同系统或组件之间传输信息的紧凑且安全的标准。它的作用主要有两个方面:-**身份验证(Authentication)**:JWT通常用于验证用户的身份。当用户登录时,服务器会生成一个JWT,并将其发送给客户端。客户端随后在每个请

按钮和文本框事件监听

事件监听:当某个事情发生的时候,干什么一、按钮Button监听publicclassTestActionEvent{publicstaticvoidmain(String[]args){//按下按钮,触发一些事件Frameframe=newFrame();//弹窗的监听事件/*frame.addWindowListen

如何使用国际站腾讯云服务器进行手机测速

怎么运用腾讯云服务器进行手机测速,包括挑选适宜的服务器、装置测速软件、设置测验参数等过程。腾讯云服务器是一款高性能、高可靠性的云核算服务,能够满足用户在不同场景下的需求。而在手机测速方面,腾讯云服务器相同有着出色的表现。本文将介绍怎么运用腾讯云服务器进行手机测速,帮助用户了解自己的网络速度。首要,挑选适宜的服务器是进行

HTTPS的加密流程

对称加密:只有一个密钥。加密:明文+密钥=>密文;解码:密文+密钥=>明文。非对称加密:有两个密钥,一个公钥,一个私钥。加密:明文+公钥=>密文;解码:密文+私钥=>明文;或加密:明文+私钥=>密文;解码:密文+公钥=>明文。HTTPS的基本工作过程:加密:针对HTTP的各种header和body1.使用对称密钥,来保

正则匹配手机、邮箱、密码

正则匹配手机、邮箱、密码publicabstractclassRegexPatterns{/***手机号正则*/publicstaticfinalStringPHONE_REGEX="^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$";/***邮箱

热文推荐