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完全开发指南
相关推荐
拔剑纵狂歌16 分钟前
Golang异常处理机制
开发语言·后端·golang·go
缘友一世26 分钟前
Armbian 1panel面板工具箱中FTP服务无法正常启动的解决方法
linux·运维·后端·1panel
ffyyhh99551128 分钟前
java进行音视频的拆分和拼接
java·音视频
weixin_4193497935 分钟前
flask使用定时任务flask_apscheduler(APScheduler)
后端·python·flask
乐之者v36 分钟前
Spring之 IoC、BeanFactory、ApplicationContext
java·后端·spring
DS_Watson44 分钟前
字符串和正则表达式踩坑
java·开发语言
Wayfreem1 小时前
Java锁升级:无锁 → 偏向锁 → 轻量级锁 → 重量级锁
java·开发语言
我焦虑的编程日记1 小时前
【Java EE】验证码案例
java·java-ee
牧夏。1 小时前
vscode运行java中文乱码,引发的mac配置问题
java·vscode·macos
一起学习计算机1 小时前
[附源码]基于Flask的演唱会购票系统
后端·python·flask