openresty学习笔记
openresty 简介
openresty 是一个基于 nginx 与 lua 的高性能 web 平台,其内部 集成了大量精良的 lua 库、第三方模块以及大数的依赖项。用于 方便搭建能够处理超高并发、扩展性极高的动态 web 应用、 web 服务和动态网关。
openresty 通过汇聚各种设计精良的 nginx 模块,从而将 nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人 员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单 机并发连接的高性能 Web 应用系统。
openresty 的目标是让你的 Web 服务直接跑在 Nginx 服务内部, 充分利用 Nginx 的非阻塞 I/O 模型(多reactor 模型),不仅仅 对 HTTP 客户端请求(stream),甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis etcd kafka grpc 等都进行一致的高性能响应(upstream)。
openresty 安装
官网: http://openresty.org/cn/
下载页面:http://openresty.org/cn/download.html
# 安装依赖
apt-get install libpcre3-dev \libssl-dev perl make build-essential curl
# 解压源码
tar -xzvf openresty-VERSION.tar.gz
# 配置:默认, --prefix=/usr/local/openresty 程序会被
安装到/usr/local/openresty目录。
./configure
make -j2
sudo make install
cd ~
export PATH=/usr/local/openresty/bin:$PATH
启动、关闭、重启 openresty
# 指定配置启动 openresty
openresty -p . -c conf/nginx.conf
# 优雅退出
openresty -p . -s quit
# 重启 openresty
openresty -p . -s reload
openresty 应用场景
奇虎360的所有服务端团队都在使用,京东、百度、魅族、知 乎、优酷、新浪这些互联网公司都在使用。有用来写 WAF (web application firewall)、有做 CDN 调度、有做广告系统、消息推送系统,API server 的。还有用在非常关键的业务上,比如高可用架构分享的京东商品详情页。
1 在请求真正到达上游服务之前,Lua 可以随心所欲的做复杂的访问控制和安全检测
2 随心所欲的操控响应头里面的信息
3 从外部存储服务(比如 Redis,Memcached,MySQL, Postgres)中获取后端信息,并用这些信息来实时选择哪一个后端来完成业务访问
4 在内容 handler 中随意编写复杂的 Web 应用,使用同步但依然非阻塞的方式,访问后端数据库和其他存储
5 在 rewrite 阶段,通过 Lua 完成非常复杂的 URL dispatch
6 用 Lua 可以为 nginx 子请求和任意 location,实现高级缓存机制
lua-nginx-module
nginx 采用模块化设计,使得每一个 http 模块可以仅专注于完 成一个独立的、简单的功能,而一个请求的完整处理过程可以 由无数个 http 模块共同合作完成。为了灵活有效地指定下一个 http 处理模块是哪一个;http 框架依据常见的的处理流程将处 理阶段划分为 11 个阶段,其中每一个阶段都可以由任意多个 http 模块流水式地处理请求。
openresty 将 lua 脚本嵌入到 nginx 阶段处理的末尾模块下;这样以来并不会影响 nginx 原有的功能,而是在 nginx 基础上丰富它的功能;
嵌入 lua 的优点是:使用 openresty 开发,不需要重新编译, 直接修改 lua 脚本,重新启动即可;

lua 模块指令顺序
问题:访问某个页面,先验证是否用户权限是否合法,否则跳到用户验证界面;
问题:黑白名单在哪个阶段实现?



init_by_lua
在 nginx 重新加载配置文件时,运行里面 lua 脚本,常用于 全局变量的申请。例如 lua_shared_dict 共享内存的申请,只 有当 nginx 重启后,共享内存数据才清空,这常用于统计。
set_by_lua
设置一个变量,常用与计算一个逻辑,然后返回结果,该阶 段不能运行Output API、Control API、Subrequest API、 Cosocket API
rewrite_by_lua
在 access 阶段前运行,主要用于 rewrite url;
access_by_lua
主要用于访问控制,这条指令运行于 nginx access 阶段的末 尾,因此总是在 allow 和 deny 这样的指令之后运行,它们 同属 access 阶段。可用来判断请求是否具备访问权限;
content_by_lua
阶段是所有请求处理阶段中最为重要的一个,运行在这个阶 段的配置指令一般都肩负着生成内容(content)并输出 HTTP 响应。
header_filter_by_lua
一般只用于设置 Cookie 和 Headers 等。
body_filter_by_lua
一般会在一次请求中被调用多次,因为这是实现基于 HTTP 1.1 chunked 编码的所谓“流式输出”的。
log_by_lua
该阶段总是运行在请求结束的时候,用于请求的后续操作, 如在共享内存中进行统计数据,如果要高精确的数据统计, 应该使用 body_filter_by_lua
嵌入原理

openresty 是在nginx处理的阶段末尾加上我们的方法,补充功能,原来实现的功能不受影响。
责任链模式

ngx.exit(status)
如果status == 0 只打断当前责任链,如果status>=200 则打断整个责任链,直接退出。
ngx.redirect()
cosocket
openresty 为 nginx 添加的最核心的功能就是 cosocket;自 cosocket 加入,可以在 http 请求处理中访问第三方服务; cosocket 主要依据 nginx 中的事件机制和 lua 的协程结合后实现了非阻塞网络 io;在业务逻辑使用层面上可以通过同步非阻塞的方式来写代码;
引入 cosocket 后,nginx 中相当于有了多条并行同步逻辑线 (lua 协程),nginx 中单线程负责唤醒或让出其中 lua 协程; 唤醒或让出依据来源于协程运行的条件是否得到满足;
问题:比较 openresty 、skynet、zvnet 的 lua 虚拟机抽象和 lua 协程抽象?

黑名单用户 nginx.conf
worker_processes 8;events {worker_connections 10240;
}http {lua_shared_dict bklist 1m;init_worker_by_lua_file ./app/init_worker.lua;server {listen 9000;location / {access_by_lua_block {local black_list = {["192.168.44.1"] = true}if black_list[ngx.var.remote_addr] then return ngx.exit(403)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("hello" , "\t" , ngx.var.remote_addr)}}location /black_v2 {access_by_lua_file ./app/black_v2.lua;content_by_lua_block {ngx.say("hello" , "\t" , ngx.var.remote_addr)}}}
}
black_v1.lua (将黑名单ip放入redis)
local redis = require "resty.redis"local red = redis:new()local ok , err = red:connect("127.0.0.1" , 6379)if not ok then return ngx.exit(301)
endlocal ip = ngx.var.remote_addrlocal exists , err = red:sismember("black_list" , ip)if exists == 1 thenreturn ngx.exit(403)
end
black_v2.lua
local bklist = ngx.shared.bklistlocal ip = ngx.var.remote_addrif bklist:get(ip) then return ngx.exit(403)
end
init_worker.lua 一个worker定时往共享内存中刷数据,(黑名单ip)
if ngx.worker.id() ~= 0 thenreturn
endlocal redis = require "resty.redis"
local bklist = ngx.shared.bklistlocal function update_blacklist()local red = redis:new()local ok , err = red:connect("127.0.0.1" , 6379)if not ok then returnendlocal black_list,err = red:smembers("black_list")bklist:flush_all() for _,v in pairs(black_list) dobklist:set(v , true)endngx.timer.at(5 , update_blacklist)
endngx.timer.at(5 , update_blacklist)
反向代理
worker_processes 8;events {worker_connections 10240;
}# http
http {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_here")end}content_by_lua_block {ngx.say("hello", "\t", ngx.var.remote_addr)}}location /jump_here {content_by_lua_block {ngx.say("jump_here hello", "\t", ngx.var.remote_addr)}body_filter_by_lua_block {local chunk = ngx.arg[1]ngx.arg[1] = chunk:gsub("hello", "mark")}}}
}stream {upstream ups {server 127.0.0.1:8888;}server {listen 9999;proxy_pass ups;proxy_protocol on;}server {listen 9000;content_by_lua_file ./app/proxy.lua;}
}
cosocket proxy.lua
local sock, err = ngx.req.socket()if err thenngx.log(ngx.INFO, err)
endlocal upsock, okupsock = ngx.socket.tcp()ok, err = upsock:connect("127.0.0.1", 8989)
if not ok thenngx.log(ngx.INFO, "connect error:"..err)
endupsock:send(ngx.var.remote_addr .. '\n')local function handle_upstream()local datafor i=1, 1000 dolocal reader = upsock:receiveuntil("\n", {inclusive = true})data, err, _ = reader()if err thensock:close()upsock:close()returnendsock:send(data)end
endngx.thread.spawn(handle_upstream)local datawhile true dolocal reader = sock:receiveuntil("\n", {inclusive = true})data, err, _ = reader()if err thensock:close()upsock:close()returnendupsock:send(data)
end相关文章:
openresty学习笔记
openresty 简介 openresty 是一个基于 nginx 与 lua 的高性能 web 平台,其内部 集成了大量精良的 lua 库、第三方模块以及大数的依赖项。用于 方便搭建能够处理超高并发、扩展性极高的动态 web 应用、 web 服务和动态网关。 openresty 通过汇聚各种设计精良的 ngi…...
微信小程序DAY3
文章目录一、页面导航1-1、声明式导航1-2、编程式导航1-3、声明式导航传参1-4、编程式导航传参1-5、获取导航传递的参数二、页面事件2-1、下拉刷新事件2-1-1、启用下拉刷新2-1-2、配置下拉刷新2-1-3、监听页面下拉刷新事件2-2、上拉触底事件2-2-1、事件触发2-2-1、事件配置三、…...
【CAN】手把手教你学习CAN总线(一)
CAN总线一、CAN总线概念二、CAN的差分信号三、CAN总线的通信协议1、 帧起始2、仲裁段3、控制段4、数据段5、CRC段6、ACK段7、帧结束四、CAN的位时序1、同步段(SS)2、传播时间段(PTS)3、相位缓冲段(PBS)4、再…...
JUC 体系的基石——AQS
—— AQS(AbstractQueuedSynchronizer) 概念 抽象队列同步器;volatile cas 机制实现的锁模板,保证了代码的同步性和可见性,而 AQS 封装了线程阻塞等待挂起,解锁唤醒其他线程的逻辑。AQS 子类只需要根据状…...
Qt中信号与槽的使用
Qt中信号与槽的使用 Qt当中一个重要的东西是信号和槽,它被用于对象之间的通信。 在Qt中,例如“点击按钮”这个事件就是发送信号的对象,接收信号的是某一个窗口,响应信号的是一个处理,可以是隐藏窗口或者是关闭窗口。…...
力扣-销售员
大家好,我是空空star,本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目:607. 销售员二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其他总结前言 …...
HTML综合案例练习
一、展示简历内容 可以首先看一下我们的效果,之后再思考怎么实现 总的来说,这个练习不算难。 这里关于这个简历的代码编写我们不说太多,只注意以下几个内容即可: 注意及时查看我们的代码是否符合预期,即一段一段测 …...
MySQL运维
目录 1、日志 1、错误日志 2、二进制日志 3、查询日志 4、慢查询日志 2、主从复制 搭建 1、主库配置 2、从库配置 3、分库分表 1、简介 编辑 1、垂直拆分 2、水平拆分 3、实现技术 2、MyCat 3、MyCat使用和配置 配置 4、MyCat分片 1、垂直拆分 2、水平拆分…...
【网络原理10】构造HTTP请求、HTTPS加密
目录 一、构造HTTP请求 ①使用form表单构造HTTP请求: form表单是如何提交的 form提交的缺点 ②基于ajax构造http请求 如何使用Jquery框架 二、HTTPS 运营商劫持 HTTP的加密版本:HTTPS ①对称加密:客户端和服务端使用同一把密钥&…...
Allegro如何锁定报表界面操作指导
Allegro如何锁定报表界面操作指导 用Allegro做PCB设计的时候,进行测量的时候,比如测量器件两个PIN中间的间距,如下图,会有一个报表显示 但是当运行下一个命令的时候,报表会被自动关闭掉。 但是有时我们需要报表界面仍被保留 下面介绍如何将报表界面进行锁定,不受下一个…...
基于STM32的微型电子琴设计
基于STM32的微型电子琴设计报告中的图片和文字太多了,全部一个一个把搬过来太麻烦了,需要完整文本和代码自行q我963160156 第一章 总体设计1.1 系统功能1.2 主要技术性能指标第二章硬件设计2.1 整体硬件图2.2 按键模块2.3 扬声器模块2.4 显示模块2.5 主控模块第三章…...
Shell输入输出重定向
一、文件描述符 文件描述符是一个非负整数。它是一个索引值,指向进程打开的文件。 Linux 程序在执行任何形式的 I/O 操作时,都是在读取或者写入一个文件描述符。 每个文件描述符会与一个打开的文件相对应 不同的文件描述符也可能指向同一个文件 在L…...
华为OD机试-运维日志排序
文章目录题目描述输入描述输出描述:示例Java 代码实现题目描述 运维工程师采集到某产品线网运行一天产生的日志n条,现需根据日志时间先后顺序对日志进行排序,日志时间格式为H:M:S.N。 H表示小时(0~23) M表示分钟(0~59) S表示秒(0~59) N表…...
1Kotlin基础知识
1 变量 1.1 用法 Kotlin中的变量定义有2个关键字,val和var val用来定义不可变变量,第一次赋值后就不能再被修改了, var定义可变变量, 随便修改。一个好的编程习惯是, 能用val的就不要用var, 原因是安全&a…...
Redis Lua脚本
文章目录一.引言二.eval简介三.lua数据类型和redis数据类型之间转换四.脚本的原子性五.错误处理六.纯函数脚本七.选择内部脚本一.引言 eval和evalsha命令使用内置的lua解释器,可以对lua脚本进行求值。 二.eval简介 第一个参数是一段脚本程序第二个参数是参数的个…...
web自动化测试-执行 JavaScript 脚本
JavaScript 是一种脚本语言,有的场景需要使用 js 脚本注入辅助我们完成 Selenium 无法做到的事情。 当 webdriver 遇到无法完成的操作时,可以使用 JavaScript 来完成,webdriver 提供了 execute_script() 方法来调用 js 代码。 执行 js 有两种…...
libevent笔记——简单介绍
背景 libevent libevent – an event notification library 官方定义:libevent是一个事件通知的库。更详细的介绍参考官方的就够了,这里我摘抄一下,并做一些注释 The libevent API provides a mechanism to execute a callback function whe…...
C++学习笔记-多态
多态的概念 多态的概念:通俗来说,就是多种形态, 具体点就是去完成某个行为,当不同的对象去完成时会 产生出不同的状态 。 举个例子:比如 买票这个行为 ,当 普通人 买票时,是全价买票;…...
5632: 三角形
描述平面坐标系下,给定不共线的三个点组成一个三角形,问三角形最短的边长和最长的边长各为多少?输入输入包含3行,每行两个整数,表示一个点的坐标x和y。输出输出包括2个小数,分别为最短的边长和最长的边长。…...
Java基础--IO操作
一、IO原理及分类 一、IO原理 1、I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输,如读写文件,网络通信等。 2、java程序中对于数据的输入/输出操作一般都是以流的方式进行 3、java.io包下提供各…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
