一、概述OpenResty是一个基于 Nginx 与 Lua 的高性能Web平台其内部集成了大量精良的Lua库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web应用、Web服务和动态网关。简单地说OpenResty的目标是让你的Web服务直接跑在 Nginx 服务内部充分利用 Nginx 的非阻塞 I/O 模型不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。从上面官网的描述信息中可以看出OpenResty主要包含两方面的技术Nginx一款轻量级、高性能、高并发的Web服务器。Lua一种轻量、小巧、可移植、快速的脚本语言LuaJIT即时编译器会将频繁执行的Lua代码编译成本地机器码交给CPU直接执行执行效率更高OpenResty会默认启用LuaJIT。官方网站http://openresty.org/Github组织https://github.com/openrestynginx 与 lua 介绍与安装可以参考我以下几篇文章NGINX - 高级负载均衡器、Web服务器、反向代理NGINX 路由配置与参数详解https配置、跨域配置、socket配置NGINX sub_filter 和 subs_filter 指令讲解lua 语法介绍与 NGINX lua 高级用法实战操作二、OpenResty 安装yum install pcre-devel openssl-devel gcc curl wget https://openresty.org/package/centos/openresty.repo sudo mv openresty.repo /etc/yum.repos.d/openresty.repo # update the yum index: sudo yum check-update yum -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的一些核心模块1ngx_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配置文件。2ngx_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代码将读取并输出接收到的数据。3ngx_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获取并输出了这个变量的值。4ngx_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的响应头信息添加或删除特定的头部字段。请注意使用这些指令时应谨慎确保符合安全性和隐私性的最佳实践。5ngx_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指令中直接使用变量也可以使用其他模块提供的一些特殊的变量。6ngx_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脚本编写。此示例仅为演示基本用法。7ngx_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 服务器配置和业务需求进行适当的修改。此示例仅为演示基本用法。8ngx_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握手并将请求代理到上游服务器。9ngx_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 脚本。10ngx_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数据库文件路径。此示例只是一个基本的演示实际场景中可能需要根据业务需求进一步处理和使用这些地理位置信息。11ngx_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应用和服务。