- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
OpenResty是一个基于Nginx与Lua的高性能web平台,其内部继承了大量精良的Lua库,第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发,扩展性极高的动态的web应用.
让你的web服务直接跑在Nginx服务内部,充分利用Nginx的非阻塞I/O模型,不仅仅对HTTP客户端请求,甚至于对远程后端诸如MySQL,PostgreSQL以及Redis等都进行一些列的高性能响应.
OpenResty的主要作用和功能包括:
安装OpenResty的依赖库 。
yum install -y pcre-devel openssl-devel gcc --skip-broken 。
安装OpenResty仓库 。
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo 。
如果提示说命令不存在,则运行 。
yum install -y yum-utils 。
然后重复上面的命令 。
安装OpenResty 。
yum install -y openresty 。
安装opm工具 。
yum install -y openresty-opm 。
目录结构 。
默认情况下,OpenResty安装的目录是: /usr/local/openresty OpenResty就是在Nginx基础上继承了一些lua模块.
配置Nginx环境变量 。
打开配置文件 。
vi /etc/profile 。
在最下面加入两行 。
export NGINX_HOME=/usr/local/openresty/nginx 。
export PATH=${NGINX_HOME}/sbin:$PATH 。
NGINX_HOME:后面是OpenResty安装目录下的Nginx的目录 。
然后让配置生效 。
source /etc/profile 。
OpenResty启动 。
# 启动nginx 。
nginx 。
# 重新加载配置 。
nginx -s reload 。
# 停止 。
nginx -s stop 。
nginx的默认配置文件注释太多,影响后续我们的编辑,这里将nginx.conf中的注释部分删除,保留有效部分.
修改/usr/local/openresty/nginx/conf/nginx.conf文件,内容如下:
#user nobody;
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 8081;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
在Linux的控制台输入命令以启动nginx:
nginx
下载: http://openresty.org/cn/download.html 。
解压 。
双击nginx.exe 或者执行 start nginx启动nginx 。
验证是否成功 tasklist /fi "imagename eq nginx.exe" 其中一个是 master 进程,另一个是 worker 进程 。
另外当 nginx 成功启动后,master 进程的 pid 存放在 logs\nginx.pid 文件中.
为了工作目录与安装目录互不干扰,并顺便学下简单的配置文件编写,就另外创建一个OpenResty的工作目录来练习,并且另外写一个配置文件.
创建OpenResty-test目录,并在该目录下创建logs和conf子目录分别用于存放日志和配置文件 。
$ mkdir ~/openresty-test ~/openresty-test/logs/ ~/openresty-test/conf/
$
$ tree ~/openresty-test
/Users/yuansheng/openresty-test
├── conf
└── logs
2 directories, 0 files
创建配置文件 。
在 conf 目录下创建一个文本文件作为配置文件,命名为 nginx.conf,文件内容如下
worker_processes 1; #nginx worker 数量
error_log logs/error.log; #指定错误日志文件路径
events {
worker_connections 1024;
}
http {
server {
#监听端口,若你的6699端口已经被占用,则需要修改
listen 6699;
location / {
default_type text/html;
content_by_lua_block {
ngx.say("HelloWorld")
}
}
}
}
提示:如果你安装的是 openresty 1.9.3.1 及以下版本,请使用 content_by_lua 命令代替示例中的 content_by_lua_block。可使用 nginx -V 命令查看版本号.
--- 启动nginx
➜ ~ nginx -p ~/openresty-test
--- 查看nginx进程
➜ ~ ps -ef | grep nginx
501 88620 1 0 10:58AM ?? 0:00.00 nginx: master process nginx -p
/Users/yuansheng/openresty-test
501 88622 88620 0 10:58AM ?? 0:00.00 nginx: worker process
--- 访问nginx
➜ ~ curl http://localhost:6699 -i
HTTP/1.1 200 OK
Server: openresty/1.9.7.3
Date: Sun, 20 Mar 2016 03:01:35 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
HelloWorld
利用不同的Location的功能组合,可以完成内部调用,流水线方式跳转,外部重定向等几大不同方式, 。
例如对数据库,内部公共函数的统一接口,可以把他们放到统一的Location中,通常情况下,为了保护这些内部接口,都会把这些接口设置为internal。这么做的好处就是可以让这个内部接口相互独立,不受外界干扰.
示例代码 。
location = /sum {
# 只允许内部调用
internal;
# 这里做了一个求和运算只是一个例子,可以在这里完成一些数据库、
# 缓存服务器的操作,达到基础模块和业务逻辑分离目的
content_by_lua_block {
local args = ngx.req.get_uri_args()
ngx.say(tonumber(args.a) + tonumber(args.b))
}
}
location = /app/test {
content_by_lua_block {
local res = ngx.location.capture(
"/sum", {args={a=3, b=8}}
)
ngx.say("status:", res.status, " response:", res.body)
}
}
稍微扩充一下, 并行请求效果,示例如下:
location = /sum {
internal;
content_by_lua_block {
ngx.sleep(0.1)
local args = ngx.req.get_uri_args()
ngx.print(tonumber(args.a) + tonumber(args.b))
}
}
location = /subduction {
internal;
content_by_lua_block {
ngx.sleep(0.1)
local args = ngx.req.get_uri_args()
ngx.print(tonumber(args.a) - tonumber(args.b))
}
}
location = /app/test_parallels {
content_by_lua_block {
local start_time = ngx.now()
local res1, res2 = ngx.location.capture_multi( {
{"/sum", {args={a=3, b=8}}},
{"/subduction", {args={a=3, b=8}}}
})
ngx.say("status:", res1.status, " response:", res1.body)
ngx.say("status:", res2.status, " response:", res2.body)
ngx.say("time used:", ngx.now() - start_time)
}
}
-- ngx.location.capture_multi 方法允许在同一个请求中并发地发起多个子请求
location = /app/test_queue {
content_by_lua_block {
local start_time = ngx.now()
local res1 = ngx.location.capture_multi( {
{"/sum", {args={a=3, b=8}}}
})
local res2 = ngx.location.capture_multi( {
{"/subduction", {args={a=3, b=8}}}
})
ngx.say("status:", res1.status, " response:", res1.body)
ngx.say("status:", res2.status, " response:", res2.body)
ngx.say("time used:", ngx.now() - start_time)
}
}
➜ ~ curl 127.0.0.1/app/test_parallels
status:200 response:11
status:200 response:-5
time used:0.10099983215332
➜ ~ curl 127.0.0.1/app/test_queue
status:200 response:11
status:200 response:-5
time used:0.20199990272522
利用 nginx.location.capture_multi 函数,直接完成了两个子请求并执行。当两个请求没有相互依赖,这种方法可以极大提高查询效率.
该方法,可以被广泛应用于广告系统(1:N模型,一个请求,后端从N家供应商中获取条件最优的广告)、高并发前段页面展示(并行无依赖界面,降级开关等).
各种不同的API,下载请求混杂在一起,要求厂商对下载的动态调整有各种不同的定制策略,而这些策略在一天的不同时间段,规则可能还不一样。这个时候还可以效仿工厂的流水线模式,逐层过滤,处理.
示例代码 。
location ~ ^/static/([-_a-zA-Z0-9/]+).jpg {
set $image_name $1;
content_by_lua_block {
ngx.exec("/download_internal/images/"
.. ngx.var.image_name .. ".jpg");
};
}
location /download_internal {
internal;
# 这里还可以有其他统一的 download 下载设置,例如限速等
alias ../download;
}
注意,ngx.exec 方法与 ngx.redirect 是完全不同的,前者是个纯粹的内部跳转并且没有引入任何额外 HTTP 信号。 这里的两个 location 更像是流水线上工人之间的协作关系。第一环节的工人对完成自己处理部分后,直接交给第二环节处理人(实际上可以有更多环节),它们之间的数据流是定向的.
百度的首页已经不再是 HTTP 协议,它已经全面修改到了 HTTPS 协议上。但是对于大家的输入习惯,估计还是在地址栏里面输入 baidu.com ,回车后发现它会自动跳转到 https://www.baidu.com ,这时候就需要的外部重定向了.
location = /foo {
content_by_lua_block {
ngx.say([[I am foo]])
}
}
location = / {
rewrite_by_lua_block {
return ngx.redirect('/foo');
}
}
测试结果如下 。
-- -i 表示输出响应头信息
➜ ~ curl 127.0.0.1 -i
HTTP/1.1 302 Moved Temporarily
Server: openresty/1.9.3.2rc3
Date: Sun, 22 Nov 2015 11:04:03 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: /foo
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>openresty/1.9.3.2rc3</center>
</body>
</html>
➜ ~ curl 127.0.0.1/foo -i
HTTP/1.1 200 OK
Server: openresty/1.9.3.2rc3
Date: Sun, 22 Nov 2015 10:43:51 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
I am foo
外部重定向是可以跨域名的。例如从 A 网站跳转到 B 网站是绝对允许的。在 CDN 场景的大量下载应用中,一般分为调度、存储两个重要环节。调度就是通过根据请求方 IP 、下载文件等信息寻找最近、最快节点,应答跳转给请求方完成下载.
获取一个uri有两个方法:ngx.req.get_uri_args、ngx.req.get_post_args,二者主要的区别是参数来源有区别。前者来自uri参数,后者来自post请求内容.
示例 。
server {
listen 80;
server_name localhost;
location /print_param {
content_by_lua_block {
local arg = ngx.req.get_uri_args()
for k,v in pairs(arg) do
ngx.say("[GET ] key:", k, " v:", v)
end
ngx.req.read_body() -- 解析 body 参数之前一定要先读取 body
local arg = ngx.req.get_post_args()
for k,v in pairs(arg) do
ngx.say("[POST] key:", k, " v:", v)
end
}
}
}
输出结果:
➜ ~ curl '127.0.0.1/print_param?a=1&b=2%26' -d 'c=3&d=4%26'
[GET ] key:b v:2&
[GET ] key:a v:1
[POST] key:d v:4&
[POST] key:c v:3
ngx.location.capture 函数用于发起一个内部子请求,并且等待子请求的响应 。
location /test {
content_by_lua_block {
local res = ngx.location.capture(
'/print_param',
{
method = ngx.HTTP_POST,
args = ngx.encode_args({a = 1, b = '2&'}),
body = ngx.encode_args({c = 3, d = '4&'})
}
)
ngx.say(res.body)
}
}
输出响应结果 。
➜ ~ curl '127.0.0.1/test'
[GET] key:b v:2&
[GET] key:a v:1
[POST] key:d v:4&
[POST] key:c v:3
如果这里不调用ngx.encode_args ,可能就会比较丑了,看下面例子:
local res = ngx.location.capture('/print_param',
{
method = ngx.HTTP_POST,
args = 'a=1&b=2%26', -- 注意这里的 %26 ,代表的是 & 字符
body = 'c=3&d=4%26'
}
)
ngx.say(res.body)
PS:对于 ngx.location.capture 这里有个小技巧,args 参数可以接受字符串或Lua 表的,这样我们的代码就更加简洁直观.
local res = ngx.location.capture('/print_param',
{
method = ngx.HTTP_POST,
args = {a = 1, b = '2&'},
body = 'c=3&d=4%26'
}
)
ngx.say(res.body)
在nginx的典型应用场景中,几乎都是只读取HTTP请求头即可,例如负载均衡,正反向代理等场景。但是对于API server 或者 web Application,对body可以说比较敏感了.
我们先来构造最简单的一个请求,POST 一个名字给服务端,服务端应答一个 “Hello ********”.
http {
server {
listen 80;
location /test {
content_by_lua_block {
local data = ngx.req.get_body_data()
ngx.say("hello ", data)
}
}
}
}
测试结果
➜ ~ curl 127.0.0.1/test -d jack
hello nil
从结果中可以看出data部分获取为nil,原因是还需要添加指令 lua_need_request_body 。
http {
server {
listen 80;
# 默认读取 body 设置全局行为
lua_need_request_body on;
location /test {
content_by_lua_block {
local data = ngx.req.get_body_data()
ngx.say("hello ", data)
}
}
}
}
再次测试,符合我们预期:
➜ ~ curl 127.0.0.1/test -d jack
hello jack
如果读取body并非全局行为,也可以显示的调用ngx.req.read_body() 接口,参看下面示例:
http {
server {
listen 80;
location /test {
content_by_lua_block {
ngx.req.read_body()
local data = ngx.req.get_body_data()
ngx.say("hello ", data)
}
}
}
}
HTTP响应报文分为三个部分:
对于HTTP响应体的输出,在OpenResty中调用 ngx.say 或 ngx.print即可.
区别:
ngx.say
会对输出响应体多输出一个 \nngx.say 与 ngx.print 均为异步输出,也就是说当调用 ngx.say 后并不会立刻输出响应体.
server {
listen 80;
location /test {
content_by_lua_block {
ngx.say("hello")
ngx.sleep(3)
ngx.say("the world")
}
}
location /test2 {
content_by_lua_block {
ngx.say("hello")
ngx.flush() -- 显式的向客户端刷新响应输出
ngx.sleep(3)
ngx.say("the world")
}
}
}
测试接口可以观察到, /test 响应内容实在触发请求 3s 后一起接收到响应体,而 /test2 则是先收到一个 hello 停顿 3s 后又接收到后面的 the world.
再看下面的例子:
server {
listen 80;
lua_code_cache off;
location /test {
content_by_lua_block {
ngx.say(string.rep("hello", 1000))
ngx.sleep(3)
ngx.say("the world")
}
}
}
执行测试,可以发现首先收到了所有的 "hello" ,停顿大约 3 秒后,接着又收到了 "the world" .
通过两个例子对比,可以知道,因为是异步输出,两个响应体的输出时机是 不一样 的.
当响应体过大(例如超过2G),是不能直接调用API完成响应体输出的。响应体过大,分两种情况:
第①个情况,要利用 HTTP 1.1 特性 CHUNKED 编码来完成 。
可以利用CHUNKED格式,把一个大的响应体拆分成多个小的响应体,分批,有节制的响应给请求方 。
location /test {
content_by_lua_block {
-- ngx.var.limit_rate = 1024*1024
local file, err = io.open(ngx.config.prefix() .. "data.db","r")
if not file then
ngx.log(ngx.ERR, "open file error:", err)
ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
end
local data
while true do
data = file:read(1024)
if nil == data then
break
end
ngx.print(data)
ngx.flush(true)
end
file:close()
}
}
OpenResty的标准日志输入原句为 ngx.log(log_level, ...),几乎可以在任何ngx_lua阶段进行日志的输出 。
worker_processes 1;
error_log logs/error.log error; # 日志级别
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
server {
listen 80;
location / {
content_by_lua_block {
local num = 55
local str = "string"
local obj
ngx.log(ngx.ERR, "num:", num)
ngx.log(ngx.INFO, " string:", str)
print([[i am print]])
ngx.log(ngx.ERR, " object:", obj)
}
}
}
}
访问网页,生成日志(logs/error.log文件)结果如下:
2016/01/22 16:43:34 [error] 61610#0: *10 [lua] content_by_lua(nginx.conf:26):5:
num:55, client: 127.0.0.1, server: , request: "GET /hello HTTP/1.1",
host: "127.0.0.1"
2016/01/22 16:43:34 [error] 61610#0: *10 [lua] content_by_lua(nginx.conf:26):7:
object:nil, client: 127.0.0.1, server: , request: "GET /hello HTTP/1.1",
host: "127.0.0.1"
Nginx的日志级别:
ngx.STDERR -- 标准输出
ngx.EMERG -- 紧急报错
ngx.ALERT -- 报警
ngx.CRIT -- 严重,系统故障,触发运维告警系统
ngx.ERR -- 错误,业务不可恢复性错误
ngx.WARN -- 告警,业务中可忽略错误
ngx.NOTICE -- 提醒,业务比较重要信息
ngx.INFO -- 信息,业务琐碎日志信息,包含不同情况判断等
ngx.DEBUG -- 调试
如果你的日志需要归集,并且对时效性要求比较高那么这里要推荐的库可能就让你很喜欢了。 lua-resty-logger-socket ,可以说很好的解决了上面提及的几个特性.
lua-resty-logger-socket 的目标是替代 Nginx 标准的 ngx_http_log_module 以非阻塞 IO 方式推送 access log 到远程服务器上。对远程服务器的要求是支持 syslog-ng 的日志服务.
lua_package_path "/path/to/lua-resty-logger-socket/lib/?.lua;;";
server {
location / {
log_by_lua_block {
local logger = require "resty.logger.socket"
if not logger.initted() then
local ok, err = logger.init{
host = 'xxx',
port = 1234,
flush_limit = 1234,
drop_limit = 5678,
}
if not ok then
ngx.log(ngx.ERR, "failed to initialize the logger: ",
err)
return
end
end
-- construct the custom access log message in
-- the Lua variable "msg"
local bytes, err = logger.log(msg)
if err then
ngx.log(ngx.ERR, "failed to log message: ", err)
return
end
}
}
}
例举几个好处:
最后此篇关于OpenResty的文章就讲到这里了,如果你想了解更多关于OpenResty的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
OpenResty 简介与安装 1. 简介 OpenResty是一个基于Nginx与Lua的高性能web平台,其内部继承了大量精良的Lua库,第三方模块以及大多数的依赖项。用于方便地搭建能够处理
我正在尝试设置多个 cookie,但它不起作用: if type(ngx.header["Set-Cookie"]) ~= "table" then ngx.header["Set-Cooki
我的问题 我正在使用openresty构建一个简单的服务器。 调用此服务器后,它应再次调用其他服务器,获取JSON结果,对其进行处理并返回解析后的结果。 如果出现此问题,则出于超出范围的原因,应在op
我很难理解 openresty(或 nginx)的并发模型。我读了Lua variable scope ,它解释了变量的生命周期,但它没有说明对它们的并发访问。 语言很难解释,所以我试着用代码来解释。
项目中有个特殊的需求,根据请求URL的参数,做不同的反向代理,比如:赛事ID<1000很少有人查询的赛事,映射到配置不好的机器上。将现在的赛事ID映射到配置好的机器上。 经过调研,决定使用openre
我正在尝试将 openresty 与 torch 一起用于神经网络的 Rest api。第一个查询有效,之后的任何查询都失败了。 Nginx 配置 workers processes 1; error
我正在official openresty docker镜像中运行alpine-fat nginx,openresty进程从nobody用户开始。 我需要使用下一个字符串设置nginx变量: set_
我有与docker一起部署的openresty应用程序。 我的docker文件: FROM openresty/openresty:alpine-fat ARG APPLICATION_PATH="/
所以我有一个用于我的软件的身份验证系统,我在其中向我的服务器发送 GET 请求以验证它,然后回显真或假。每当我使用 Winsock 发送 HTTP 请求时,我都会收到一个错误:400 错误请求,下面是
当我在 Lua 中使用 ngx.say() 来输出一些东西时,它开始在浏览器中下载。试试这个网址 - http://162.241.200.114 我不知道我该怎么做才能解决这个问题 😥 还有如何使
我安装了 openresty-1.13.6.1 但它缺少“resty.http”模块。我的 openresty 安装在/usr/local/openresty 中,我需要将 resty.http 模块
我安装了 openresty-1.13.6.1 但它缺少“resty.http”模块。我的 openresty 安装在/usr/local/openresty 中,我需要将 resty.http 模块
我的理解是LuaJIT使用Lua 5.1语法。在 Lua 5.1 中,“arg”功能已从语言中删除。 但是,以下代码可以工作。 // test.lua local function foo() f
我的理解是LuaJIT使用Lua 5.1语法。在 Lua 5.1 中,“arg”功能已从语言中删除。 但是,以下代码可以工作。 // test.lua local function foo() f
假设您有一个返回 postgresQL 数据库中定义的 json 的函数。 CREATE OR REPLACE FUNCTION test() RETURNS JSON AS $$ SELECT
我正在使用带有 lua-resty 的 OpenResty;显然,对于每个请求,程序都有自己的变量。为了跨请求共享简单的字符串或配置,我目前使用 lua-shared-dict。 但是,如果我需要跨请
目前我有一个包含以下组件的工作解决方案: 带有自定义应用程序的网络服务器 Openresty 与 lua key 斗篷 这允许我使用 keycloak 进行身份验证。 因为我的网络服务器还公开了一个
如果请求 URL 是 test.com/gifts。 如果我使用 ngx.var.urioutput 是/gifts/ 预期输出是 test.com/gifts 代码 : 地点/礼物{ try_fil
我一直在使用 openresty/nginx+lua 将服务器端点击发送到 Google Analytics Measurement Protocol。但是,我使用的函数 (ngx.location.
我正在寻找修改请求 header 并在 Lua 中重定向它,我试过了 ngx.redirect("/") 和 ngx.exec("/") 但我收到以下错误: attempt to call ngx
我是一名优秀的程序员,十分优秀!