欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

OpenResty基础

程序员文章站 2022-07-09 18:46:30
OpenResty进程管理OpenResty的进程模型基于nginx,master/worker,进程相互平等且独立,由master通过信号进行管理OpenResty做了一个改进,在原有基础上增加了一个拥有root权限的特权进程,并提供了一些进程管理的库ngx.process,详细使用resty的帮助文档进行查看:./restydoc ngx.processOpenResty中进程分为六种:single:单一进程,非worker/master模式master:监控进程signall...

简介

Nginx简介

Nginx是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。

由于 Nginx 使用基于事件驱动的架构,能够并发处理百万级别的 TCP 连接,高度模块化的设计和*的许可证使得扩展 Nginx 功能的第三方模块层出不穷。因此其作为 Web 服务器被广泛应用到大流量的网站上,包括淘宝、腾讯、新浪、京东等访问量巨大的网站。

Nginx特点:

  1. 跨平台、配置简单;

  2. 非阻塞、高并发连接:处理2-3万并发连接数,官方监测能支持5万并发;

  3. 内存消耗小:开启10个nginx才占150M内存,Nginx采取了分阶段资源分配技术;

  4. nginx处理静态文件好,耗费内存少;

  5. 内置的健康检查功能:如果有一个服务器宕机,会做一个健康检查,再发送的请求就不会发送到宕机的服务器了。重新将请求提交到其他的节点上。

  6. 节省宽带:支持GZIP压缩,可以添加浏览器本地缓存;

  7. 稳定性高:宕机的概率非常小

  8. master/worker结构:一个master进程,生成一个或者多个worker进程。

  9. 接收用户请求是异步的:浏览器将请求发送到nginx服务器,它先将用户请求全部接收下来,再一次性发送给后端web服务器,极大减轻了web服务器的压力;

  10. 一边接收web服务器的返回数据,一边发送给浏览器客户端;

  11. 网络依赖性比较低,只要ping通就可以负载均衡;

  12. 可以有多台nginx服务器;

  13. 事件驱动:后端通信机制采用epoll模型。

OpenResty简介

OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

OpenResty® 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

基础知识

文档:基础知识简介

nginx内置变量汇总文档

nginx进程模型

master/worker结构:一个master进程,生成一个或者多个worker进程;master对worker进程采用信号进行控制。
Master进程:监控进程,不处理具体的http、tcpi请求,读取及评估配置和维持;Worker进程:处理请求。
Nginx是处理一个请求过程:

  1. 首先,nginx在启动时,会解析配置文件,得到需要监听的端口与ip地址;然后在nginx的master进程里面,先初始化好这个监控的socket,再进行listen;然后再fork出多个子进程出来, 子进程会竞争accept新的连接。
  2. 此时,客户端就可以向nginx发起连接了。当客户端与nginx进行三次握手,与nginx建立好一个连接后;
  3. 此时,某一个子进程会accept成功,然后Nginx创建对连接的封装。接着,根据事件调用相应的事件处理模块,如http模块与客户端进行数据的交换。
  4. 最后,nginx或客户端来主动关掉连接,到此,一个连接就完成了。

OpenResty运行机制

OpenResty基于Nginx,将整个web服务的生命周期和请求处理流程划分出若干个阶段,针对不同阶段openresty给出了不同指令来利用lua代码进行相关的控制

web生命周期

  1. initing阶段:服务启动,读取配置初始化内部数据结构
    1. configuration 读取配置文件,解析配置指令,设置运行参数,无控制指令
    2. master-init 配置文件解析完后,master进程初始化公用数据,可用init_by_lua进行定制
    3. worker-init worker进程自己初始化进程专用数据, 可用init_worker_by_lua进行定制
  2. running阶段:服务运行,接受请求,返回响应,对于每个请求都按照下面的流水线进行处理
    1. ssl SSL和TLS安全通信和验证,ssl_certificate_by_lua握手时设置安全证书
    2. ssl SSL和TLS安全通信和验证,ssl_certificate_by_lua握手时设置安全证书
    3. preread 预读数据,接收http请求头
    4. rewrite 改写nginx变量,set_by_lua || 改写url,实现重定向、跳转,rewrite_by_lua
    5. access 访问控制或者限速,access_by_lua
    6. content 产生响应内容,content_by_lua || 反向代理时选择后端服务器 balancer_by_lua
    7. filter 加工处理响应头 header_filter_by_lua, 加工处理响应体 body_filter_by_lua
    8. log 记录日志,log_by_lua
  3. exiting 服务停止,进行清理工作,如关闭监听端口

上面的xxx_by_lua都有三种形式的实现

  • xxx_by_lua ‘lua code’(字符串形式)
  • xxx_by_lua_block {lua code}(花括号形式,低版本的不行)
  • xxx_by_lua_file lua_file.lua(文件形式)

使用参考文档

restydoc nginx #查找模块的说明
restydoc -s proxy_pass #-s指定小节

配置说明

location 匹配规则
模式 含义
location = /uri = 表示精确匹配,只有完全匹配上才能生效
location ^~ /uri ^~ 开头对URL路径进行前缀匹配,并且在正则之前。
location ~ pattern 开头表示区分大小写的正则匹配
location ~* pattern 开头表示不区分大小写的正则匹配
location /uri 不带任何修饰符,也表示前缀匹配,但是在正则匹配之后
location / 通用匹配,任何未匹配到其它location的请求都会匹配到,相当于switch中的default
基础用法
#定位lua库和so库指令,apinginx的nginx.conf中的配置
# lua package path 
lua_package_path "/mnt***/nginx/lua/?.lua;;";
# lua package cpath
lua_package_cpath "/mnt/***nginx/baselib/?.so;";
#缓存lua代码,默认开启,,开启的时候lua代码加载到luavm后会被缓存,只读取一次,为了避免频繁读取磁盘,线上要开启。方便调试使用时可关闭,避免一直-s reload
lua_code_cache [on|off]
#该配置对卸载conf文件的lua代码无效,对init_by_lua_file/init_worker_by_lua_file中的代码无效
#基础配置(必须)
http {
    server {
        listen    80;
        location = /xxx{
            #用下面的location配置替换
        }}}
location = /sum {
    # 只允许内部调用
    internal;
    content_by_lua_block {
        local args = ngx.req.get_uri_args()
        #ngx.say和ngx.print两者都是为了异步输出http响应体,区别在于前者会多个\n
        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)
    }}
#串行方式调用
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)
    }}
#流水线方式跳转
location ~ ^/static/([-_a-zA-Z0-9/]+).jpg {
    #获取uri参数,设置变量值
    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 = /foo {
    content_by_lua_block {
        ngx.say([[I am foo]])
    }}
location = / {
    rewrite_by_lua_block {
        return ngx.redirect('/foo');
    }}
#获取uri参数和post参数
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,或者server配置下添加全局配置:lua_need_request_body on;
       ngx.req.get_body_data() #获取body数据
       local arg = ngx.req.get_post_args()
       for k,v in pairs(arg) do
           ngx.say("[POST] key:", k, " v:", v)
       end
   }}
#如果请求体尚未被读取,请先调用 ngx.req.read_body (或打开 lua_need_request_body 选项强制本模块读取请求体,此方法不推荐)。
#如果请求体已经被存入临时文件,请使用 ngx.req.get_body_file 函数代替。
#如需要强制在内存中保存请求体,请设置 client_body_buffer_size 和 client_max_body_size 为同样大小。
#传递参数
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)
   }}
#日志打印,这个可以为nginx增加更加详细的错误日志打印,可以考虑在nginx的上游请求报错时打印出详细的请求日志,利于排查问题
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)
    }}

OpenResty进程管理

  1. OpenResty的进程模型基于nginx,master/worker,进程相互平等且独立,由master通过信号进行管理

  2. OpenResty做了一个改进,在原有基础上增加了一个拥有root权限的特权进程,并提供了一些进程管理的库ngx.process,详细使用resty的帮助文档进行查看:./restydoc ngx.process

  3. OpenResty中进程分为六种:

    1. single:单一进程,非worker/master模式
    2. master:监控进程
    3. signaller :信号进程,-s参数时的进程
    4. worker :工作进程,对外提供服务、ngx.worker.pid,ngx.worker.id获取pid和id
    5. helper:辅助进程,如cache进程
    6. privileged agent:特权进程,OpenResty独有类型,显示调用ngx.process.enable_privileged_agent()方法才能让worker进程升级为该类型,只能在init_by_lua*阶段调用,利用ngx.timer进行定时任务,利用共享内存和其他工作线程通信。

OpenResty进程间通信:共享内存

官方博客:OpenResty 和 Nginx 如何分配和管理内存

  1. OpenResty多进程之间进行通信的方式是通过共享内存实现的,它在内存开辟一段特别的内存,多个进程可以共享所有权,进行读写数据,比信号、管道、消息队列套接字等其他方式来说速度更快
  2. OpenResty中内置强大的共享内存功能,不仅支持数据存取,还支持原子计数和队列操作,类似于一个微型的redis,数据类型只能是布尔、数字和字符串,其他的需要先序列化
#共享内存操作,所有方法都是原子操作,多进程并发下是安全的
shared_dict share_mem_cache 100m; #指令 内存命名 大小
local dict = ngx.shared.share_mem_cache #获取共享内存对象
#使用参考文档获取详细使用说明:
./restydoc ngx.shared.DICT    #从文档里面查看获取后的对象详细使用方法
./restydoc ngx.shared.DICT.get    #从文档里面查看获取后的对象详细使用方法

主要的方法包括

方法 功能
get_stale 功能
get 功能
set 功能
safe_set 功能
add 功能
safe_add 功能
replace 功能
delete 功能
incr 功能
lpush 功能
rpush 功能
lpop 功能
rpop 功能
llen 功能
ttl 功能
expire 功能
flush_all 功能
flush_expired 功能
get_keys 功能
capacity 功能
free_space 功能

定时器

详细使用说明通过文档:./restydoc -s ngx.timer
TODO

反向代理及负载均衡

TODO

日志打印

TODO

小功能

推荐一个github上面实现的基于OpenResty和Eureka实现的服务注册发现和动态路由:注册发现与动态路由

闲着可以研究一下

本文地址:https://blog.csdn.net/cRZ_7/article/details/107584963

相关标签: 大后端 nginx