OpenResty 笔记 :让Nginx也能实现复杂功能

首先分享之前的所有文章 , 欢迎点赞收藏转发三连下次一定 >>>> 😜😜😜
文章合集 : 🎁 juejin.cn/post/694164...
Github : 👉 github.com/black-ant
CASE 备份 : 👉 gitee.com/antblack/ca...

一 . 前言

以前也简单涉及过 OpenResty , 但是未深入的思考 , 这个组件应该扮演什么角色 , 这一篇就以架构的角度来想一想 , OpenResty 可以解决什么问题

文章目标 :

  • OpenResty 入门上手

宏观观念

  • OpenResty 是使用 C 语言编写的
  • OpenResty 是一个基于Nginx 的高性能Web 平台
  • OpenResty 能够方便地使用动态脚本语言Lua搭建高并发、高扩展性的Web 应用和动态网关

有没有必要学 ?

  • 你能想象这个组件在 哔哩哔哩 有自己的官方号吗 ?? space.bilibili.com/457424101
  • 从 2011 年发布,到2023 年官方论坛还保持活跃

二. 宏观

2.1 宏观图

从这个图里面可以看出来,整个框架中有几个核心的组件:

  • Nginx : 主角,底层基石,高性能的 Web 服务器
  • LuaJIT : 一个 Lua 语言的解释器和编译器 , 这个组件可以在运行时动态生成和编译机器码(可以看成 LUA 虚拟机)
  • ngx_lua :这是一个 OpenResty 的模块,允许在 Nginx 服务器中嵌入 Lua 脚本

2.2 性能

这里直接引用 《OpenResty完全开发指南》 里面的结果 :

  • Transferred : 传输数据量
  • Transfer rate :数据传输的速率,通常以每秒传输的数据量来表示 ,越高表示越快

从这个结果上看, OpenResty 的性能很高。毕竟底层使用的是 Nginx , 外层使用的是轻量级的 LUA 脚本,还慢就不合理了。

2.3 使用优势

  • Spring 类型的业务网关性能不够,需要的硬件资源更多
  • Nginx 性能足够,但是业务属性低,无法实现复杂的功能

= 需要一个既能实现业务功能, 性能又强劲的网关 = OpenResty

三. OpenResty 基础操作

3.1 OpenResty 的安装方式

@ blog.csdn.net/u013697959/...

java 复制代码
// Step 1 : 依赖库下载
yum install readline-devel pcre-devel openssl-devel
    
// Step 2 :  OpenResty 下载
wget https://openresty.org/download/openresty-1.19.9.1.tar.gz
tar -zxvf openresty-1.19.9.1.tar.gz 
cd openresty-1.19.9.1
    
// Step 3 : OpenResty 安装
判断是否安装 gcc : which gcc
未安装 : yum -y install gcc automake autoconf libtool make
    
./configure 
make 
make install

// Step 4 : 查看文件 , 并且创建访问权限
ll /usr/local/openresty/    
    
mkdir /home/www
cd /home/www/
mkdir openresty/ openresty/logs openresty/conf

3.2 怎么把代码写到 Nginx 里面的

OpenResty 支持3种集成 Lua 脚本的方式 :

  • 方式一 : 通过配置项 content_by_lua , 通过该配置项可以直接把 Lua 代码集成到 Nginx 配置红
  • 方式二 : 引用外部 Lua 文件 ,直接调用文件内的内容
  • 方式三 : 引用外部 Lua 模块,这一类的功能功能会更加复杂

OpenResty 支持多种阶段执行 :

  • rewrite_by_lua : 用于在 Nginx 的 "rewrite" 阶段执行 Lua 代码,例如重写 URL 、参数等
  • content_by_lua : content 阶段,用于处理请求的内容生成和响应 ,生成响应内容等
  • header_filter_by_lua : header_filter 阶段,处理请求头
  • body_filter : 修改响应体 body 内容
  • log_by_lua : 用于记录响应日志
  • access_by_lua : 引用认证阶段进行处理 , 用于身份认证和验证等

方式一 : 直接嵌入 Lua 代码到 Nginx 配置文件中

java 复制代码
// Step 1 : 配置 nginx (/home/www/openresty/conf/nginx.conf)
vim nginx.conf

worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
    server {
        listen 8080;
        location / {
            default_type text/html;
            content_by_lua_block {
                ngx.say("<p>hello, world</p>")
            }
        }
    }
}


// Step 2 : 启动openresty (PS : 此处注意和前文地址对应)
/usr/local/openresty/nginx/sbin/nginx -p /home/www/openresty -c /home/www/openresty/conf/nginx.conf
    
// Step 3 : 测试访问
本机 -> ps -ef | grep nginx
http://192.168.158.30:8080/
-> Hello, World!
    

>>>> 打印Log

java 复制代码
http {
    log_format log_format_2 '$remote_addr - - $time_local - - $request_method - -  $request_uri - - $status - - $request_time - - "$request_body" - - "$resp_body"';
    log_escape_non_ascii off;
    server {
     	# ........
		body_filter_by_lua_file  /home/www/lua/lua_log.lua;
        access_log  /home/www/openresty/logs/access_test.log  log_format_2;
        
        location / {
            default_type text/html;
            content_by_lua '
                ngx.say("<p>Hello, World!V2</p>")
            ';
        }

    }
}

方式二 : 集成外部的 LUA 文件

JAVA 复制代码
// Step 1 : 准备 lua 脚本 (lua_request.lua)
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


// Step 2 : 修改
location /lua_request{
	default_type 'text/html';
	lua_code_cache off;
	content_by_lua_file /home/www/lua/lua_request.lua;
}


// Step : 重启
/usr/local/openresty/nginx/sbin/nginx -t -p /home/www/openresty -c /home/www/openresty/conf/nginx.conf

方式三 : 引用外部模块

java 复制代码
http {
    lua_package_path "/path/to/lua_modules/?.lua;;";
    lua_package_cpath "/path/to/lua_modules/?.so;;";

    server {
        location /use_lua_module {
            default_type 'text/plain';
            content_by_lua '
                local my_module = require("my_module")
                ngx.say(my_module.hello())
            ';
        }
    }
}

3.3 不同的集成阶段及复杂功能

通过 Redis 对请求进行校验。

java 复制代码
worker_processes  1;
error_log logs/error.log info;

events {
    worker_connections 1024;
}

http {
    upstream apache.org {
        server apache.org;
    }

    upstream nginx.org {
        server nginx.org;
    }

    server {
        listen 8082;
        
        // 配置 Redis 路径
        location = /redis {
            internal;
            // 在 Lua 代码中对 URI 进行解码,并将解码后的结果设置为请求 URI
            set_unescape_uri $key $arg_key;
            //发送一个 GET 请求到 Redis,获取 "$key" 的值
            redis2_query get $key;
            // 将请求代理到 Redis 数据存储
            redis2_pass 127.0.0.1:6379;
        }

        location / {
            set $target '';
            access_by_lua '
                local key = ngx.var.http_user_agent
                
                // 发起一个子请求并捕获子请求的响应内容
                local res = ngx.location.capture(
                    "/redis", { args = { key = key } }
                )
    
                // 对结果进行解析
                print("key: ", key)
                if res.status ~= 200 then
                    ngx.log(ngx.ERR, "redis server returned bad status: ",
                        res.status)
                    ngx.exit(res.status)
                end
                
                if not res.body then
                    ngx.log(ngx.ERR, "redis returned empty body")
                    ngx.exit(500)
                end
                
                local parser = require "redis.parser"
                local server, typ = parser.parse_reply(res.body)
                
                if typ ~= parser.BULK_REPLY or not server then
                    ngx.log(ngx.ERR, "bad redis response: ", res.body)
                    ngx.exit(500)
                end
                print("server: ", server)
                ngx.var.target = server
            ';

            proxy_pass http://$target;
        }
    }
}


// 重启 Nginx 
/usr/local/openresty/nginx/sbin/nginx -t -p /home/www/openresty -c /home/www/openresty/conf/nginx.conf

总结

简单的入门记录,文档记得比较早了,有些东西应该是验证过的,但是之前的服务器已经丢失了,不清楚和现在的版本是不是匹配的.

基于这个文档,就可以详细说说秒杀体系了。

补充知识点

Nginx 补充命令

java 复制代码
// 启动 Nigx 
/usr/local/openresty/nginx/sbin/nginx -p /home/www/openresty -c /home/www/openresty/conf/nginx.conf

> nginx -s stop  :  快速关闭服务
> nginx -s quit  :  正常关闭服务
> nginx -s reload  :  重新加载配置文件
> nginx -s reopen  :  重新打开日志文件

Nginx 多配置

java 复制代码
// S1 : 准备一个 主 Config 用于启动

// S2 : 在主 Config 下添加 include
worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
    server {
        listen 8080;
        location / {
            default_type text/html;
            content_by_lua_block {
                ngx.say("<p>hello, world</p>")
            }
        }
    }
   include module-config/*.conf;

}

// S3 : 子module 中创建 config(此处直接以 Server 为根就行)
server {
    listen 8080;
    location / {
        default_type text/html;
        content_by_lua_block {
            ngx.say("<p>hello, world</p>")
        }
    }
}

// 如果不行需要注意 : 
- 端口是否打开 ,防火墙
- 配置是否刷新 

参考文档

  • OpenResty完全开发指南
相关推荐
程序员爱钓鱼几秒前
Go语言实战案例-项目实战篇:新闻聚合工具
后端·google·go
IT_陈寒2 分钟前
Python开发者必须掌握的12个高效数据处理技巧,用过都说香!
前端·人工智能·后端
一只叫煤球的猫8 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz9659 小时前
tcp/ip 中的多路复用
后端
bobz9659 小时前
tls ingress 简单记录
后端
皮皮林55110 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
你的人类朋友10 小时前
什么是OpenSSL
后端·安全·程序员
bobz96510 小时前
mcp 直接操作浏览器
后端
前端小张同学13 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook13 小时前
Manim实现闪光轨迹特效
后端·python·动效