大略地说 OpenResty 的目标是让你的Web做事直接跑在 Nginx 做事内部,充分利用 Nginx 的非壅塞 I/O 模型,不仅仅对 HTTP 客户端要求,乃至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行同等的高性能相应。
从上面官网的描述信息中,可以看出OpenResty紧张包含两方面的技能:
官方网站:http://openresty.org/Github组织:https://github.com/openresty

nginx 与 lua 先容与安装可以参考我以下几篇文章:
NGINX - 高等负载均衡器、Web做事器、反向代理NGINX 路由配置与参数详解(https配置、跨域配置、socket配置)NGINX sub_filter 和 subs_filter 指令讲解lua 语法先容与 NGINX lua 高等用法实战操作二、OpenResty 安装yum install pcre-devel openssl-devel gcc curlwget https://openresty.org/package/centos/openresty.reposudo mv openresty.repo /etc/yum.repos.d/openresty.repo# update the yum index:sudo yum check-updateyum -y install openresty
验证安装
/usr/local/openresty/nginx/sbin/nginx -v
启动 OpenResty
/usr/local/openresty/nginx/sbin/nginx
测试
# 创建一个 NGINX 配置文件(例如 /usr/local/openresty/nginx/conf/nginx.conf)并添加一个包含 Lua 代码的 location 块:server { listen 80; server_name localhost; location /test { content_by_lua_block { ngx.say("Hello, LuaJIT!") } }}
保存配置文件,然后重新加载 NGINX:
# 先检讨语法sudo /usr/local/openresty/nginx/sbin/nginx -t# 重新加载配置sudo /usr/local/openresty/nginx/sbin/nginx -s reload
访问 http://localhost/test 该当返回 "Hello, LuaJIT!"。
三、OpenResty 的事情事理
OpenResty 是基于 Nginx 的高性能Web平台,以是其高效运行与 Nginx 密不可分。Nginx 处理HTTP要求有11个实行阶段,我们可以从ngx_http_core_module.h 的源码中看到:
typedef enum { NGX_HTTP_POST_READ_PHASE = 0, NGX_HTTP_SERVER_REWRITE_PHASE, NGX_HTTP_FIND_CONFIG_PHASE, NGX_HTTP_REWRITE_PHASE, NGX_HTTP_POST_REWRITE_PHASE, NGX_HTTP_PREACCESS_PHASE, NGX_HTTP_ACCESS_PHASE, NGX_HTTP_POST_ACCESS_PHASE, NGX_HTTP_PRECONTENT_PHASE, NGX_HTTP_CONTENT_PHASE, NGX_HTTP_LOG_PHASE} ngx_http_phases;
巧合的是,OpenResty 也有 11 个 _by_lua 指令,它们和 NGINX 的11个实行阶段有很大的关联性。指令是利用Lua编写Nginx脚本的基本构建块,用于指定用户编写的Lua代码何时运行以及运行结果如何利用等。下图显示了不同指令的实行顺序,这张图可以帮助理清我们编写的脚本是按照若何的逻辑运行的。
四、OpenResty 核心模块
OpenResty 是一个基于 NGINX 的全功能 Web 平台,它集成了许多模块和库,为 NGINX 增加了额外的功能和能力。以下是 OpenResty 的一些核心模块:
1)ngx_lua 模块ngx_lua 模块是 OpenResty 的核心模块之一,供应了对 Lua 脚本的支持。它许可开拓者在 NGINX 配置中嵌入Lua代码,实现高等的要求处理逻辑、动态内容天生、访问掌握等功能。
ngx_lua 模块示例:
server { listen 80; server_name example.com; location /lua_example { default_type 'text/plain'; content_by_lua_block { ngx.say("Hello, ngx_lua!") } }}
在这个例子中,当访问 http://example.com/lua_example 时,将返回 "Hello, ngx_lua!"。这里利用了 ngx_lua 模块的 content_by_lua_block 指令,将 Lua 代码嵌入 NGINX 配置文件。
2)ngx_stream_lua 模块ngx_stream_lua 模块 与 ngx_lua 类似,但专门用于处理 TCP 和 UDP 流量。它许可开拓者在 NGINX 配置中嵌入 Lua 代码以处理流量。
以下是一个大略的 ngx_stream_lua 模块的示例:
stream { server { listen 12345; content_by_lua_block { local data, err = ngx.req.socket() if not data then ngx.log(ngx.ERR, "Failed to read request: ", err) return end ngx.say("Received data: ", data) } }}
在这个示例中:
利用 content_by_lua_block 指令定义了一个 Lua 代码块,用于处理 TCP 流量。通过 ngx.req.socket() 获取连接的套接字,然后读取要求数据。输出吸收到的数据。此配置监听在端口 12345 上,当有 TCP 连接到达时,Lua 代码将读取并输出吸收到的数据。
3)ngx_http_lua_module 模块ngx_http_lua_module 模块是 ngx_lua 模块的一部分,为 NGINX 供应了强大的 HTTP 做事和 Lua 扩展。
以下是一个大略的 ngx_http_lua_module 模块的示例:
server { listen 80; server_name example.com; location /lua_example { default_type 'text/plain'; content_by_lua_block { ngx.say("Hello, ngx_http_lua!") } } location /lua_variable { default_type 'text/plain'; set $my_variable "NGINX with Lua"; content_by_lua_block { local my_variable = ngx.var.my_variable ngx.say("Value of my_variable: ", my_variable) } }}
这个示例中:
/lua_example 路径下的要求将返回 "Hello, ngx_http_lua!"。这里利用了 content_by_lua_block 指令,将 Lua 代码嵌入 NGINX 配置文件,实现了大略的相应内容输出。/lua_variable 路径下的要求将输出一个自定义变量的值。利用了 set 指令设置了一个名为 my_variable 的变量,然后在 Lua 代码块中通过 ngx.var 获取并输出了这个变量的值。4)ngx_http_headers_more 模块ngx_http_headers_more 模块供应了更多的操作 HTTP 头部的指令,使得在 NGINX 中更随意马虎操作和修正 HTTP 头信息。
以下是一个大略的利用 ngx_http_headers_more 模块的示例:
server { listen 80; server_name example.com; location /add_custom_header { more_set_headers "Custom-Header: OpenResty"; return 200 "Custom header added!"; } location /remove_server_header { more_clear_headers Server; return 200 "Server header removed!"; }}
在这个示例中:
/add_custom_header 路径下的要求将返回 "Custom header added!",同时相应头中包含了一个自定义的头部 "Custom-Header: OpenResty"。这是通过 more_set_headers 指令添加的。/remove_server_header 路径下的要求将返回 "Server header removed!",同时相应头中不再包含 "Server" 头部。这是通过 more_clear_headers 指令移除的默认的 "Server" 头部。这些指令许可你更灵巧地配置 NGINX 的相应头信息,添加或删除特定的头部字段。请把稳,利用这些指令时应谨慎,确保符合安全性和隐私性的最佳实践。
5)ngx_http_echo 模块ngx_http_echo 模块 供应了更丰富的内容输出和变量更换的功能。可以通过指定相应内容、设置 HTTP 状态码等,以及支持类似 PHP 的变量更换。
server { listen 80; server_name example.com; location /echo_example { echo "Hello, ngx_http_echo!"; }}
在这个示例中:
/echo_example 路径下的要求将返回 "Hello, ngx_http_echo!"。这是通过 ngx_http_echo 模块的 echo 指令实现的。ngx_http_echo 模块的 echo 指令许可你更方便地输出内容,支持类似 PHP 的变量更换等功能。你可以在 echo 指令中直策应用变量,也可以利用其他模块供应的一些分外的变量。6)ngx_http_lua_upstream 模块ngx_http_lua_upstream 模块用于在 Lua 脚本中进行向上游做事器(后端做事器)的要求,并处理来自上游的相应。
以下是一个大略的示例,演示了如何利用 ngx_http_lua_upstream 模块向上游做事器发起要求,并处理来自上游做事器的相应:
http { upstream backend { server backend1; server backend2; } server { listen 80; server_name example.com; location /proxy_example { content_by_lua_block { -- 初始化 upstream 工具 local upstream = require "ngx.upstream" local backend = upstream.backend -- 创建一个新的要求工具 local request = upstream.request() -- 设置要求的方法、URI和头部 request.method = ngx.HTTP_GET request.uri = "/path/to/resource" request.headers["Host"] = "backend.example.com" -- 发送要求到上游做事器 local status, headers, body = request.send(backend) -- 处理上游做事器的相应 if status == 200 then ngx.say("Response from backend: ", body) else ngx.say("Error from backend. Status: ", status) end } } }}
在这个示例中:
定义了一个名为 backend 的上游做事器块,包含两个后端做事器 backend1 和 backend2。在 /proxy_example 路径下的要求中,通过 Lua 脚本利用 ngx_http_lua_upstream 模块创建了一个新的上游要求工具。设置了要求的方法、URI和头部信息。调用 request.send(backend) 发送要求到上游做事器。根据上游做事器的相应状态码,输出相应内容或显示缺点信息。请把稳,实际利用时,你可能须要根据详细的业务需求和上游做事器的特性进行更繁芜的 Lua 脚本编写。此示例仅为演示基本用法。
7)ngx_http_redis 模块ngx_http_redis 模块供应了与 Redis 数据库的交互功能,许可 NGINX 通过 Lua 脚本与 Redis 通信。
以下是一个大略的示例,演示了如何利用 ngx_http_redis 模块与 Redis 交互:
http { server { listen 80; server_name example.com; location /redis_example { # 定义 Redis 做事器的地址和端口 set $redis_host "127.0.0.1"; set $redis_port 6379; # 利用 ngx_http_redis 模块向 Redis 发送 GET 要求 redis_pass $redis_host:$redis_port; redis_query GET my_key; # 处理 Redis 的相应 content_by_lua_block { local redis = require "ngx.redis" local red = redis:new() red:set_timeout(1000) -- 设置超时时间 local ok, err = red:connect(ngx.var.redis_host, ngx.var.redis_port) if not ok then ngx.say("Failed to connect to Redis: ", err) return end local res, err = red:get("my_key") if not res then ngx.say("Failed to get value from Redis: ", err) return end ngx.say("Value from Redis: ", res) -- 开释连接 local ok, err = red:set_keepalive(10000, 100) if not ok then ngx.say("Failed to set keepalive: ", err) return end } } }}
在这个示例中:
/redis_example 路径下的要求首先通过 redis_pass 和 redis_query 指令设置了 Redis 做事器的地址和端口,并发送了一个 GET 要求获取键为 "my_key" 的值。在 Lua 脚本中,利用 ngx.redis 模块创建了一个 Redis 工具,连接到 Redis 做事器,并通过 get 方法获取了 "my_key" 的值。末了,输出从 Redis 获取的值。请把稳,实际利用时,你须要根据你的 Redis 做事器配置和业务需求进行适当的修正。此示例仅为演示基本用法。
8)ngx_http_proxy_connect_module 模块ngx_http_proxy_connect_module 模块许可 NGINX 充当 CONNECT 代理,用于处理 TLS/SSL 连接的代理要求。
以下是一个大略的利用示例:
http { server { listen 80; server_name example.com; location /proxy_connect_example { proxy_pass http://backend; } } server { listen 443 ssl; server_name example.com; ssl_certificate /path/to/certificate.crt; ssl_certificate_key /path/to/private_key.key; location /proxy_connect_example { proxy_pass http://backend; } }}
在这个示例中:
配置了两个 server 块,分别监听了 80 端口和 443 端口。第一个 server 块用于处理 HTTP 要求,第二个 server 块用于处理 HTTPS 要求。对付 /proxy_connect_example 路径,利用了 proxy_pass 指令,将要求代理到名为 backend 的上游做事器。对付 HTTPS 的情形,须要供应 SSL 证书和私钥的路径。实际上,这个配置使 NGINX 具有 CONNECT 代理的能力,可以处理 TLS/SSL 握手并将要求代理到上游做事器。9)ngx_http_js_module 模块ngx_http_js_module 模块供应了对 JavaScript 的支持,使得可以在 NGINX 中利用 JavaScript 来编写要求处理逻辑。
以下是一个大略的利用 ngx_http_js_module 模块的示例:
http { server { listen 80; server_name example.com; location /js_example { js_content main; } } js_include main; function main(r) { r.return(200, "Hello, ngx_http_js_module!"); }}
在这个示例中:
定义了一个监听 80 端口的 server 块。在 /js_example 路径下的要求中,利用了 js_content 指令,将要求处理的逻辑指定为 JavaScript 脚本。利用 js_include 指令引入了一个名为 main 的 JavaScript 函数。main 函数中利用了 r.return 方法返回了一个 HTTP 200 相应,并带有相应的。请把稳,利用 ngx_http_js_module 模块时,须要确保已经精确安装并启用了该模块。此示例只是一个基本的演示,实际利用时可能须要根据详细的业务需求编写更繁芜的 JavaScript 脚本。
10)ngx_http_geoip2_module 模块ngx_http_geoip2_module 模块用于通过 MaxMind GeoIP2 数据库来获取客户真个地理位置信息。
以下是一个大略的示例,演示了如何利用 ngx_http_geoip2_module 模块获取客户真个地理位置信息:
http { geoip2 /path/to/GeoIP2-City.mmdb { $geoip2_city_country_iso_code country iso_code; $geoip2_city_country country names en; $geoip2_city_city city names en; $geoip2_city_latitude latitude; $geoip2_city_longitude longitude; } server { listen 80; server_name example.com; location /geoip_example { default_type 'text/plain'; content_by_lua_block { local country = ngx.var.geoip2_city_country local city = ngx.var.geoip2_city_city local latitude = ngx.var.geoip2_city_latitude local longitude = ngx.var.geoip2_city_longitude ngx.say("Country: ", country) ngx.say("City: ", city) ngx.say("Latitude: ", latitude) ngx.say("Longitude: ", longitude) } } }}
ngx_http_geoip2_module 模块用于在 NGINX 中获取客户真个地理位置信息,基于 MaxMind 的 GeoIP2 数据库。以下是一个大略的示例,演示了如何利用 ngx_http_geoip2_module 模块获取客户真个地理位置信息:
http { geoip2 /path/to/GeoIP2-City.mmdb { $geoip2_city_country_iso_code country iso_code; $geoip2_city_country country names en; $geoip2_city_city city names en; $geoip2_city_latitude latitude; $geoip2_city_longitude longitude; } server { listen 80; server_name example.com; location /geoip_example { default_type 'text/plain'; content_by_lua_block { local country = ngx.var.geoip2_city_country local city = ngx.var.geoip2_city_city local latitude = ngx.var.geoip2_city_latitude local longitude = ngx.var.geoip2_city_longitude ngx.say("Country: ", country) ngx.say("City: ", city) ngx.say("Latitude: ", latitude) ngx.say("Longitude: ", longitude) } } }}
在这个示例中:
利用 geoip2 指令配置了 GeoIP2 数据库的路径,并定义了一些变量用于存储地理位置信息,如国家 ISO 代码、国家名称、城市名称、纬度和经度。在 /geoip_example 路径下的要求中,通过 Lua 脚本获取了客户真个地理位置信息,并输出了国家、城市、纬度和经度等信息。请把稳,在实际利用中,你须要确保已经获取并配置了精确的 GeoIP2 数据库文件路径。此示例只是一个基本的演示,实际场景中可能须要根据业务需求进一步处理和利用这些地理位置信息。
11)ngx_brotli 模块ngx_brotli 模块用于支持 Brotli 压缩算法,供应更高效的内容压缩。
以下是一个大略的利用 ngx_brotli 模块的示例:
http { brotli on; brotli_comp_level 6; brotli_static on; server { listen 80; server_name example.com; location /brotli_example { default_type 'text/plain'; content_by_lua_block { ngx.say("Hello, ngx_brotli!"); } } }}
在这个示例中:
利用 brotli 指令开启了 Brotli 压缩功能。利用 brotli_comp_level 指令设置了 Brotli 压缩级别。利用 brotli_static 指令开启了静态文件的 Brotli 压缩。在 /brotli_example 路径下的要求中,返回了一个大略的文本内容 "Hello, ngx_brotli!"。请把稳,在实际利用中,你须要确保已经安装了支持 Brotli 压缩的库,并且 NGINX 配置中启用了对应的模块。此示例只是一个基本的演示,实际配置中可能须要根据业务需求调度压缩级别等参数。
这些模块共同构成了 OpenResty 的核心,使得 NGINX 变得更加强大和灵巧。利用这些模块,你可以实现更高等的要求处理、负载均衡、反向代理、动态内容天生等功能。详细信息和用法可以参考 OpenResty 官方文档:https://openresty.org/。
五、OpenResty 示例讲解OpenResty 是一个基于 NGINX 的全功能 Web 平台,集成了大量的第三方模块和库,个中最主要的是 ngx_lua 模块,它许可在 NGINX 配置中嵌入 Lua 脚本,实现高等的要求处理逻辑、动态内容天生、访问掌握等功能。下面是一个大略的 OpenResty 示例:
http { server { listen 80; server_name example.com; location /hello { default_type 'text/plain'; content_by_lua_block { ngx.say("Hello, OpenResty!") } } }}
在这个示例中:
配置了一个监听 80 端口的 server 块,处理 example.com 的要求。当访问路径 /hello 时,通过 content_by_lua_block 指令实行 Lua 代码,输出 "Hello, OpenResty!"。这只是一个最大略的演示,OpenResty 的强大之处在于它许可在 NGINX 配置中利用 Lua 脚本,从而实现更繁芜的逻辑。以下是一个稍繁芜的示例,演示了如何通过 OpenResty 实现大略的 API 访问掌握:
http { lua_shared_dict my_limit 10m; server { listen 80; server_name api.example.com; location /api { access_by_lua_block { local limit = ngx.shared.my_limit local key = ngx.var.remote_addr local reqs, err = limit:get(key) if reqs then if reqs > 10 then ngx.exit(ngx.HTTP_TOO_MANY_REQUESTS) else limit:incr(key, 1) end else limit:set(key, 1, 60) end } default_type 'application/json'; content_by_lua_block { ngx.say('{"message": "API response"}') } } }}
在这个示例中:
配置了一个共享内存字典 my_limit 用于存储要求计数。当访问路径 /api 时,通过 access_by_lua_block 指令实行 Lua 代码,实现了一个大略的要求频率限定,每个 IP 地址在 60 秒内最多许可 10 次要求。如果超过要求限定,将返回 HTTP 429 (TOO MANY REQUESTS) 状态码;否则,连续实行后续 Lua 代码返回 JSON 相应。这只是 OpenResty 的一小部分功能展示,实际利用中可以结合更多的模块和功能,如 ngx_http_lua_upstream、ngx_http_headers_more、ngx_stream_lua 等,以实现更繁芜的 Web 运用和做事。
OpenResty 先容与实战讲解就先到这里了,有任何疑问也可关注我"大众号:大数据与云原生技能分享,进行技能互换,如本篇文章对您有所帮助,麻烦帮忙一键三连(点赞、转发、收藏)~