当前位置: 首页 > article >正文

OpenResty 深度解析:构建高性能 Web 服务的终极方案

引言

openresty是什么?在我个人对它的理解来看相当于嵌入了lua的nginx;

我们在nginx中嵌入lua是为了不需要再重新编译,我们只需要重新修改lua脚本,随后重启即可;

一.lua指令序列
 

 我们分别从初始化阶段,重写/访问阶段,内容阶段,日志阶段来介绍上述图中的信息

1.初始化阶段

 init_by_lua*:Nginx 启动时,在 master 进程中仅执行一次,用于全局初始化,比如加载配置文件、初始化共享字典等。

init_worker_by_lua* :Nginx 启动时,每个 worker 进程初始化时执行,可用于 worker 进程级别的初始化,像设置特定于 worker 的变量等 。

2.重写/访问阶段

ssl_certificate_by_lua* :当请求是安全请求(涉及 SSL/TLS)时执行,可用于动态选择 SSL 证书等操作。

set_by_lua* :用于设置 Nginx 变量,可在请求处理早期计算变量值。

rewrite_by_lua* :用于 URL 重写相关操作,可修改请求的 URI 等。

access_by_lua* :用于访问控制,比如认证、鉴权、IP 黑白名单判断等,决定请求是否能继续处理。

3.内容阶段

balancer_by_lua* :在负载均衡阶段执行,可自定义负载均衡算法,选择合适的上游服务器。

content_by_lua* :用于生成响应内容,是核心的内容生成阶段,可查询数据库、组装数据并输出响应。

header_filter_by_lua* :用于过滤和修改响应头,比如添加自定义响应头、修改缓存相关头信息等。

body_filter_by_lua* :用于过滤和修改响应体,可对响应内容进行二次处理,如压缩、加密等。

4.日志阶段 

log_by_lua* :请求处理完成后,在记录日志时执行,可自定义日志记录逻辑,比如将日志发送到特定存储或进行格式化处理。

5.conf代码案例

我们可以直接在conf文件里面写lua代码块从而实现一些功能

worker_processes 8;events {worker_connections 10240;
}http {error_log ./logs/error.log info;server {listen 8989;location / {rewrite_by_lua_block {local args = ngx.req.get_uri_args()if args["jump"] == "1" thenreturn ngx.redirect("http://baidu.com")elseif args["jump"] == "2" thenreturn ngx.redirect("/jump_other")end}content_by_lua_block {ngx.say("hello","\t",ngx.var.remote_addr)}}location /jump_other {content_by_lua_block{ngx.say("jump other","\t",ngx.var.remote_addr)}body_filter_by_lua_block{local chunk =  ngx.arg[1]ngx.arg[1]=string.gsub(chunk,"other","lion")}log_by_lua_block{local request_method = ngx.var.request_methodlocal request_uri = ngx.var.request_urilocal status = ngx.var.statuslocal response_time = ngx.var.request_timelocal msg  = string.fomat("[%s] %s -Status:%d,response time = %.2fms",os.data("%Y-%m-%d %H:%M:%S"),request_uri,status,response_time)ngx.log(ngx.INFO,msg)}}}
}

上述conf代码块起了8个工作线程 每个工作线程的最大连接数为10240

我们sever的监听端口为8989,当我们页面路由到location /时候会调用lua嵌入的rewrite_by_lua_block(重写url)接口;

当jump=1时会直接重定向到百度

当jump=2时会重定向到location /jumpother

当我们跳转到location /jump_other时 我们会调用content_by_lua_block(生成内容输出http响应)接口 后面执行到body_filter_by_lua_block(对响应内容进行二次处理)接口

后面执行到日志输出接口 log_by_lua_block(打印对应的日志信息)

执行结果展示

默认输出 不输入jump

输入jump=1 重定向到百度

 

 输入jump=2 重定向到jump_other

 

二.openresty 中 嵌入原理和 责任链模式
1.OpenResty 嵌入原理

OpenResty 本质是将 LuaJIT 虚拟机嵌入到 Nginx 的管理进程(master 进程)和工作进程(worker 进程)中 。具体表现为:

进程内虚拟机共享:每个 worker 进程使用一个 LuaVM ,同一个进程内的所有协程共享该虚拟机。当请求分配到 worker 进程时,会在 LuaVM 中创建一个 coroutine 协程来处理请求。比如,在处理 HTTP 请求时,不同请求的协程都在所属 worker 进程的 LuaVM 里运行 Lua 代码。

与 Nginx 事件模型结合:ngx_lua 模块使 Lua 内建协程能和 Nginx 的事件驱动模型深度协作。Lua 代码中的 IO 操作委托给 Nginx 事件模型,实现非阻塞调用。像网络请求等 IO 操作时,Lua 协程挂起,Nginx 事件处理机制接管,操作完成后恢复协程上下文继续执行,对开发者透明。

模块与 API 注入:Nginx 的 I/O 原语等功能经封装后注入 Lua 虚拟机,让 Lua 代码能直接访问。例如,通过ngx.reqngx.resp等 API 可在 Lua 代码里方便操作 Nginx 的请求和响应相关功能 。

2.OpenResty 责任链模式

在 OpenResty 中,责任链模式是一种用于请求处理的设计模式 :

特点:解耦合和中断

节点构建:把请求处理逻辑拆分成一个个独立节点,每个节点完成单一功能,如鉴权、限流、日志记录等。例如在 API 网关场景,鉴权节点验证用户身份合法性,限流节点控制请求频率。

链式调用:节点按特定顺序组成责任链,请求到达后依次流经各节点。前一节点处理完决定是否将请求传递给下一节点。比如鉴权通过才将请求传给限流节点,否则直接返回错误响应。

动态调整:可根据业务需求灵活添加、删除或调整节点顺序。像某些高安全要求业务,在责任链中增加更严格加密和多重认证节点;普通业务则简化节点链。

三.cosocket

cosocket指的是协程和socket的结合实现特定的功能

 四.openresty总结
1.我们使用openresty的三板斧

①背靠nginx,嵌入到各个阶段的lua函数

②cosocket可同步非阻塞在多个阶段访问第三方库服务,在nginx上实现业务成为可能

③ngx,shared.dict共享内存可在多个worker进程共享数据,数据实时生效

2.conf和lua代码案例

conf文件

worker_processes 8;events {worker_connections 10240;
}http {error_log ./logs/black.log info;lua_shared_dict blks 1m;init_worker_by_lua_file ./app/init_worker.lua;server {listen 8989;location / {access_by_lua_block {local black_list= {["192.168.217.2"]=true}if black_list[ngx.var.remote_addr] thenreturn ngx.exit(404)end}content_by_lua_block {ngx.say("hello","\t",ngx.var.remote_addr)}}location /black_v1 {access_by_lua_file ./app/black_v1.lua;content_by_lua_block {ngx.say("black_v1","\t",ngx.var.remote_addr)}}location /black_v2 {access_by_lua_file ./app/black_v2.lua;content_by_lua_block {ngx.say("black_v2","\t",ngx.var.remote_addr)}}}
}

我们在worker线程初始化的时候通过lua_shared_dict接口实现一块1m的共享内存 后我们调用init_worker_by_lua_file接口   进入到 init_worker.lua 文件中

我们通过conf代码块中的

        location /black_v2 {

            access_by_lua_file ./app/black_v2.lua;

            content_by_lua_block {

                ngx.say("black_v2","\t",ngx.var.remote_addr)

            }

        }

进行详解

init_worker.lua文件

--只在第一个worker进程里面初始化
if ngx.worker.id() ~= 0 thenreturn
endlocal redis = require("resty.redis")
local bklist = ngx.shared.blkslocal function updata_blacklist()local red = redis:new()local ok, err = red:connect("127.0.0.1", 6379)if not ok thenreturnendlocal black_list, err = red:smembers("black_list")bklist:flush_all()for _, value in pairs(black_list) dobklist:set(value, true)endngx.timer.at(5, updata_blacklist)
endngx.timer.at(5, updata_blacklist) --每5s把redis黑名单里面的内容更新到共享内存里

 我们在上述lua代码中实现了 对redis的连接以及实时把redis里面黑名单的内容更新到共享内存块中

black_v2.lua 文件

 

local bklist = ngx.shared.blkslocal ip = ngx.var.remote_addrif bklist:get(ip) thenreturn ngx.exit(404)
end

当我们路由到    location /black_v2时候 通过access_by_lua_file 接口 会执行black_v2.lua文件

从而拿到共享内存中的黑名单ip地址从而进行判断

实现黑白名单结果演示

启动openresty

启动redis

 我们在balck_list中添加两个ip地址

http请求访问

把本地ip地址从 black_list中删除

 五.kong在openresty进一层的封装
1.概念和接口

kong和konga-->web服务在开发中经常使用的 

我们只介绍其中的反向代理来演示其功能

kong在反向代理的两个接口分别是

proxy_pass;

proxy_protocol on;   

2.conf和lua代码案例 

conf文件

worker_processes 2;events {worker_connections 1024;
}# #http
##动态
http {error_log ./logs/proxy.log info;lua_shared_dict shm 1m;lua_shared_dict urls 1m;##########################################################
}#静态---->问题--->添加删除需要重启生效
http {error_log ./logs/proxy.log info;upstream ups {server 192.168.217.148:7001;server 192.168.217.148:7002;server 192.168.217.148:7003;}server {listen 9001;location / {proxy_pass http://ups;proxy_protocol on;}}
}#tcp
stream {upstream tcp_ups {server 192.168.217.148:8080;}server {listen 9002;proxy_pass tcp_ups;proxy_protocol on;}server {listen 9003;content_by_lua_file ./app/proxy.lua;}
}

proxy.lua

local sock, err = ngx.req.socket()
if not sock thenreturn
endlocal upsock = ngx.socket.tcp()local ok, err = upsock:connect("192.168.217.148", 8080)
if not ok thenreturn
endupsock:send(ngx.var.remote_addr .. "\n")
-- local function handler_upstream()-- end
六.kong总结

Kong 是一款基于 NGINX 和 OpenResty 构建的开源 API 网关,支持 API 管理、流量控制、身份验证、监控等功能,可实现对 API 的全生命周期管理与流量治理。

相关文章:

OpenResty 深度解析:构建高性能 Web 服务的终极方案

引言 openresty是什么?在我个人对它的理解来看相当于嵌入了lua的nginx; 我们在nginx中嵌入lua是为了不需要再重新编译,我们只需要重新修改lua脚本,随后重启即可; 一.lua指令序列 我们分别从初始化阶段,重写/访问阶段,内容阶段,日志…...

什么是路由器环回接口?

路由器环回接口(LoopbackInterface)是网络设备中的一种逻辑虚拟接口,不依赖物理硬件,但在网络配置和管理中具有重要作用。以下是其核心要点: 一、基本特性 1.虚拟性与稳定性 环回接口是纯软件实现的逻辑接口&#x…...

OpenHarmony:开源操作系统重塑产业数字化底座

OpenHarmony:开源操作系统重塑产业数字化底座 引言:当操作系统成为数字公共品 在万物智联时代,操作系统不再是科技巨头的专属领地。华为捐赠的OpenHarmony项目,正以开源协作模式重构操作系统产业格局。这个脱胎于商业版本的开源…...

【MySQL进阶】如何在ubuntu下安装MySQL数据库

前言 🌟🌟本期讲解关于如何在ubuntu环境下安装mysql的详细介绍~~~ 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 🔥 你的点赞就是小编不断更新的最大动力 &#x1f3…...

【数据结构】_二叉树

1.二叉树链式结构的实现 1.1 前置说明 在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,为了降低大家学习成本,此处手动快速创建一棵简单的二叉树&#x…...

给图表组件上点“颜色” —— 我与 CodeBuddy 的合作记录

我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 前段时间,我在开发一个 Vue3 项目的时候,碰到了一个小小的挑战:我想做一个可…...

使用 YOLO 结合 PiscTrace 实现股票走势图像识别

在智能投研和金融分析中,自动识别图表中的模式(如 K 线走势、支撑/阻力位、形态结构)成为一种新兴手段。传统的技术分析依赖大量人工判断,而计算机视觉技术的发展,特别是 YOLO 模型在图像识别领域的高效表现&#xff0…...

OpenCV中的光流估计方法详解

文章目录 一、引言二、核心算法原理1. 光流法基本概念2. 算法实现步骤 三、代码实现详解1. 初始化设置2. 特征点检测3. 光流计算与轨迹绘制 四、实际应用效果五、优化方向六、结语 一、引言 在计算机视觉领域,运动目标跟踪是一个重要的研究方向,广泛应用…...

OpenCL C++ 常见属性与函数

核心对象与属性 对象/属性描述示例cl::Platform表示OpenCL平台cl::Platform::get(&platforms)cl::Device表示计算设备cl::Device::getDefault()cl::Context管理设备、内存和命令队列的上下文cl::Context(contextDevices)cl::CommandQueue命令队列,用于提交命令cl::Command…...

Android核心系统服务:AMS、WMS、PMS 与 system_server 进程解析

1. 引言 在 Android 系统中,ActivityManagerService (AMS)、WindowManagerService (WMS) 和 PackageManagerService (PMS) 是三个最核心的系统服务,它们分别管理着应用的生命周期、窗口显示和应用包管理。 但你是否知道,这些服务并不是独立…...

18.自动化生成知识图谱的多维度质量评估方法论

文章目录 一、结构维度评估1.1 拓扑结构评估1.1.1 基础图论指标1.1.2 层级结构指标 1.2 逻辑一致性评估1.2.1 形式逻辑验证1.2.2 约束满足度 二、语义维度评估2.1 语义一致性评估2.1.1 标签语义分析2.1.2 关系语义评估 2.2 语义表示质量2.2.1 嵌入质量2.2.2 上下文语义评估 三、…...

【行为型之命令模式】游戏开发实战——Unity可撤销系统与高级输入管理的架构秘钥

文章目录 ⌨️ 命令模式(Command Pattern)深度解析一、模式本质与核心价值二、经典UML结构三、Unity实战代码(可撤销的建造系统)1. 定义命令接口与接收者2. 实现具体命令3. 命令管理器(Invoker)4. 客户端使…...

图论模板(部分)

图论模板&#xff08;部分&#xff09; maincpp #include <iostream> #include <climits> #include <limits>typedef unsigned long long ull; typedef long long ll; typedef long double ld; typedef std::pair<int, int> PII;#define rep(i, n) f…...

LeetCode 热题 100_寻找重复数(100_287_中等_C++)(技巧)(暴力解法;哈希集合;二分查找)

LeetCode 热题 100_寻找重复数&#xff08;100_287_中等_C&#xff09; 题目描述&#xff1a;输入输出样例&#xff1a;题解&#xff1a;解题思路&#xff1a;思路一&#xff08;暴力解法&#xff09;&#xff1a;思路二&#xff08;哈希集合&#xff09;&#xff1a;思路三&am…...

NBA足球赛事直播源码体育直播M33模板赛事源码

源码名称&#xff1a;体育直播赛事扁平自适应M33直播模板源码 开发环境&#xff1a;帝国cms7.5 空间支持&#xff1a;phpmysql 带软件采集&#xff0c;可以挂着自动采集发布&#xff0c;无需人工操作&#xff01; 演示地址&#xff1a;NBA足球赛事直播源码体育直播M33模板赛事…...

【QT 项目部署指南】使用 Inno Setup 打包 QT 程序为安装包(超详细图文教程)

一、为什么需要打包成安装包&#xff1f; 在完成 QT 项目开发后&#xff0c;直接发布可执行文件&#xff08;.exe&#xff09;和依赖的 DLL 文件虽然可行&#xff0c;但存在以下问题&#xff1a; 用户体验差&#xff1a;用户需手动管理文件路径&#xff0c;容易因文件缺失导致…...

电子电器架构 --- 整车造车阶段四个重要节点

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…...

黑马点评-用户登录

文章目录 用户登录发送短信验证码注册/登录校验登录 用户登录 发送短信验证码 public Result sendCode(String phone, HttpSession session) {// 1.校验手机号if (RegexUtils.isPhoneInvalid(phone)) {// 2.如果不符合&#xff0c;返回错误信息return Result.fail("手机…...

ecmascript 第6版特性 ECMA-262 ES6

https://blog.csdn.net/zlpzlpzyd/article/details/146125018 在之前写的文章基础上&#xff0c;ES6在export和import的基础外&#xff0c;还有如下特性 特性说明let/const块级作用域变量声明>箭头函数Promise异步编程...

十二、Hive 函数

作者&#xff1a;IvanCodes 日期&#xff1a;2025年5月1日 专栏&#xff1a;Hive教程 在数据处理的广阔天地中&#xff0c;我们常常需要对数据进行转换、计算、清洗或提取特定信息。Hive 提供了强大的内置运算符和丰富的内置函数库&#xff0c;它们就像魔法师手中的魔法棒&…...

No More Adam: 新型优化器SGD_SaI

一.核心思想和创新点 2024年12月提出的SGD-SaI算法&#xff08;Stochastic Gradient Descent with Scaling at Initialization&#xff09;本质上是一种在训练初始阶段对不同参数块&#xff08;parameter block&#xff09;基于**梯度信噪比&#xff08;g-SNR, Gradient Signa…...

数据结构【AVL树】

AVL树 1.AVL树1.AVL的概念2.平衡因子 2.AVl树的实现2.1AVL树的结构2.2AVL树的插入2.3 旋转2.3.1 旋转的原则 1.AVL树 1.AVL的概念 AVL树可以是一个空树。 它的左右子树都是AVL树&#xff0c;且左右子树的高度差的绝对值不超过1。AVL树是一颗高度平衡搜索二叉树&#xff0c;通…...

C#将1GB大图裁剪为8张图片

C#处理超大图片&#xff08;1GB&#xff09;需要特别注意内存管理和性能优化。以下是几种高效裁剪方案&#xff1a; 方法1&#xff1a;使用System.Drawing分块处理&#xff08;内存优化版&#xff09; using System; using System.Drawing; using System.Drawing.Imaging; us…...

数据库——SQL约束窗口函数介绍

4.SQL约束介绍 &#xff08;1&#xff09;主键约束 A、基本内容 基本内容 p r i m a r y primary primary k e y key key约束唯一表示数据库中的每条记录主键必须包含唯一的值&#xff08;UNIQUE&#xff09;主键不能包含NULL值&#xff08;NOT NULL&#xff09;每个表都应…...

Linux系统启动相关:vmlinux、vmlinuz、zImage,和initrd 、 initramfs,以及SystemV 和 SystemD

目录 一、vmlinux、vmlinuz、zImage、bzImage、uImage 二、initrd 和 initramfs 1、initrd&#xff08;Initial RAM Disk&#xff09; 2、initramfs&#xff08;Initial RAM Filesystem&#xff09; 3、initrd vs. initramfs 对比 4. 如何查看和生成 initramfs 三、Syste…...

JSP链接MySQL8.0(Eclipse+Tomcat9.0+MySQL8.0)

所用环境 Eclipse Tomcat9.0 MySQL8.0.21(下载&#xff1a;MySQL Community Server 8.0.21 官方镜像源下载 | Renwole&#xff09; mysql-connector-java-8.0.21&#xff08;下载&#xff1a;MySQL :: Begin Your Download&#xff09; .NET Framework 4.5.2&#xff08;下…...

Python爬虫-爬取百度指数之人群兴趣分布数据,进行数据分析

前言 本文是该专栏的第56篇,后面会持续分享python爬虫干货知识,记得关注。 在本专栏之前的文章《Python爬虫-爬取百度指数之需求图谱近一年数据》中,笔者有详细介绍过爬取需求图谱的数据教程。 而本文,笔者将再以百度指数为例子,基于Python爬虫获取指定关键词的人群“兴…...

SEO长尾词与关键词优化实战

内容概要 在SEO优化体系中&#xff0c;长尾关键词与核心关键词的协同作用直接影响流量获取效率与用户转化路径。长尾词通常由3-5个词组构成&#xff0c;搜索量较低但意图明确&#xff0c;能精准触达细分需求用户&#xff1b;核心关键词则具备高搜索量与广泛覆盖能力&#xff0…...

机器学习-人与机器生数据的区分模型测试-数据处理1

附件为训练数据&#xff0c;总体的流程可以作为参考。 导入依赖 import pandas as pd import os import numpy as np from sklearn.model_selection import train_test_split,GridSearchCV from sklearn.ensemble import RandomForestClassifier,VotingClassifier from skle…...

HelloWorld

HelloWorld 新建一个java文件 文件后缀名为 .javahello.java【注意】系统可能没有显示文件后缀名&#xff0c;我们需要手动打开 编写代码 public class hello {public static void main(String[] args) {System.out.print(Hello,World)} }编译 javac java文件&#xff0c;会生…...