OpenResty单机限流

目录

  • 该项目已经实现的限流方法
  • 限流流程图
      • 限流规则存储
      • 针对接口限流
  • 限流算法实现主要代码部分
      • 固定窗口
      • 令牌桶
      • 限制并发数
  • 注意点

前言: 上一篇文章介绍了OpenResty的安装和lua的基本语法学习,这一篇介绍一下使用OpenResty进行限流。本文只对限流功能实现做简单介绍,不对限流算法原理做过多解释。

该项目已经实现的限流方法

  • 固定窗口(限制单位时间内接口可以请求的数量)
  • 令牌桶
  • 计数器(限制接口并发连接数)

限流流程图

限流规则存储

在这里插入图片描述

针对接口限流

在这里插入图片描述

限流算法实现主要代码部分

固定窗口

time_range_request_count(rule_detail)local request_uri = ngx.var.urilocal limitTimeRange = rule_detail.limitTimeRangelocal limitNum = rule_detail.limitNumif not limitTimeRange or not limitNum thenngx.log(ngx.ERR, "limitTimeRange or limitNum is nil")returnend-- 检查 limitTimeRange 和 limitNum 的类型if type(limitTimeRange) ~= "number" or type(limitNum) ~= "number" thenngx.log(ngx.ERR, "limitTimeRange 或 limitNum 的类型不是数字","rule_detail: "..cjson.encode(rule_detail))returnendlocal lim, err = limit_count.new("api_rate_limit_req_store", limitNum, limitTimeRange)if not lim thenngx.log(ngx.ERR, "创建限流器失败 err: ", err.." rule_detail: "..cjson.encode(rule_detail).." uri: "..request_uri)--return ngx.exit(500)baseUtil.api_rate_limit_res(500,500,"服务器异常")endlocal delay, response = lim:incoming(request_uri, true)if not delay thenif response == "rejected" thenngx.log(ngx.ERR, "限制请求数 rejected: "," rule_detail: "..cjson.encode(rule_detail).." uri: "..request_uri)--return ngx.exit(429)baseUtil.api_rate_limit_res(429,429,"服务器异常")endngx.log(ngx.ERR, "failed to limit count: ", tostring(response).." rule_detail: "..cjson.encode(rule_detail).." uri: "..request_uri)--return ngx.exit(500)baseUtil.api_rate_limit_res(500,500,"服务器异常")end
endreturn {time_range_request_count = time_range_request_count
}

令牌桶

local limit_req = require "resty.limit.req"
local cjson = require "cjson"
local baseUtil = require "BaseUtil"-- 令牌桶算法限流
local function token_bucket_algorithm(rule_detail)local request_uri = ngx.var.uri-- 限流速率 r/slocal rate = rule_detail.rate-- 令牌数量local burst = rule_detail.burst-- 检查 rate 和 burst 的类型if type(rate) ~= "number" or type(burst) ~= "number" thenngx.log(ngx.ERR, "rate 或 burst 的类型不是数字","rule_detail: "..cjson.encode(rule_detail))returnendlocal lim, err = limit_req.new("api_rate_limit_req_store", rate, burst)if not lim thenngx.log(ngx.ERR, "令牌桶限流,创建限流器失败", err)--return ngx.exit(500)baseUtil.api_rate_limit_res(500,500,"服务器异常")end-- 调用限流器local delay, response = lim:incoming(request_uri, true)if not delay thenif response == "rejected" thenngx.log(ngx.ERR, "限制请求数 rejected: "," rule_detail: "..cjson.encode(rule_detail).." uri: "..request_uri)--return ngx.exit(429)  -- 返回 HTTP 429 状态码baseUtil.api_rate_limit_res(429,429,"服务器异常")endngx.log(ngx.ERR, "调用限流器失败: ", tostring(response).." rule_detail: "..cjson.encode(rule_detail).." uri: "..request_uri)--return ngx.exit(500)baseUtil.api_rate_limit_res(500,500,"服务器异常")end-- 如果请求没有超过限制,正常处理请求if delay >= 0 thenngx.sleep(delay)end
endreturn {token_bucket_algorithm = token_bucket_algorithm
}

限制并发数

local limit_conn = require "resty.limit.conn"
local cjson = require "cjson"
local baseUtil = require "BaseUtil"-- 限制最大并发连接数
local function concurrent_connections(rule_detail)local key = ngx.var.urilocal concurrentNum = rule_detail.concurrentNumlocal concurrentExtraNum = rule_detail.concurrentExtraNumlocal concurrentTime = rule_detail.concurrentTime-- 检查 concurrentNum、concurrentExtraNum、concurrentTime 的类型if type(concurrentNum) ~= "number" or type(concurrentExtraNum) ~= "number" or type(concurrentTime) ~= "number"thenngx.log(ngx.ERR, "concurrentNum 或 concurrentExtraNum 或 concurrentTime 的类型不是数字","rule_detail: "..cjson.encode(rule_detail))returnendlocal lim, err = limit_conn.new("api_rate_limit_req_store", concurrentNum, concurrentExtraNum, concurrentTime)if not lim thenngx.log(ngx.ERR, "限制最大并发连接数,创建限流器失败", err)baseUtil.api_rate_limit_res(500,500,"服务器异常")endlocal delay, response = lim:incoming(key, true)if not delay thenif response == "rejected" thenngx.log(ngx.ERR, "限制请求数 rejected: "," rule_detail: "..cjson.encode(rule_detail).." uri: "..key)baseUtil.api_rate_limit_res(429,429,"服务器异常")endngx.log(ngx.ERR, "failed to limit req: ", tostring(response).." rule_detail: "..cjson.encode(rule_detail).." uri: "..key)baseUtil.api_rate_limit_res(500,500,"服务器异常")end-- 如果请求没有超过并发限制,那么将连接信息添加到ngx.ctx中if lim:is_committed() thenlocal ctx = ngx.ctxctx.limit_type = "concurrent_connections"ctx.limit_conn = limctx.limit_conn_key = keyctx.limit_conn_delay = delayendif delay >= 0.001 thenngx.log(ngx.WARN, "delaying conn, excess ", delay, "s per binary_remote_addr by limit_conn_store")ngx.sleep(delay)end
end-- 请求离开,减少数量
local function concurrent_connections_leaving()local ctx = ngx.ctxlocal lim = ctx.limit_connif lim thenlocal key = ctx.limit_conn_keylocal latency = ctx.limit_conn_delaylocal limit_type = ctx.limit_typeif not limit_type thenreturnendif limit_type ~= "concurrent_connections" thenreturnend--ngx.log(ngx.ERR, "释放连接", "request: ", key.." latency: "..latency)local conn, err = lim:leaving(key, latency)if not conn thenngx.log(ngx.ERR, "failed to record the connection leaving ", "request: ", err.." key: "..key)returnendend
endreturn {concurrent_connections = concurrent_connections,concurrent_connections_leaving = concurrent_connections_leaving
}

注意点

  • 实际情况下,生产nginx会存在多台,所以这里将规则存储在redis当中
  • OpenResty本身只支持单机的redis连接,所以这里需要单独引入redis集群模块。参考地址:https://developer.aliyun.com/article/1334650

上面就是几种限流算法用lua实现的关键部分逻辑,代码仅供参考学习,欢迎留言讨论。后续会将完整的项目代码更新到远程仓库,欢迎关注我的公众号,后续会在公众号提供获取地址。下一篇会继续更新使用redis来实现上面几种限流逻辑,进行集群限流
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/327312.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BLDC电机基础知识

1、电机工作原理 电机输入的是电能输出机械能,即电机是一种将电能转换为机械能的装置。电机利用磁场的同名磁极互相排斥以及电磁场原理完成电能与机械能的转换。 由物理电磁场理论知识我们知道,磁铁周围存在磁场,同时运动的电荷或通电导线周…

将 Vue、React、Angular、HTML 等一键打包成 macOS 和 Windows 平台客户端应用

应用简介 PPX 基于 pywebview 和 PyInstaller 框架,构建 macOS 和 Windows 平台的客户端。本应用的视图层支持 Vue、React、Angular、HTML 中的任意一种,业务层支持 Python 脚本。考虑到某些生物计算场景数据量大,数据私密,因此将…

uniapp的底部弹出层实现保姆式教程

实现照片: 此过程先进入uniapp官网,找到扩展组件 打开找到里面的uni-popup和uni-icons 点击进入,下载&安装 点击下载并导入HBuilderX 导入到你使用的目录,如test目录 同样将uni-icons点击下载并导入HBuilderX 点击合并 此时te…

C++ 常量

常量是指在程序运行过程中,其值不能被改变的量。 如:i255;arearr3.14; 在程序中直接使用数值有两个问题: 可读性差; 可维护差; 一 符号常量 C语言符号常量的顶用形式如下: 二 C99的const常量 C 语言co…

MyBatis-Plus核心功能详解:条件构造器、自定义SQL与Service接口

在Java的Web开发中,MyBatis-Plus作为MyBatis的增强工具,提供了许多实用的功能,极大地简化了数据库操作的开发过程。下面,我们将详细探讨MyBatis-Plus的三大核心功能:条件构造器、自定义SQL以及Service接口。 一、条件…

凸优化理论学习二|凸函数及其相关概念

系列文章目录 凸优化理论学习一|最优化及凸集的基本概念 文章目录 系列文章目录一、凸函数(一)凸集(二)凸函数的定义及举例(三)凸函数的证明1、将凸函数限制在一条直线上2、判断函数是否为凸函数的一阶条件…

网络安全ctf比赛_学习资源整理,解题工具、比赛时间、解题思路、实战靶场、学习路线,推荐收藏!...

对于想学习或者参加CTF比赛的朋友来说,CTF工具、练习靶场必不可少,今天给大家分享自己收藏的CTF资源,希望能对各位有所帮助。 CTF在线工具 首先给大家推荐我自己常用的3个CTF在线工具网站,内容齐全,收藏备用。 1、C…

Modbus协议

Modbus协议 1.起源 Modbus由Modicon公司于1979年开发,是一种工业现场总线协议标准。 Modbus通信协议具有多个变种,其中有支持串口,以太网多个版本,其中最著名的是Modbus RTU、Modbus ASCII和Modbus TCP三种 其中Modbus TCP是在施…

Oracle 流stream将删除的数据保存

Oracle 流stream将删除的数据保存 --实验的目的是捕获hr.employees表的删除行,将删除行插入到emp_del表中。 --设置初始化参数 AQ_TM_PROCESSES1 COMPATIBLE9.2.0 LOG_PARALLELISM1 --查看数据库的名称,我的为ora9,将以下的ora9全部替换为你的数据库名称…

【教程向】从零开始创建浏览器插件(三)解决 Chrome 扩展中弹出页面、背景脚本、内容脚本之间通信的问题

第三步:解决 Chrome 扩展中弹出页面、背景脚本、内容脚本之间通信的问题 Chrome 扩展开发中,弹出页面(Popup)、背景脚本(Background Script)、内容脚本(Content Script)各自拥有独立…

微信小程序知识点归纳(一)

前言:适用于有一定基础的前端开发同学,完成从网页开发到小程序开发的知识转换。 先立框架,后砌墙壁 回顾:了解微信小程序开发流程-CSDN博客 初始页面结构,三部分pages、utils、配置,分别存放页面、工具类…

OpenAI Whisper 语音转文本实验

为了实现语音方式与大语言模型的对话,需要使用语音识别(Voice2Text)和语音输出(Text2Voice)。感觉这项技术已比较成熟了,国内也有许多的机构开发这项技术,但是像寻找一个方便测试的技术居然还不…

使用Vue调用ColaAI Plus大模型,实现聊天(简陋版)

首先去百度文心注册申请自己的api 官网地址&#xff1a;LuckyCola 注册点开个人中心 查看这个文档自己申请一个ColaAI Plus定制增强大模型API | LuckyColahttps://luckycola.com.cn/public/docs/shares/api/colaAi.html来到vue的页面 写个样式 <template><Header …

C++ | Leetcode C++题解之第79题单词搜索

题目&#xff1a; 题解&#xff1a; class Solution { public:bool exist(vector<vector<char>>& board, string word) {rows board.size();cols board[0].size();for(int i 0; i < rows; i) {for(int j 0; j < cols; j) {if (dfs(board, word, i, …

dnf手游攻略,新手入坑必备!

一、角色创建策略 在DNF手游中&#xff0c;角色创建是玩家初入游戏的首要步骤。为最大化游戏体验和收益&#xff0c;新手玩家通常建议创建三个角色&#xff1a;一个主账号和两个副账号。 主账号选择 主账号的选择应基于玩家个人的喜好和对职业的熟悉程度。无论选择哪个职业&a…

Gone框架介绍17 - 创建一个可运行在生产环境的Web项目

gone是可以高效开发Web服务的Golang依赖注入框架 github地址&#xff1a;https://github.com/gone-io/gone 文档原地址&#xff1a;https://goner.fun/zh/guide/auto-gen-priest.html 请帮忙在github上点个 ⭐️吧&#xff0c;这对我很重要 &#xff1b;万分感谢&#xff01;&a…

视频汇聚管理/安防监控系统EasyCVR如何开启和调用验证码登录接口?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。视频汇聚融合管理平台EasyCVR既具备传统安防视…

C语言写扫雷游戏(数组和函数实践)

目录 最后是代码啦&#xff01; 手把手教你用C语言写一个扫雷游戏&#xff01; 1.我们搭建一下这个多文件形式的扫雷游戏文件结构 2.在主函数里面设置一个包含游戏框架的菜单 菜单可以方便游戏玩家选择要进行的动作和不断地进行下一局。 3.switch语句连接不同的结果 菜单可…

AI与边缘设备,光子芯片,AI规划能力,自然语言驱动的AI游戏

1 Archetype AI 发布了一个创新的人工智能平台 —— Newton 这是一个专门为理解物理世界设计的基础模型。 Newton 设计用于连接实时物理数据&#xff0c;其数据源是全球数十亿传感器的输入&#xff0c;实现了对物理现实的直接解读。 利用从各种传感器&#xff08;如加速度计…

被动防护不如主动出击

自网络的诞生以来&#xff0c;攻击威胁事件不断涌现&#xff0c;网络攻防对抗已然成为信息时代背景下的一场无硝烟的战争。然而&#xff0c;传统的网络防御技术&#xff0c;如防火墙和入侵检测技术&#xff0c;往往局限于一种被动的敌暗我明的防御模式&#xff0c;面对攻击者无…