my_study_nginx’s 学习笔记
我自己对nginx学习视频的学习笔记
初识nginx
主要使用场景
静态资源服务
反向代理服务
api服务

nginx为何出现
互联网的跨苏普及
摩尔定律性能提升
低效的apache 一个连接对应一个进程
nginx的优点
高并发,高性能
可扩展性比较好
高可靠性
热部署
BSD许可证
nginx组成
nginx二进制可执行文件
nginx.conf配置文件
access.log 访问日志
error.log 错误日志
常见nginx及其分支
标准分支
开源nginx: nginx.org
商业版本: nginx.com
tengine
tengine是淘宝发起的web服务器项目
openrestry
张亦春维护的。
开源版本 openresty.org
商业版本 openresty.com
nginx配置语法
配置文件由指令与指令块构成
每个指令以分号结尾,指令和参数之间空格分隔。
指令块以{}大括号将多条指令组织在一起。
include 语句运行组合多个配置文件来提升可维护性。
使用#符号表示注释,提升可读性。
使用$符号使用变量。
部分指令是支持正则表达式的。
配置样例

nginx 编译安装
wget https://nginx.org/download/nginx-1.20.2.tar.gz
tar xf nginx-1.20.2.tar.gz
cd nginx-1.20.2/
yum install gcc
./configure --prefix=/root/nginx
make && make install
cd /root/nginx
./sbin/nginx
ps axu |grep nginx
nginx命令行
重载配置文件
vim conf/nginx.conf 修改端口,
./sbin/nginx -s reload
热部署
热部署是保证在一个nginx状态下,完成不影响业务的前提下更新nginx从一个版本到另一个版本的过程。
# 备份下老版本的
mv sbin/nginx sbin/nginx.old
# 弄新版本nginx过来
cp /root/n2/sbin/nginx sbin/nginx
[root@zhaojiedi-elk-2 nginx]# ps aux |grep nginx |grep master
root 33924 0.0 0.0 20708 1380 ? Ss 15:52 0:00 nginx: master process ./sbin/nginx
# 发送热部署信号
kill -USR2 33924
# 检查查看有2个master进程和对应的work进程
[root@zhaojiedi-elk-2 nginx]# ps aux |grep nginx
root 33924 0.0 0.0 20708 1380 ? Ss 15:52 0:00 nginx: master process ./sbin/nginx
nobody 35468 0.0 0.0 33380 1484 ? S 15:55 0:00 nginx: worker process
root 40861 0.0 0.0 20576 1604 ? S 16:00 0:00 nginx: master process ./sbin/nginx
nobody 40862 0.0 0.0 33264 1620 ? S 16:00 0:00 nginx: worker process
root 41217 0.0 0.0 112812 976 pts/1 S+ 16:01 0:00 grep --color=auto nginx
# 通知老的进行关闭自己work进程
kill -WINCH 33924
# 确认老的work关闭
[root@zhaojiedi-elk-2 nginx]# ps aux |grep nginx
root 33924 0.0 0.0 20708 1380 ? Ss 15:52 0:00 nginx: master process ./sbin/nginx
root 40861 0.0 0.0 20576 1604 ? S 16:00 0:00 nginx: master process ./sbin/nginx
nobody 40862 0.0 0.0 33264 1620 ? S 16:00 0:00 nginx: worker process
root 41782 0.0 0.0 112812 972 pts/1 S+ 16:02 0:00 grep --color=auto nginx
# 这里可以在发送一个kill -9 信号关闭老的,或者留着, 然后发送reload进行重启。
切割日志文件
mv access.log access.log.$(date "+%F")
./sbin/nginx -s reopen
SSL发展
发展过程
ssl3.0 => tls1.0 => tls1.1 => tls1.2 => tls1.3
密码套件

证书类型
域名验证 => 组织验证 => 扩展验证
SSL通信过程

client hello: 客户端通过发送消息给服务端发起握手请求,该消息包括了客户端支持的tls版本和多个密码套件以供服务端选择,还有一个随机数。
server hello: 服务端发送server hello对客户端进行回应,包含数字证书 选择一个密码套件和一个随机数。
验证: 对服务端进行证书验证,检查数字签名,证书链,有效期。
预主秘钥: 客户端发送给服务器一个随机字符串,这是经过服务端的证书加密的。
服务端使用私钥解密出来预主秘钥
生成共享秘钥: 根据客户端随机数,服务端随机数以及预主秘钥三个数,然后通过算法生成共享秘钥。
客户端发送finish: 这个finish是经过共享秘钥加密的。
服务端就绪: 服务端发送经过共享秘钥加密的finish信号。
握手完成。
配置证书
一般情况下会通过nginx的include来包含各个域名的配置文件。
通过include sites/*.conf 这种片段来包含sites目录下各个配置文件, 具体配置文件里面是每个域名的配置。
# 老的配置
[root@zhaojiedi-elk-2 nginx]# cat sites/nx.linuxpanda.tech.conf
server{
listen 8083 ;
server_name nx.linuxpanda.tech;
alias /html/nx;
}
# 申请证书,一般是2个文件, crt 一个 key一个, 一个是公钥的一个是私钥的。
[root@zhaojiedi-elk-2 nginx]# cat sites/nx.linuxpanda.tech.conf
server{
listen 8083 ;
listen 8443 ssl;
server_name nx.linuxpanda.tech;
alias /html/nx;
ssl_certificate ssl/nx.linuxpanda.tech.crt;
ssl_certificate_key ssl/nx.linuxpanda.tech.key;
}
重载下nginx即可生效
Note
如果你要使用免费证书的话,这里建议大家选择国外的证书免费提供商,国内的太绕了,需要填写和登记的太多了。
可以参考下: https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E
openresty+lua样例
#添加如下片段
location /lua {
default_type text/html;
content_by_lua_block {
ngx.say("<p>hello, world</p>")
}
}
# 重载一下
[root@zhaojiedi-elk-2 openresty]# curl http://10.157.89.215:8084/lua
<p>hello, world</p>
nginx架构基础
nginx请求处理流程

nginx接收流量, 通过fastcgi、tcp代理等转发后端。 内部完成日志处理,静态文件处理,和一些状态机处理。
nginx进程结构

基本是有个master进程的, 多个work进程的。 还可能有cache manager进程和cache loader进程。
nginx进程管理
master 进程
需要监控worker进程的chld信号
管理worker进程
接收控制信号 term int quit hup usr1 usr2 winch
work进程
接收管理信号 term quit usr1 winch
nginx命令行
reload : hup
reopen : usr1
stop : term
quit : quit
reload流程
向master发送hup信号
master校验conf配置
master打开新的端口(如果需要)
master进程用新的配置启动新的worker子进程。
master向老的worker发送quit信号
老的worker进程关闭监听句柄,处理完毕当前连接结束进程。
热升级流程
旧nginx文件替换为新的nginx文件
给master发送usr2信号
master修改pid文件名字,加后缀.oldbin
master进程使用新的nginx文件启动新的master进程
向老的master发送quit信号,关闭老的master
如果要回滚的话, 可以给老的master发送hup信号, 给新的master发送quit信号即可。
worker进程优雅退出
设置定时器worker_shutdown_timeout
关闭监听句柄
关闭空闲连接
循环关闭断开的连接
退出进程
网络传输
网络传输过程

tcp流与报文

epoll高性能
每次只处理活跃连接。
实现层面红黑树和链表高效。
select缺点
每次调用selet都需要将fd集合从用户态copy到内核态,
在内核态遍历所有fd
select默认支持的文件描述符也比较小。
poll模式基本和select一致。 文件描述符支持更多。
epoll
线程安全的。
使用mmap共享用户和内核部分空间,避免来回copy.
基于事件驱动,注册事件的时候注册了callback回调函数的, epoll_wait只返回发生的事件。
请求切换
apache传统web服务, 进程调度比较多。
nginx用户态完成连接切换
nginx模块
主要模块
events
http
core
errlog
mail
thread_poll
stream
openssl
连接池
包含了对下游客户端的连接和对上游服务的连接。
内存池
connection_poll_size 内存提前分配好一批。 大块内存使用alloc分配。
连接内存池
请求内存池 一般4k
connection_poll_size
request_poll_size
nginx进程间的通讯方式
信号和共享内存 通过共享内存的worker进程之间存在抢占问题, 需要引入锁机制。 内存管理对应需要slab内存管理器。
哪些需要共享内存
限流类的
cache类
lua使用
nginx slab 编译使用
wget https://tengine.taobao.org/download/tengine-2.3.3.tar.gz
tar xf tengine-2.3.3.tar.gz
./configure --add-module=/root/tengine-2.3.3/modules/ngx_slab_stat
make && make install
替换掉openrest的二进制文件, 重启。
nginx配置的修改
lua_shared_dict dogs 10m;
location = /slab_stat {
slab_stat;
}
location /set {
content_by_lua_block{
local dogs = ngx.shared.dogs
dogs:set("panda",1)
ngx.say("stored")
}
}
location /get {
content_by_lua_block{
local dogs = ngx.shared.dogs
ngx.say(dogs:get("panda"))
}
}
[root@zhaojiedi-elk-2 nginx]# curl http://localhost:8084/slab_stat
* shared memory: dogs
total: 10240(KB) free: 10168(KB) size: 4(KB)
pages: 10168(KB) start:00007F3CCFB54000 end:00007F3CD0544000
slot: 8(Bytes) total: 0 used: 0 reqs: 0 fails: 0
slot: 16(Bytes) total: 0 used: 0 reqs: 0 fails: 0
slot: 32(Bytes) total: 127 used: 1 reqs: 1 fails: 0
slot: 64(Bytes) total: 0 used: 0 reqs: 0 fails: 0
slot: 128(Bytes) total: 32 used: 2 reqs: 2 fails: 0
slot: 256(Bytes) total: 0 used: 0 reqs: 0 fails: 0
slot: 512(Bytes) total: 0 used: 0 reqs: 0 fails: 0
slot: 1024(Bytes) total: 0 used: 0 reqs: 0 fails: 0
slot: 2048(Bytes) total: 0 used: 0 reqs: 0 fails: 0
nginx容器
哈希表配置
bucket_size : 控制每个的大小。
max_size 这个控制一共最多不能超过多少个。

红黑树
自平衡的二叉查找树的特点
高度不会超过2 log(n)
增删改查复杂度log(n)
遍历复杂度o(n)
如何编译动态模块
动态模块一些,频繁更新的时候建议使用动态模块, 不用每次去更新二进制文件的。 这个在编译的时候使用–add-dynamic-module即可。
nginx的http模块
配置块的嵌套情况
http {
upstream {}
map {}
geo {}
server {}
server{
if () {}
location {
}
location {
}
}
}
指令的上下文
指令的上下文是控制指令在哪个地方生效。这里按照官方网站的介绍一个。

这个例子说明log_format这个指令只能在http的片段内进行配置。
指令的合并
值指令: 可以合并,子类可以从父类获取值的。可以向上覆盖的。
动作类指令: 不可以合并。

listen 指令
参考: https://nginx.org/en/docs/http/ngx_http_core_module.html
这里提供几种listen方式
listen unix:/var/run/nginx.sock;
listen 127.0.0.1:8000;
listen 127.0.0.1;
listen 8000;
listen \*:8000;
listen [::]:8000 ipv6only=on;
listen [::1];
接收请求事件模块
操作系统会完成三次握手的, nginx通过epoll_wait读取到握手完毕包, nginx开始分配连接池 connection_poll_size:512 , nginx的http模块会给这个请求读取设置一个超时时间 client_header_time:60s, 然后分配一个缓冲区来读取header信息, client_header_buffer_size=1k, 接下来nginx继续通过epoll_wait获取header信息,存储在这个buffer中。

接收请求事件模块详细
接收请求是2个大的部分, 一个是请求头部分,一个是请求body部分。 这里先说下第一个部分。
http模块处理请求,会先分配内存池的request_poll_size:4k,会解析行的, 如果第一行数据比较大, 原来的client_header_buffer_size 是放不下的,需要分配大内存。 large_clent_header_buffers: 4 8k 的大小。 继续解析行。 解析好后,uri变量就有值了, 接下来继续获取header信息 。 这个和uri使用共同的buffer。

上面提到的几个参数重点这里说明下
client_header_buffer_size: 默认是1k的, 也就是默认1k,如果uri和header信息这个1k不够存储的话才会使用large_client_header_buffers指定的大小。
large_client_header_buffers: 默认4 8k, 如果8k能够存储下,那就只是用1个8k, 不够的话,2个,再不够就3个,但是最多使用4个8k的大小。如果超过4*8k大小那就返回414 url too large ,or 400.
client_header_timeout: 默认60s,如果60s内没有读取完毕,就响应408.
正则表达式
nginx的正则是标准的posix正则, 这里简单说下。

nginx的正则也是支持捕获组的,也支持捕获组命名的。 样例如下
rewrite^/admin/website/solution/(\d+)/change/uploads/(.*)\.(?<ext>png|jpg|gif|jpeg|bmp)$ /static/uploads/$2/$3.$ext last;
server_name 指令
server_name 后面可以指定多个域名的, 第一个是主域名。 相关参数 server_name_in_redirect on表示在重定向的时候使用主域名而非用户访问过来的域名进行重定向。
补充说明:
server_name 的指定的特殊情况。 “” 表示匹配没有传递host头部的请求, _表示匹配所有。
server {
listen 8084;
server_name n-n1.linuxpanda.tech n-n2.linuxpanda.tech ;
server_name_in_redirect on;
return 302 /redirect;
}
测试下如下
# server_name_in_redirect on 的情况下 可以发现重定向的结果都是变成了主域名的host了。
curl http://n-n1.linuxpanda.tech:8084/ -IL
HTTP/1.1 302 Moved Temporarily
Server: openresty/1.19.9.1
Date: Mon, 06 Dec 2021 12:28:56 GMT
Content-Type: text/html
Content-Length: 151
Location: http://n-n1.linuxpanda.tech:8084/redirect
Connection: keep-alive
curl http://n-n2.linuxpanda.tech:8084/ -IL
HTTP/1.1 302 Moved Temporarily
Server: openresty/1.19.9.1
Date: Mon, 06 Dec 2021 12:29:44 GMT
Content-Type: text/html
Content-Length: 151
Location: http://n-n1.linuxpanda.tech:8084/redirect
Connection: keep-alive
使用正则创建变量
server {
listen 8084;
server_name ~^(?<pre>.*).linuxpanda.tech$;
server_name_in_redirect on;
return 200 "$pre\n" ;
}
验证结果如下
[root@zhaojiedi-elk-2 conf]# curl http://n-n2.linuxpanda.tech:8084/
n-n2
[root@zhaojiedi-elk-2 conf]# curl http://n-n1.linuxpanda.tech:8084/
n-n1
server匹配顺序
精确匹配的
*在前的泛域名
*在后的泛域名
正则匹配的
default server
其中default server 是在listen指定default的,那就是default server , 如果没有。 那就是nginx加载的第一个server为default server 。
nginx处理的11个阶段


post_read
server_rewrite
find_config
rewrite
post_rewrite
preaccess
access
post_access
precontent
content
log
如何获取真实的用户ip地址。
用户访问到我们的服务,可能经过多层代理后到达的, 一般情况下通过这几种方式获取用户真实ip地址。
http头部的X-Real-IP用于传递用户的真实ip地址。
http头部的X-Forwarded-For用于传递代理等中间ip地址。 一般最后就是用户ip地址。
帮助文档: https://nginx.org/en/docs/http/ngx_http_realip_module.html
real_ip_header 这个默认值是X-Real-IP的
Note
这个模块默认是不会编译到nginx的, 需要启用才可以的。 –with-http_realip_module 方式启用。
server {
server_name n-realip.linuxpanda.tech;
error_log logs/n-realip-err.log debug;
set_real_ip_from 10.157.0.0/16;
set_real_ip_from 10.21.0.0/16;
#real_ip_header X-Real-IP;
#real_ip_recursive off;
real_ip_recursive on;
real_ip_header X-Forwarded-For;
location /{
return 200 "Client real ip: $remote_addr\n";
}
}
测试结果如下
# 可以看到,real_ip_recursive on 开启后, set_real_ip_from指定的地址不会识别为real ip 的, 找到最后一个才算
[root@zhaojiedi-elk-2 nginx]# curl http://n-realip.linuxpanda.tech -H "X-Forwarded-For: 1.1.1.1 2.2.2.2 10.157.1.2 10.157.1.3"
Client real ip: 2.2.2.2
[root@zhaojiedi-elk-2 nginx]# curl http://n-realip.linuxpanda.tech -H "X-Forwarded-For: 1.1.1.1 2.2.2.2 3.3.3.3 10.157.1.2 10.157.1.3"
Client real ip: 3.3.3.3
[root@zhaojiedi-elk-2 nginx]# curl http://n-realip.linuxpanda.tech -H "X-Forwarded-For: 10.157.1.2 10.157.1.3"
Client real ip: 10.157.1.2
# 可以看到,real_ip_recursive off 关闭后,只是简单的取最后一个的。
[root@zhaojiedi-elk-2 nginx]# curl http://n-realip.linuxpanda.tech -H "X-Forwarded-For: 1.1.1.1 2.2.2.2 3.3.3.3 10.157.1.2 10.157.1.3"
Client real ip: 10.157.1.3
如果拿到用户的ip如何使用
nginx中可以通过变量访问到用户的真实ip地址。 remote_addr就是用户的ip地址。 有了这个用户ip可以做些限流等分流操作。
return 指令
这个指令结束后续处理,直接给用户响应一个code和一些内容。
官方参考: https://nginx.org/en/docs/http/ngx_http_rewrite_module.html
几种样例
return 404 "find nothing!"
return http://www.baidu.com
return 502
验证return errorpage优先级
server {
listen 8084;
server_name n-return.linuxpanda.tech;
root html/;
error_page 404 /403.html;
location /{
return 404 "find nothing!\n";
}
return 405;
}
效果验证
# return 405; 关闭
[root@zhaojiedi-elk-2 sites]# curl http://n-return.linuxpanda.tech:8084/ -IL
HTTP/1.1 404 Not Found
Server: openresty/1.19.9.1
Date: Tue, 07 Dec 2021 02:47:12 GMT
Content-Type: application/octet-stream
Content-Length: 14
Connection: keep-alive
# return 405; 启用
[root@zhaojiedi-elk-2 sites]# curl http://n-return.linuxpanda.tech:8084/ -IL
HTTP/1.1 405 Not Allowed
Server: openresty/1.19.9.1
Date: Tue, 07 Dec 2021 02:48:12 GMT
Content-Type: text/html
Content-Length: 163
Connection: keep-alive
通过验证我们知道,
server种的return指令是高于location的, 和配置前后无关系的。
return就是直接返回了, 不会在经过errpage这些处理的。
error_page
error_page 用于给特定code的展示一个特定的错误页面。 url可以包含变量的。 适用于给用户友好提示。
官方参考: https://nginx.org/en/docs/http/ngx_http_core_module.html#error_page
几种样例配置
# 这种方式,会引发内部的重定向,请求对应的页面, 方法为get, 而不是请求的原始方法。
error_page 404 /404.html;
error_page 500 502 503 504 /5xx.html ;
# 使用 = 方式,可以改变响应码的。
error_page 404 =200 /empty.gif;
# 这个没有指定200 ,那就是跟进/404.php的返回码来定。
error_page 404 = /404.php;
# 下面的这个部分就是将404请求,转发给后端backend来响应
location / {
error_page 404 =@fallback;
}
location @fallback {
proxy_pass http://backend ;
}
# 使用url的方式, 默认是响应码是302的, 当然可以指定其他的 301, 302 303 307 308 只能这几个。 第二个404=301 就是指定方式。
error_page 403 http://www.linuxpanda.tech/forbidden.html;
error_page 404=301 http://www.linuxpanda.tech/notfound.html;
rewrite指令
这个指令的功能是将指定的url替换为新的url。 支持正则表达式提取的。
当replacement以http:// 或者https://或者$schema开头, 则直接返回302重定向。
替换后的url跟进flag指定的方式进行处理。
last 这个url接下来使用新的location进行匹配。
break 停止执行。
redirect 返回302 。
permanent 返回301 。
先准备下环境
[root@zhaojiedi-elk-2 sites]# mkdir ../../html/{first,second,third}
[root@zhaojiedi-elk-2 sites]# echo "1" >> ../../html/first/1.txt
[root@zhaojiedi-elk-2 sites]# echo "2" >> ../../html/second/2.txt
[root@zhaojiedi-elk-2 sites]# echo "3" >> ../../html/third/3.txt
[root@zhaojiedi-elk-2 sites]# tree ../../html/
../../html/
├── 50x.html
├── first
│ └── 1.txt
├── index.html
├── second
│ └── 2.txt
└── third
└── 3.txt
对应配置如下
server {
listen 8084 ;
server_name n-rewrite.linuxpanda.tech;
rewrite_log on;
error_log logs/rewrite_error.log notice;
root html/;
location /first {
rewrite /first(.*) /second$1 last;
return 200 'first!\n';
#rewrite /first(.*) /second$1 last;
}
location /second {
rewrite /second(.*) /third$1 break;
#rewrite /second(.*) /third$1;
return 200 'second!\n';
}
location /third {
return 200 'third!\n';
}
location /redirect1 {
rewrite /redirect1(.*) $1 permanent;
}
location /redirect2 {
rewrite /redirect2(.*) $1 redirect;
}
location /redirect3 {
rewrite /redirect3(.*) http://n-rewrite.linuxpanda.tech$1;
}
location /redirect4 {
rewrite /redirect4(.*) http://n-rewrite.linuxpanda.tech$1 permanent;
}
}
验证结果
# 可以看到这个url直接命中了location片段, 就return了。
[root@zhaojiedi-elk-2 sites]# curl http://n-rewrite.linuxpanda.tech:8084/third/3.txt
third!
# 访问这个url命中了/second的location, 然后被break了, 后面return没有机会执行了, 然后直接content了, html/3.txt进行相应了。
[root@zhaojiedi-elk-2 sites]# curl http://n-rewrite.linuxpanda.tech:8084/second/3.txt
3
# 使用last会继续进行location的, 然后走第二个,然后和上面的案例一样了。
[root@zhaojiedi-elk-2 sites]# curl http://n-rewrite.linuxpanda.tech:8084/first/3.txt
3
# 然后进行调整rewrite和return的顺序, 在进行测试
[root@zhaojiedi-elk-2 sites]# curl http://n-rewrite.linuxpanda.tech:8084/first/3.txt
first!
# 测试第一个重定向。
[root@zhaojiedi-elk-2 sites]# curl http://n-rewrite.linuxpanda.tech:8084/redirect1/1.txt -IL
HTTP/1.1 301 Moved Permanently
Server: openresty/1.19.9.1
Date: Tue, 07 Dec 2021 04:45:17 GMT
Content-Type: text/html
Content-Length: 175
Location: http://n-rewrite.linuxpanda.tech:8084/1.txt
Connection: keep-alive
HTTP/1.1 404 Not Found
Server: openresty/1.19.9.1
Date: Tue, 07 Dec 2021 04:45:17 GMT
Content-Type: text/html
Content-Length: 159
Connection: keep-alive
[root@zhaojiedi-elk-2 sites]# curl http://n-rewrite.linuxpanda.tech:8084/redirect2/2.txt -IL
HTTP/1.1 302 Moved Temporarily
Server: openresty/1.19.9.1
Date: Tue, 07 Dec 2021 04:45:59 GMT
Content-Type: text/html
Content-Length: 151
Location: http://n-rewrite.linuxpanda.tech:8084/2.txt
Connection: keep-alive
HTTP/1.1 404 Not Found
Server: openresty/1.19.9.1
Date: Tue, 07 Dec 2021 04:45:59 GMT
Content-Type: text/html
Content-Length: 159
Connection: keep-alive
# 测试重定向一个url的。默认是302临时重定向的。
[root@zhaojiedi-elk-2 sites]# curl http://n-rewrite.linuxpanda.tech:8084/redirect3/3.txt -IL
HTTP/1.1 302 Moved Temporarily
Server: openresty/1.19.9.1
Date: Tue, 07 Dec 2021 04:46:35 GMT
Content-Type: text/html
Content-Length: 151
Connection: keep-alive
Location: http://n-rewrite.linuxpanda.tech/3.txt
curl: (7) Failed connect to n-rewrite.linuxpanda.tech:80; Connection refused
# 重定向4
[root@zhaojiedi-elk-2 sites]# curl http://n-rewrite.linuxpanda.tech:8084/redirect4/4.txt -IL
HTTP/1.1 301 Moved Permanently
Server: openresty/1.19.9.1
Date: Tue, 07 Dec 2021 04:47:40 GMT
Content-Type: text/html
Content-Length: 175
Connection: keep-alive
Location: http://n-rewrite.linuxpanda.tech/4.txt
curl: (7) Failed connect to n-rewrite.linuxpanda.tech:80; Connection refused
可以看出:
rewrite 和return的指令优先级基本一致, 谁在前谁先生效。
permanent 是301, last这是302的,默认也是302的重定向。
break这个会跳过执行,然后执行content阶段的。
last这个会继续回头进行匹配location的。 内部重定向的,
rewrite 行为记录error日志
通过rewrite_log on即可启用的,
if指令
if指令使用在server或者location中的。
# 匹配ie浏览器
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
# 提取cooke部分作为变量
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
}
# 判定请求方法
if ($request_method = POST) {
return 405;
}
# 判定变量,进行速度限制
if ($slow) {
limit_rate 10k;
}
# 无效refer 给返回403
if ($invalid_referer) {
return 403;
}
location指令
官方参考: https://nginx.org/en/docs/http/ngx_http_core_module.html#location

精确匹配优先
^~禁用正则次之
最前面的匹配正则
最长匹配前缀
如何限制每个客户端的并发连接数量
每个请求是通过worker处理, 各个work之间怎么知道别人多少流量呢。 这个时候需要引入共享内存, 全部woker进程都是可以访问这个共享内存的。 一般限制通过用户的ip来控制的。
官方文档: https://nginx.org/en/docs/http/ngx_http_limit_conn_module.html
样例配置
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_req_zone $binary_remote_addr zone=one:10m rate=2r/m;
server {
listen 8084;
server_name n-limit.linuxpanda.tech;
root html/;
error_log logs/myerror.log info;
location /{
limit_conn_status 500;
limit_conn_log_level warn;
limit_rate 50;
limit_conn addr 1;
#limit_req zone=one burst=3 nodelay;
#limit_req zone=one;
}
}
验证效果
# 第一次请求,
curl http://n-limit.linuxpanda.tech:8084/
# 换个终端继续请求一次。 这次就是500了, 因为我们设置了limit_conn_status 500
[root@zhaojiedi-elk-2 sites]# curl http://n-limit.linuxpanda.tech:8084/
<html>
<head><title>500 Internal Server Error</title></head>
<body>
<center><h1>500 Internal Server Error</h1></center>
<hr><center>openresty/1.19.9.1</center>
</body>
</html>
# 看到日志, 已经被拒绝记录日志了。
tail -f ../../logs/myerror.log
2021/12/07 15:58:08 [warn] 41823#0: *24 limiting connections by zone "addr", client: 10.157.89.215, server: n-limit.linuxpanda.tech, request: "GET / HTTP/1.1", host: "n-limit.linuxpanda.tech:8084"
几个参数说明
limit_conn_zone: 定义一个zone 涉及名字,key 和大小。
limit_conn: 限制并发数。
limit_conn_log_level: 限流的级别,
limit_conn_status: 命中限流的指定状态码,默认是503的。
如何限制每个客户端的每秒处理请求数量
官方文档: https://nginx.org/en/docs/http/ngx_http_limit_req_module.html
几个参数说明
limit_req_zone: 定义一个zone 涉及名字,key 和限制速率。
limit_req: 限制并发数,burst=0默认 nodelay将直接返回不仅进入池子。
limit_req_log_level: 限流的级别,
limit_req_status: 命中限流的指定状态码,默认是503的。
limit_req 和limit_conn 区别
这个主要涉及conn和req的区别了, conn是表示一个连接, 三次捂手四次断开, 中间是可以发送多个req的。
发了多个请求但是conn还是1的。
所有连接限制limit_conn ,请求限制limit_req .
如何限制哪些ip地址的访问权限
有时候我们只希望特定的接口只能被内网访问,或者特定的来源ip访问,其他的访问都要拒绝怎么办?
官方文档: https://nginx.org/en/docs/stream/ngx_stream_access_module.html
access模块提供allow deny 命令来控制访问的。
样例配置
server {
listen 8084;
server_name n-access.linuxpanda.tech;
root html/;
location /{
}
location /monitor {
allow 10.21.0.0/16;
deny all ;
#return 200 "monitor" ;
}
}
验证
# 10.157访问就是403的。
[root@zhaojiedi-elk-2 conf]# curl http://n-access.linuxpanda.tech:8084/monitor
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>openresty/1.19.9.1</center>
</body>
</html>
# 10.21网段机器验证下
[zhaojiedi_dxm@instance-yzjf9ek0-07 ~]$ curl http://n-access.linuxpanda.tech:8084/monitor -L
monitor.index
http base authentication
auth_basic 设置了认证的, 只有通过输入用户名和密码,校验正确才可以放到到后面的真实内容。
官方文档: https://nginx.org/en/docs/http/ngx_http_auth_basic_module.html
主要指令说明
auth_basic: 这个是弹出一个认证页面的时候,上面的title信息。
auth_basic_user_file : 指定一个密码文件, 用于核对用户的登录信息的。
这里说明下如何创建一个密码文件。
yum install httpd-tools
[root@zhaojiedi-elk-2 yum.repos.d]# htpasswd -b -c /root/openresty/nginx/conf/sites/passwd panda panda
Adding password for user panda
[root@zhaojiedi-elk-2 yum.repos.d]# cat /root/openresty/nginx/conf/sites/passwd
panda:$apr1$uG5p/wXQ$ZVip2iJlcBIgcQCS9Z48o0
# 第二种生成方式
[root@zhaojiedi-elk-2 yum.repos.d]# openssl passwd -apr1 -salt uG5p
Password:
$apr1$uG5p$HmDGUeTQSY/vpUKghwght1
配置如下
server {
listen 8084;
server_name n-access.linuxpanda.tech;
root html/;
location /{
auth_basic "what ?" ;
auth_basic_user_file conf/passwd ;
}
}
验证效果

统一的用户权限验证系统auth_request
auth_request对应的路由返回401 or 403时,会拦截请求直接nginx返回前台401 or 403信息;
auth_request对应的路由返回2xx状态码时,不会拦截请求,而是构建一个subrequest请求再去请求真实受保护资源的接口;
auth_request模式没有编译进入nginx的。
样例配置如下
upstream web1 {
server 192.168.20.131:3000;
}
upstream web2 {
server 192.168.20.131:3001;
}
server {
listen 8084;
server_name n-access.linuxpanda.tech;
location /api/web1 {
auth_request /auth;
error_page 401 = @error401;
auth_request_set $user $upstream_http_x_forwarded_user;
proxy_set_header X-Forwarded-User $user;
proxy_pass http://web1;
}
location /api/web2 {
auth_request /auth;
error_page 401 = @error401;
auth_request_set $user $upstream_http_x_forwarded_user;
proxy_set_header X-Forwarded-User $user;
proxy_pass http://web2;
}
location /auth {
internal;
proxy_set_header Host $host;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_pass http://192.168.20.131:7001/auth;
}
location @error401 {
add_header Set-Cookie "NSREDIRECT=$scheme://$http_host$request_uri;Path=/";
return 302 http://192.168.20.131:7001/login;
}
}
限制所有access阶段的satisfy指令
上面我有有allow deny 控制ip来源, 还有auth提供用户名和密码的, 还有统一认证等。 是所有都通过放行,还是一个满足就可以放行了呢。 通过satisfy指令即可实现。

这个条件判定如果一个判定能决定结果的话,后续的判定就不做了。
access
auth_basic
auth_request
precontent 阶段的try_files
依次访问多个url对应的文件,那就存着的时候直接返回内容,如果不存在则按照最后一个url响应。
一个样例
try_files /system/maintenance.html
$uri $uri/index.html $uri.html
@mongrel;
实时流量mirror 模块
处理请求时候,生成子请求访问其他服务,对子请求的返回值不做处理。 通过mirror uri 方式将流量转发给一个uri 。
root和alias指令差异
root会将完成url映射近文件路径中,alias只会将location后的url映射到文件路径中。
样例配置如下
server {
listen 8084;
server_name n-alias.linuxpanda.tech;
location /root {
root html ;
}
location /alias {
alias html;
}
location ~ /root/(\w+\.txt) {
root html/first/$1;
}
location ~ /alias/(\w+\.txt) {
alias html/first/$1;
}
}
测试效果
# 可以看到这个请求命中了第一个location了, 实际找的文件是 nginx基础目录/root/openresty/nginx + root指定位置html + 请求的路径/root
curl http://n-alias.linuxpanda.tech:8084/root
[root@zhaojiedi-elk-2 conf]# tail -n1 ../logs/access.log
10.157.89.215 - - [07/Dec/2021:19:24:24 +0800] "GET /root HTTP/1.1" 404 159 "-" "curl/7.29.0" "-"request_filename=/root/openresty/nginx/html/root document_root=/root/openresty/nginx/html realpath_root=/root/openresty/nginx/html
#实际找的文件是 nginx基础目录/root/openresty/nginx + root指定位置html/first/1.txt + 请求的路径/root/1.txt
[root@zhaojiedi-elk-2 conf]# curl http://n-alias.linuxpanda.tech:8084/root/1.txt
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>openresty/1.19.9.1</center>
</body>
</html>
[root@zhaojiedi-elk-2 conf]# tail -n1 ../logs/access.log
t/openresty/nginx/html/first/1.txt
# 命中了第二个location 访问的路径其实是 nginx基础目录/root/openresty/nginx + alias执行路径 html
curl http://n-alias.linuxpanda.tech:8084/alias
[root@zhaojiedi-elk-2 nginx]# tail -n 1 logs/access.log
10.157.89.215 - - [07/Dec/2021:20:27:20 +0800] "GET /alias HTTP/1.1" 301 175 "-" "curl/7.29.0" "-"request_filename=/root/openresty/nginx/html document_root=/root/openresty/nginx/html realpath_root=/root/openresty/nginx/html
# nginx基础目录/root/openresty/nginx + alias执行路径 html/first/a.txt
[root@zhaojiedi-elk-2 nginx]# curl http://n-alias.linuxpanda.tech:8084/alias/a.txt
[root@zhaojiedi-elk-2 nginx]# tail -n 1 logs/access.log
10.157.89.215 - - [07/Dec/2021:20:31:01 +0800] "GET /alias/a.txt HTTP/1.1" 404 159 "-" "curl/7.29.0" "-"request_filename=/root/openresty/nginx/html/first/a.txt document_root=/root/openresty/nginx/html/first/a.txt realpath_root=-
综合上面的实现发现, alias和root主要是针对的请求的uri部分是否追加到原来的访问路径上面的, alias不追加, 但是root是追加的。
额外几个变量的含义
request_filename: 带访问文件的完整的路径
document_root: 对应的访问根
realpath_root: 软连接换成真实路径。
静态文件返回的content-type
default_type 指定默认的响应类型。 log_not_found on 这是默认值, 会在访问文件不存在的时候打印对应的错误日志,可以关闭。但是不建议。
index模块
index 模块提供指定访问目录时候的默认请求文件。 默认值是index.html
auto index 模块
访问一个url的时候,通过html或者其他类型返回对应目录的目录的结构信息。
几个主要参数含义:
autoindex : 开启auto index
autoindex_exact_size: 对于html格式,指定是否输出目录列表输出准确的文件大小。
autoindex_format: 响应格式,默认是html的格式的。
autoindex_localtime: 日期的本地时间。
样例配置如下
server{
listen 8084;
server_name n-autoindex.linuxpanda.tech;
location / {
alias html/ ;
autoindex on ;
autoindex_exact_size off ;
autoindex_format xml;
}
}
设置为html的效果

设置为xml的效果

log阶段
log模块是将http请求相关信息记录到日志中,无法被禁用。
官方文档: https://nginx.org/en/docs/http/ngx_http_log_module.html
使用样例
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'request_filename=$request_filename document_root=$document_root realpath_root=$realpath_root ';
access_log logs/access.log main;
# access_log /path/to/log.gz combined gzip flush=5m;
替换响应中的字符串
通过sub模块提供的,完成对响应的内容进行替换,支持变量方式。 默认是没有编译进来nginx的。
官方文档: https://nginx.org/en/docs/http/ngx_http_sub_module.html
主要参数说明
sub_filter: 替换命令
sub_filter_once: 只替换一次
sub_filter_last_modified: 是否展示Last-Modified响应头, 默认是off的,也就是这个header被移除的。
sub_filter_types: 哪些类型文件才替换,默认是html,*表示所有类型。
样例配置如下
server {
listen 8084;
server_name n-sub.linuxpanda.tech;
location / {
alias html/ ;
sub_filter 'Nginx.oRg' '$host/nginx';
sub_filter 'zhaojiedi' 'panda';
#sub_filter_once on;
sub_filter_once off;
#sub_filter_last_modified off;
sub_filter_last_modified on;
}
}
测试效果图如下

可以看到对响应的content进行了替换工作。
在相应的前后添加内容
这个ngx_http_addition_filter_module模块是给响应内容添加特定的内容的, 默认是未编译到nginx的。
官方文档: https://nginx.org/en/docs/http/ngx_http_addition_module.html
主要参数含义:
add_before_body: 之前添加的
add_after_body: 之后添加的。
addition_types: 哪些类型才添加内容。
server {
listen 8084;
server_name n-addition.linuxpanda.tech;
location / {
add_before_body /before_action;
add_after_body /after_action;
addition_types *;
}
location /before_action {
return 200 'new content before\n';
}
location /after_action {
return 200 'new content after\n';
}
}
验证效果
[root@zhaojiedi-elk-2 nginx]# curl http://n-addition.linuxpanda.tech:8084/
new content before
......
......
Nginx.oRg Nginx.oRg zhaojiedi
new content after
变量的惰性求值
变量使用的时候才求值,变量的值可能随时都变化,其值为当时使用的那一刻值。
http框架使用的常用变量
http请求相关的变量
arg_参数名: url中某个具体的参数值
query_string: args变量完全相同
args: 全部url参数
is_args: 如果url中有参数则返回,如果无就是空。
content_length: 请求中的Content_Length头部的值
content_type: 标识请求包体类型的content_Type头部的值。
uri: 请求的uri 不包括后面的参数的。
document_uri: 通uri
request_uri: 包含uri及其后面的参数。
scheme: 协议名字
request_method: 请求方法
request_length: 请求内容的大小,包括请求行,头部,包体。
remote_user: base auth 传递的用户名。
request_body: 请求包体,使用代理才生效。
request: 含有方法,请求uri 协议信息, 请求的第一行。
host: 请求行提取,如果有host header指定,那就替换, 如果都没有,使用匹配的server_name替换。
http_host: host header
http_user_agent: agent header
http_referer: referer header
http_via: via header
http_x_forwarded_for: x_forwared_for header
http_cookie: cookie header
tcp连接相关的变量
binary_remote_addr: 客户端地址
connection: 递增的连接序号
connection_requests: 当前连接上执行过的请求数。
remote_addr: 客户端地址
remote_port: 客户端端口
proxy_protocal_addr: 返回proxy_protocol协议中的地址。
proxy_protocol_port: 返回proxy_protocol协议中的端口。
server_addr: 服务器端地址
server_port: 服务器端端口
TCP_INFO: tcp 内核参数
server_protocol: 服务器端协议。
nginx处理请求过程中产生的变量
request_time : 请求处理到现在的耗时
server_name: 匹配的server_name
https: 是否开启https
request_compltion: 请求是否处理完毕。
request_id: 请求id
request_filename: 待访问的文件完整路径
document_root: 由root alias 规则生成的访问root
realpath_root: document_root路径(如果是软连的)换成真实路径。
limit_rate: 返回客户端的响应速度上限。 set设置即可。
这里演示下limit_rate 的效果。
配置如下
server {
listen 8084;
server_name n-limit-rate.linuxpanda.tech;
root html/;
location /{
limit_rate 50;
}
}
测试如下
time curl http://n-limit-rate.linuxpanda.tech:8084/ -L
time curl http://n-limit-rate.linuxpanda.tech:8084/ -L
real 0m27.087s
user 0m0.002s
sys 0m0.008s
看到启用了limit_rate后, 速度明显受限了。
发送http响应时相关的变量
body_bytes_send: 响应body包体的长度
bytes_send: 全部http响应的长度
status: http响应的返回码
sent_trailer_名字: 把响应结尾内容里值返回。
nginx系统变量
time_local: 本地时间
time_iso8601: iso8601标准时间。
nginx_version: 版本
pid: work pid
pipe: 如果使用管道返回p
hostname: 服务器的主机名字。
referer模块
referer模块记录访问的url的来源url地址的, 可以通过这个模块来拒绝非正常的网络访问我们站点的资源。
相关参数
valid_referers: 控制那些是有效的refer
referer_hash_bucket_size: referhash大小
refer_hash_max_size: 最大hash个数。
valid_referers 几个参数说明
none: 允许缺失referer头部的请求访问。没有key的
block: 允许referer头部没有对应值的请求访问。没有value的。
server_name: 如果refer和server中的本机域名某个匹配则允许请求访问。
正则: 如果满足正则表示匹配
字符串: 如果包含特定字符串满足。
如果有效, 会生成一个变量 invalid_referer变量=1 ,否则=0。
配置如下
server {
listen 8084;
server_name n-referer.linuxpanda.tech;
location / {
alias html/ ;
valid_referers none blocked server_names
*.linuxpanda.pub www.linuxpanda.cn/nginx/
~\.google\.;
if ($invalid_referer) {
return 403;
}
return 200 'valid\n';
}
}
测试效果
[root@zhaojiedi-elk-2 conf]# curl http://n-referer.linuxpanda.tech:8084/
valid
[root@zhaojiedi-elk-2 conf]# curl http://n-referer.linuxpanda.tech:8084/ -H "Referer: "
valid
[root@zhaojiedi-elk-2 conf]# curl http://n-referer.linuxpanda.tech:8084/ -H "Referer: http://abc.com" -I
HTTP/1.1 403 Forbidden
Server: openresty/1.19.9.1 (no pool)
Date: Tue, 14 Dec 2021 13:56:26 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
[root@zhaojiedi-elk-2 conf]# curl http://n-referer.linuxpanda.tech:8084/ -H "Referer: http://www.google.com" -I
HTTP/1.1 200 OK
Server: openresty/1.19.9.1 (no pool)
Date: Tue, 14 Dec 2021 13:56:52 GMT
Content-Type: application/octet-stream
Content-Length: 6
Connection: keep-alive
secure_link模块
这个模块可以通过某服务器生成加密的安全连接url返回给客户端, 客户端使用安全的url, nginx通过secure_link变量判断是否验证通过。
几个变量说明
secure_link: 指定请求中的md5,请求中的过期时间。
secure_link_md5: 计算md5使用那些顺序组合
secure_link_secret: 秘钥单词。
校验结果说明secure_link
值为空的: 验证不通过
值为0: url过期
值为1: 验证通过
map指令
map的能力更像其他语言的switch功能, 通过case 1 case 2 命中不同的case 设置不同的变量, 方便后续的模块使用变量的。
map $http_host $name {
hostnames;
default 0;
~map\.tao\w+\.org.cn 1;
\*.linuxpanda.org.cn 2;
map.linuxpanda.tech 3;
map.linuxpanda.* 4 ;
}
和其他的语言的switch case不一样, 一个一个按照顺序去匹配, 这个匹配顺序是这样的。
字符串严格匹配
使用hostnames可以对域名前缀*泛域名匹配。
~和~* 正则表达式匹配
都不的话, 使用default指令的配置。
split_clients模块
基于已有的变量创建新的变量,为其他ab测试提供更多的可能性。
split_clients "${http_testcli}" $variant {
0.51% .one;
20% .two;
50% .three;
* "",
}
geo模块
根据ip地址创建新的变量。 格式geo $adress $variable {}
匹配优先最长匹配
通过ip地址或者子网掩码的方式,如果ip在范围内,使用其后的值。
default是没有命中的时候,兜底的默认值。
include: 优化可读性
delete 删除指定的网络。
geoip模块基于maxmind数据库获取
官方参考: https://nginx.org/en/docs/stream/ngx_stream_geoip_module.html
需要安装c开发库, 编译启用geoip 然后配置nginx 。 详细操作如下
# 下载数据库dat文件
#下周geoip组件
# 编译支持
# nginx配置支持
geo_city主要变量说明
geoip_country_code: 国家编码2字母
geoip_country_code3: 国安编码3字母
geoip_country_name: 国家名字
geo_city提供的变量如下
geoip_latitude: 维度
geoip_longitude: 经度
geoip_city_continent_code: 属于全球哪个大洲
geoip_region 州或者省编码
geoip_region_name: 名称,比如zhejiang
geoip_city: 城市名字
geoip_postal_code: 邮编号
对客户端keepalive行为控制的指令
多个http请求通过复用tcp连接实现以下功能。
减少握手次数
通过减少并发连接数减少服务器的资源消耗。
降低tcp拥堵控制影响。
常见的header说明
connection: close: 表示不使用keepalive
connection: keepalive: 启用keepalive.
keep-alive: timeout=n: 表示keep alive保留的时间是多少秒。
主要指令说明
keepalive_disable: 哪个浏览器禁用,默认是msie6 .
keepalive_request : 同一个连接做多使用的请求数量。
keepalive_timeout: 超时时间。
负载均衡
nginx扩展方式
基于url对功能进行分发
基于rr算法进行水平扩展
基于ip地址映射到特定ip或者集群
支持的反向代理协议
udp
tcp
memcached
scgi
uwsgi
grpc
http
websocket
负载均衡基础指令
指定上游服务地址, 通过upstream指令指定, 内部通过server指令指定server。 server指定的地址, 可以是域名、ip、或者socket地址。不加端口默认是80端口。
官方文档: https://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream
server片段重要参数说明
weight: 权重,默认是1
max_conns: 最大活动连接数量,默认是0,也就是不限制。
max_fails: 最大失败次数,也就是在fail_timeout这个时间内,如果出现max_fails次数的话,对应的server就不会再次被选择。
fail_timeout: 默认是10s
backup: 备用, 如果所有的主都不可用才使用这个的。
down: 表示这个机器永远不要调度。
resolve: 解析域名到地址的。必须使用共享内存的。1.5.12之后才支持动态感知域名变化的。
对上游服务使用长连接
降低ningx与上游服务器的建立关闭连接的消耗,提升吞吐量的同事降低延迟。
http1.1才支持, 需要加入如下设置。
proxy_http_version 1.1;
proxy_set_header Connection "";
主要参数说明
keepalive : 指定次数。
keepalive_requests: 一个连接最多使用的req
keepalive_timeout: 一个连接最多使用的时间
轮训配置样例
这里我先使用一个nginx启动了server, 测试如下
[root@zhaojiedi-elk-2 nginx]# curl 127.0.0.1:8001
8001 s1
[root@zhaojiedi-elk-2 nginx]# curl 127.0.0.1:8002
8002 s2
配置样例
upstream rrups {
server 127.0.0.1:8001 weight=2 max_conns=2 max_fails=2 fail_timeout=5;
server 127.0.0.1:8002;
keepalive 20;
}
server {
listen 8084;
server_name n-rrups.linuxpanda.tech;
error_log myerror.log info;
location /{
proxy_pass http://rrups;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
测试结果
[root@zhaojiedi-elk-2 conf]# curl http://n-rrups.linuxpanda.tech
8001 s1
[root@zhaojiedi-elk-2 conf]# curl http://n-rrups.linuxpanda.tech
8002 s2
[root@zhaojiedi-elk-2 conf]# curl http://n-rrups.linuxpanda.tech
8001 s1
[root@zhaojiedi-elk-2 conf]# curl http://n-rrups.linuxpanda.tech
8001 s1
[root@zhaojiedi-elk-2 conf]# curl http://n-rrups.linuxpanda.tech
8002 s2
启用了keepalive 我们看下tcpdump 抓包的结果
[root@zhaojiedi-elk-2 ~]# tcpdump -i lo port 8001 -n
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
16:20:09.756199 IP 127.0.0.1.42492 > 127.0.0.1.vcom-tunnel: Flags [S], seq 1693123386, win 43690, options [mss 65495,sackOK,TS val 299254666 ecr 0,nop,wscale 7], length 0
le 7], length 0
16:20:09.756220 IP 127.0.0.1.42492 > 127.0.0.1.vcom-tunnel: Flags [.], ack 1, win 342, options [nop,nop,TS val 299254666 ecr 299254666], length 0
16:20:09.756262 IP 127.0.0.1.42492 > 127.0.0.1.vcom-tunnel: Flags [P.], seq 1:70, ack 1, win 342, options [nop,nop,TS val 299254666 ecr 299254666], length 69
16:20:09.756266 IP 127.0.0.1.vcom-tunnel > 127.0.0.1.42492: Flags [.], ack 70, win 342, options [nop,nop,TS val 299254666 ecr 299254666], length 0
16:20:09.756357 IP 127.0.0.1.vcom-tunnel > 127.0.0.1.42492: Flags [P.], seq 1:171, ack 70, win 342, options [nop,nop,TS val 299254666 ecr 299254666], length 170
16:20:09.756361 IP 127.0.0.1.42492 > 127.0.0.1.vcom-tunnel: Flags [.], ack 171, win 350, options [nop,nop,TS val 299254666 ecr 299254666], length 0
-----下面是第二次的。
16:20:35.599901 IP 127.0.0.1.42492 > 127.0.0.1.vcom-tunnel: Flags [P.], seq 70:139, ack 171, win 350, options [nop,nop,TS val 299280510 ecr 299254666], length 69
16:20:35.600018 IP 127.0.0.1.vcom-tunnel > 127.0.0.1.42492: Flags [P.], seq 171:341, ack 139, win 342, options [nop,nop,TS val 299280510 ecr 299280510], length 170
16:20:35.600028 IP 127.0.0.1.42492 > 127.0.0.1.vcom-tunnel: Flags [.], ack 341, win 359, options [nop,nop,TS val 299280510 ecr 299280510], length 0
可以看到第一次是三次握手了, 但是是没有F的falgs的,也就是关闭连接的, 接下里curl的直接传输了。
反向代理的hash算法
对于ipv4地址使用前面3个字节作为关键字,对ipv6使用完整的地址。通过ip_hash 进行配置。
当然也可以通过hash key 方式配置非ip方式的。
官方文档: https://nginx.org/en/docs/http/ngx_http_upstream_module.html#ip_hash
配置ip_hash
upstream rrups {
#ip_hash;
hash user_$arg_username;
server 127.0.0.1:8001 weight=2 max_conns=200 max_fails=2 fail_timeout=5;
server 127.0.0.1:8002;
}
server {
listen 8084;
server_name n-hash.linuxpanda.tech;
error_log myerror.log info;
location /{
set_real_ip_from 10.157.0.0/16;
set_real_ip_from 10.21.0.0/16;
real_ip_recursive on;
real_ip_header X-Forwarded-For;
proxy_pass http://rrups;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
验证1 ip_hash
[root@zhaojiedi-elk-2 nginx]# curl http://n-hash.linuxpanda.tech:8084 -H "X-Forwarded-For: 1.1.1.1"
8001 s1
[root@zhaojiedi-elk-2 nginx]# curl http://n-hash.linuxpanda.tech:8084 -H "X-Forwarded-For: 1.1.1.1"
8001 s1
[root@zhaojiedi-elk-2 nginx]# curl http://n-hash.linuxpanda.tech:8084 -H "X-Forwarded-For: 1.1.1.1"
8001 s1
[root@zhaojiedi-elk-2 nginx]# curl http://n-hash.linuxpanda.tech:8084 -H "X-Forwarded-For: 1.1.1.1"
8001 s1
[root@zhaojiedi-elk-2 nginx]# curl http://n-hash.linuxpanda.tech:8084 -H "X-Forwarded-For: 1.1.1.1"
8001 s1
验证1 hash key
[zhaojiedi_dxm@instance-pu4usb9a ~]$ curl http://n-hash.linuxpanda.tech:8084?username=abc
8001 s1
[zhaojiedi_dxm@instance-pu4usb9a ~]$ curl http://n-hash.linuxpanda.tech:8084?username=abc
8001 s1
[zhaojiedi_dxm@instance-pu4usb9a ~]$ curl http://n-hash.linuxpanda.tech:8084?username=abc
8001 s1
[zhaojiedi_dxm@instance-pu4usb9a ~]$ curl http://n-hash.linuxpanda.tech:8084?username=deaaa
8002 s2
[zhaojiedi_dxm@instance-pu4usb9a ~]$ curl http://n-hash.linuxpanda.tech:8084?username=deaaa
8002 s2
[zhaojiedi_dxm@instance-pu4usb9a ~]$ curl http://n-hash.linuxpanda.tech:8084?username=deaaa
8002 s2
一致性hash算法
通过hash key consistent 即可。
连接做少的上游服务器
upsteam共享内存
使用共享内存可以将upstream定义的策略数据,状态数据放到共享内存中,对所有worker进程生效。
upsteam模块提供的变量
upstream_addr: 地址
upstream_connect_time: 建立了解消耗时间
upstream_header_time: 接收上游的头部需要的时间
upstream_response_time: 完整耗时
upstream_bytes_received: 响应长度
upstream_response_length: 包体长度
upstream_status: 上游的状态吗, 如果没有连接上,502
upstream_cookie_名称: 上游返回的set_cookie取出的值。
http反向代理的处理流程

proxy模块的基本使用
这个模块是支持http和https协议2种类型的代理的, proxy 后面的url必须以http或者https开头, 接下来是域名、ip 、socket或者upstream名字。前面2个是可以添加端口的。
如果url参数带不带uri差异是比较大的。
不携带uri: 直接转发给上游
携带uri: 将location匹配的部分进行替换。
提前准备一个后端
server {
listen 8001 ;
location / {
return 200 '8001 s1\r\n uri=$uri \r\n';
}
}
upstream r1 {
server 127.0.0.1:8001;
}
server {
listen 8084;
server_name n-proxy.linuxpanda.tech;
error_log myerror.log info;
location /a/b/c {
#proxy_pass http://r1;
proxy_pass http://r1/panda;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
验证一下
# 不带uri方式的。
[root@zhaojiedi-elk-2 conf]# curl http://n-proxy.linuxpanda.tech:8084/a/b/c/d/e/f
8001 s1
uri=/a/b/c/d/e/f
[root@zhaojiedi-elk-2 conf]# curl http://n-proxy.linuxpanda.tech:8084/a/b/c/def
8001 s1
uri=/a/b/c/def
# 带uri方式的。
[root@zhaojiedi-elk-2 conf]# curl http://n-proxy.linuxpanda.tech:8084/a/b/c/def
8001 s1
uri=/panda/def
[root@zhaojiedi-elk-2 conf]# curl http://n-proxy.linuxpanda.tech:8084/a/b/c/d/e/f
8001 s1
uri=/panda/d/e/f
修改向后端的请求行
proxy_method: 修改请求方法
proxy_http_version: 修改协议版本。
proxy_set_header field value: 修改请求头部。
proxy_pass_request_header: 用户的header是否发送。
proxy_pass_request_body: body是否发送
proxy_set_body: 自定义body方式。
接收客户端请求的包体
proxy_request_buffering 控制收完在转发还是边收边转发。
client_max_body_size: 仅仅对头部含有Content-Length有效超过最大长度后,返回413错误。
client_body_temp_path: 临时文件存放目录,这个是存储body信息的。
client_body_in_file_only : 请求的包体是否保留的文件中,on必须写的, clean: 处理完毕后删除, off: 非常小,buffer_size 如果够的话,就不写了。
client_body_timeout : 两次读取body的最大时延,返回418错误。
向上游建立连接
proxy_connect_timeout 建立连接,如果超时,502
proxy_next_upstream : 特定错误后,可以换一个机器进行调度响应。
proxy_socket_keepalive: 保持连接。
keepalive: 控制数量
keepalive_requests: 控制连接复用次数
proxy_bind: 修改源地址。如果非本机地址,需要transparent的参数辅助的。
proxy_ignore_client_abort: 客户端和nginx如果取消了, nginx和后端的连接是否断开。
proxy_send_timeout : 发送请求的超时时间。
接收上游的响应头部
proxy_buffer_size 是用来存放对应响应头部的,如果比较大,errlog会出现upstream send too big header。
proxy_buffering : 接收完整的响应包体,这个基本同proxy_request_buffering.
接收上游的包体
proxy_buffers 这个用于存放上游的http包体大小,8 8k参数是如果8k足够就只分配1个8k的, 不够继续分配,最多8个8k。
proxy_buffering: 禁用的话,会收到上游响应后立刻同步给客户端响应。如果开启,放到内存,内存放不下,写临时文件。
proxy_max_temp_file_size: 写入磁盘的文件的最大值。
proxy_temp_file_write_size: 每次写入字节限制。
proxy_temp_path: 指定临时文件目录和存储级别。
proxy_busy_buffers_size: 及时转发包体
接受上游网络速度相关指令
proxy_read_timeout: 2次读取超时时间。
proxy_limit_rate: 读取上游的速率。
包体持久化
proxy_store_access: 定义临时文件持久化, 权限设置。
proxy_store: 可以使用变量控制存放位置。
加工响应头部
proxy_ignore_header: 禁用特定字段。
proxy_hide_header: 不转发某些头部。
porxy_pass_header: 允许哪些头部发送。
proxy_cookie_domain: 修改域名
proxy_cookie_path: 修改path
proxy_redirect: 重定向url
上游返回错误的处理办法
proxy_next_upstream: 在没有想客户端发送任何内容的时候,就错误的才重新选择新的机器。
proxy_next_upstream_timeout: 重试的时间
proxy_next_upstream_tries: 重试的次数。
proxy_intercept_erros: 是否拦截上游失败响应,如果上游响应>=300的视乎,启用这个选项的话, error_page就会生效了。
准备工作
[root@zhaojiedi-elk-2 nginx]# cat /root/nginx/conf/sites/s1.conf
server {
listen 8001 ;
location / {
return 200 '8001 s1\r\n uri=$uri \r\n';
}
}
[root@zhaojiedi-elk-2 nginx]# cat /root/nginx/conf/sites/s2.conf
server {
listen 8002;
location / {
return 200 '8002 s2 \r\n';
}
}
[root@zhaojiedi-elk-2 nginx]# cat /root/nginx/conf/sites/s3.conf
server {
listen 8003;
location / {
return 502 ;
}
}
openrestry配置如下
upstream ups {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
log_format ups 'porxy_host="$proxy_host" proxy_port="$proxy_port" upstream_addr="$upstream_addr" upstream_status="$upstream_status"';
server {
listen 8084;
server_name n-proxyc.linuxpanda.tech;
error_log myerror.log info;
root html;
error_page 502 500 /a.txt;
access_log logs/access.log ups ;
location / {
proxy_pass http://ups;
proxy_next_upstream error timeout http_502;
}
}
验证效果
[root@zhaojiedi-elk-2 nginx]# curl http://n-proxyc.linuxpanda.tech:8084/
8001 s1
uri=/
[root@zhaojiedi-elk-2 nginx]# curl http://n-proxyc.linuxpanda.tech:8084/
8002 s2
# 803是返回502的, 但是我们配置了next的,会调度到别的实例然后拿到结果。
[root@zhaojiedi-elk-2 nginx]# curl http://n-proxyc.linuxpanda.tech:8084/
8001 s1
uri=/
[root@zhaojiedi-elk-2 nginx]# tail -n 10 logs/access.log
porxy_host="ups" proxy_port="80" upstream_addr="127.0.0.1:8001" upstream_status="200"
porxy_host="ups" proxy_port="80" upstream_addr="127.0.0.1:8002" upstream_status="200"
porxy_host="ups" proxy_port="80" upstream_addr="127.0.0.1:8003, 127.0.0.1:8001" upstream_status="502, 200"
ssl使用场景和双向认证

官方文档: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#directives
几个主要连接相关变量
ssl_client_serial: 连接上的客户端序列号。
ssl_early_data: 在tls3使用early data 且握手为完成返回1 ,否则返回空。
ssl_client_verify: 验证失败返回failed:原因,成功返回Success.
ssl_session_reused: 如果session复用,返回r,否则为. 。
准备相关证书
# 这里不多弄具体证书创建问题, 需要几个文件,
ca的pem文件
n-ssl1.linuxpanda.tech.key n-ssl1.linuxpanda.tech.crt
n-ssl2.linuxpanda.tech.key n-ssl2.linuxpanda.tech.crt
# 具体操作可以参考: https://www.linuxpanda.tech/en/latest/%E6%9D%82%E9%A1%B9/CA%E7%9A%84%E6%90%AD%E5%BB%BA.html
# 或者: https://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_linux_011_ca.html
nginx配置
server {
listen 8011 ssl;
server_name n-ssl1.linuxpanda.tech;
ssl_certificate ssl/n-ssl1.linuxpanda.tech.crt;
ssl_certificate_key ssl/n-ssl1.linuxpanda.tech.key;
ssl_verify_client on;
ssl_client_certificate ssl/cacert.pem;
location / {
return 200 'ssl_early_data=$ssl_early_data ; ssl_client_verify=$ssl_client_verify; \r\n';
}
}
openrestry配置
server {
listen 8011 ssl;
server_name n-ssl1.linuxpanda.tech;
ssl_certificate ssl/n-ssl1.linuxpanda.tech.crt;
ssl_certificate_key ssl/n-ssl1.linuxpanda.tech.key;
ssl_verify_client on;
ssl_client_certificate ssl/cacert.pem;
location / {
return 200 'ssl_early_data=$ssl_early_data ; ssl_client_verify=$ssl_client_verify; \r\n';
}
}
验证测试
[root@zhaojiedi-elk-2 sites]# curl http://n-ssl2.linuxpanda.tech:8012/
ssl_early_data= ; ssl_client_verify=SUCCESS;
浏览器缓存与nginx缓存
- 浏览器缓存
优点: 没有网络消耗,速度最快,即使有网络消耗也比较小。 缺点: 仅仅提升一个用户体验。
- nginx缓存:
优点: 提升所有用户体验,有效降低后端负载,通过304减少与上游的流量消耗。 缺点: 用户仍然保持网络消耗
建议同时使用浏览器缓存和nginx缓存。

etag
根据文件的修改时间和大小生成。
if-none-match
它的原理是这样的,当浏览器请求服务器的某项资源(A)时, 服务器根据A算出一个哈希值(3f80f-1b6-3e1cb03b)并通过 ETag 返回给浏览器, 浏览器把”3f80f-1b6-3e1cb03b” 和 A 同时缓存在本地,当下次再次向服务器请求A时,会通过类似 If-None-Match: “3f80f-1b6-3e1cb03b” 的请求头把ETag发送给服务器,服务器再次计算A的哈希值并和浏览器返回的值做比较,如果发现A发生了变化就把A返回给浏览器(200),如果发现A没有变化就给浏览器返回一个304未修改。 这样通过控制浏览器端的缓存,可以节省服务器的带宽,因为服务器不需要每次都把全量数据返回给客户端。
具体参考: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/If-None-Match
if-modified-since头部
如果没有超过日期,就返回304,超过就返回200,具体内容就返回。
Warning
如何和if-None-Match一同使用的时候,这个since是不生效的,除非服务器不支持Match的。
nginx判定缓存是否过期
expire指令:
max: 最大的值。cache-control基本10年。
off,不添加或者修改过期和cache-control字段。
epoch 不设置缓存
time 设置具体时间, @18h30m
准备几个文件
[root@zhaojiedi-elk-2 html]# for i in $(seq 1 7) ; do mkdir dir$i; echo "this is dir$i" >> dir$i/index.html; done
[root@zhaojiedi-elk-2 html]# tree
.
├── 50x.html
├── dir1
│ └── index.html
├── dir2
│ └── index.html
├── dir3
│ └── index.html
├── dir4
│ └── index.html
├── dir5
│ └── index.html
├── dir6
│ └── index.html
├── dir7
│ └── index.html
└── index.html
nginx配置样例
server {
listen 8084;
server_name n-cache.linuxpanda.tech;
error_log myerror.log info;
root html;
location /dir1 {
expires max ;
}
location /dir2 {
expires @15h30m;
}
location /dir3 {
expires modified +24h;
}
location /dir4 {
expires 0;
}
location /dir5 {
expires -1;
}
location /dir6 {
expires epoch;
}
}
这里对集中情况进行验证
# 案例1,max, 可以看到结果max-age是10年的
[root@zhaojiedi-elk-2 conf]# curl http://n-cache.linuxpanda.tech:8084/dir1/index.html -IL
HTTP/1.1 200 OK
Server: openresty/1.19.9.1 (no pool)
Date: Tue, 11 Jan 2022 03:49:14 GMT
Content-Type: text/html
Content-Length: 13
Last-Modified: Tue, 11 Jan 2022 03:45:37 GMT
Connection: keep-alive
ETag: "61dcfd61-d"
Expires: Thu, 31 Dec 2037 23:55:55 GMT
Cache-Control: max-age=315360000
Accept-Ranges: bytes
#案例2 我当前是11:50的,我设置15h30m 具体这个时间大概220分钟=(3小时 40分钟)
[root@zhaojiedi-elk-2 conf]# curl http://n-cache.linuxpanda.tech:8084/dir2/index.html -IL
HTTP/1.1 200 OK
Server: openresty/1.19.9.1 (no pool)
Date: Tue, 11 Jan 2022 03:50:00 GMT
Content-Type: text/html
Content-Length: 13
Last-Modified: Tue, 11 Jan 2022 03:45:37 GMT
Connection: keep-alive
ETag: "61dcfd61-d"
Expires: Tue, 11 Jan 2022 07:30:00 GMT
Cache-Control: max-age=13200
Accept-Ranges: bytes
#案例3 根据modify修改时间,加一个时间。
[root@zhaojiedi-elk-2 conf]# curl http://n-cache.linuxpanda.tech:8084/dir3/index.html -IL
HTTP/1.1 200 OK
Server: openresty/1.19.9.1 (no pool)
Date: Tue, 11 Jan 2022 03:52:56 GMT
Content-Type: text/html
Content-Length: 13
Last-Modified: Tue, 11 Jan 2022 03:45:37 GMT
Connection: keep-alive
ETag: "61dcfd61-d"
Expires: Wed, 12 Jan 2022 03:45:37 GMT
Cache-Control: max-age=85961
Accept-Ranges: bytes
[root@zhaojiedi-elk-2 conf]# ll ../html/dir3/index.html
-rw-r--r-- 1 root root 13 Jan 11 11:45 ../html/dir3/index.html
# 案例4 max-age=0
[root@zhaojiedi-elk-2 conf]# curl http://n-cache.linuxpanda.tech:8084/dir4/index.html -IL
HTTP/1.1 200 OK
Server: openresty/1.19.9.1 (no pool)
Date: Tue, 11 Jan 2022 03:53:43 GMT
Content-Type: text/html
Content-Length: 13
Last-Modified: Tue, 11 Jan 2022 03:45:37 GMT
Connection: keep-alive
ETag: "61dcfd61-d"
Expires: Tue, 11 Jan 2022 03:53:43 GMT
Cache-Control: max-age=0
Accept-Ranges: bytes
# 案例5 设置负数表示no-cache
[root@zhaojiedi-elk-2 conf]# curl http://n-cache.linuxpanda.tech:8084/dir5/index.html -IL
HTTP/1.1 200 OK
Server: openresty/1.19.9.1 (no pool)
Date: Tue, 11 Jan 2022 03:54:39 GMT
Content-Type: text/html
Content-Length: 13
Last-Modified: Tue, 11 Jan 2022 03:45:37 GMT
Connection: keep-alive
ETag: "61dcfd61-d"
Expires: Tue, 11 Jan 2022 03:54:38 GMT
Cache-Control: no-cache
Accept-Ranges: bytes
# 案例6
[root@zhaojiedi-elk-2 conf]# curl http://n-cache.linuxpanda.tech:8084/dir6/index.html -IL
HTTP/1.1 200 OK
Server: openresty/1.19.9.1 (no pool)
Date: Tue, 11 Jan 2022 03:55:34 GMT
Content-Type: text/html
Content-Length: 13
Last-Modified: Tue, 11 Jan 2022 03:45:37 GMT
Connection: keep-alive
ETag: "61dcfd61-d"
Expires: Thu, 01 Jan 1970 00:00:01 GMT
Cache-Control: no-cache
Accept-Ranges: bytes
not_modified
客户端拥有缓存,但是不确定缓存是否过期,请求闯入if-none-match或者if-modified-since 头部, 该模块通过将改值与响应中的last-modified值进行比较, 决定是否返回200还是仅仅302 notmodified头部。

nginx缓存:定义存放的载体
proxy_cache zone: 定义使用哪个zone
proxy_cache_path: 定义zone
proxy_cache_path指令详细参数
path: 定义目录
level: 目录级别
use_temp_path: 定义临时目录
keys_zone: name定义共享内存名字,size是共享内存大小 1MB大约可以存放8k key
inactive: 在特定时间没有被访问就会被淘汰掉, 默认10min
max_size: 设置最大的缓存文件大小,超出后按照lru淘汰。
manager_files: 淘汰的最大文件数量 默认100
manager_sleep: 淘汰一次后的休眠时间
manager_threshold: 执行一次的最大耗时,默认50ms
loader_files: 载入磁盘文件到共享内存的批处理文件数量,默认100
loader_sleep: 执行一次缓存文件到共享内存后,进程的休眠时间。
loader_threshold: 每次载入文件的最大耗时,默认50ms
定义缓存的key
proxy_cache_key : 可以使用变量,定义缓存的key
缓存什么请求
proxy_cache_valid:
不缓存什么内存
proxy_no_cache : 参数为真的时候,响应不存入缓存
porxy_cache_bypass: 参数为真,不使用缓存内容。
upstrream_cache_status变量
MISS 未命中
HIT 命中缓存
EXPIRED 缓存已经过期
STALE 命中陈旧缓存
UPDATING 内容陈旧单正在更新
REVALIDATED nginx验证陈旧内容依然有效
BYPASS 响应是从原始服务器获得的。
nginx后端配置
server {
listen 8004;
location / {
# add_header Vary * ;
# add_header X-Accel-Expires 3 ;
alias html/;
}
}
openrestry 配置
proxy_cache_path /root/openresty/nginx/cache levels=2:2 keys_zone=two:10m loader_threshold=300
loader_files=200 max_size=200m inactive=1m;
server {
listen 8084;
server_name n-cachec.linuxpanda.tech;
error_log myerror.log debug;
root html;
location / {
# 这里为了可以在响应中看到是否命中,添加个header看看
proxy_cache two;
proxy_cache_valid 200 1m;
add_header X-Cache-Status $upstream_cache_status;
proxy_cache_key $scheme$uri ;
proxy_pass http://localhost:8004;
}
}
验证结果
curl http://n-cachec.linuxpanda.tech:8084/index.html -IL
HTTP/1.1 200 OK
Server: openresty/1.19.9.1 (no pool)
Date: Tue, 11 Jan 2022 07:43:32 GMT
Content-Type: text/html
Content-Length: 612
Connection: keep-alive
Last-Modified: Mon, 29 Nov 2021 07:50:00 GMT
ETag: "61a48628-264"
X-Cache-Status: MISS
Accept-Ranges: bytes
[root@zhaojiedi-elk-2 conf]# curl http://n-cachec.linuxpanda.tech:8084/index.html -IL
HTTP/1.1 200 OK
Server: openresty/1.19.9.1 (no pool)
Date: Tue, 11 Jan 2022 07:43:35 GMT
Content-Type: text/html
Content-Length: 612
Connection: keep-alive
Last-Modified: Mon, 29 Nov 2021 07:50:00 GMT
ETag: "61a48628-264"
X-Cache-Status: HIT
Accept-Ranges: bytes
[root@zhaojiedi-elk-2 sites]# !tree
tree /root/openresty/nginx/cache/
/root/openresty/nginx/cache/
└── 0a
└── 0d
└── 3fc7ad9511bc116105001aa24d260d0a
2 directories, 1 file
[root@zhaojiedi-elk-2 sites]# cat /root/openresty/nginx/cache/0a/0d/3fc7ad9511bc116105001aa24d260d0a
缓存流程 发起请求部分

缓存流程 接手上游响应

如何减轻上游压力
合并回源请求 proxy_cache_lock on 同一个时间只能有1个请求。 proxy_cache_lock_timeout: 等待第一个多久, proxy_cache_lock_age: 上一个请求的超时时间。
使用久缓存返回 proxy_cache_use_stale updating proxy_cache_backgroupd_update on 。
proxy——cache_revalidate on 在请求上游的时候会带header if-modified_since if-none-match等,没有变化就是304减少传输。
及时清理缓存
官方的开源是不支持的,plus nginx是支持的, 这里有个模块,可以编译进来。 https://github.com/FRiCKLE/ngx_cache_purge
七层反向代理对照表
redis反向代理
将http请求转换为redis协议中的get请求转发到上游memcached服务中。
配置如下
upstream redis1 {
server 127.0.0.1:6379;
}
server {
listen 8084;
server_name n-redis.linuxpanda.tech;
error_log myerror.log info;
root html;
# GET /get?key=some_key
location = /get {
set_unescape_uri $key $arg_key; # this requires ngx_set_misc
redis2_query get $key;
redis2_pass redis1:6379;
}
# GET /set?key=one&val=first%20value
location = /set {
set_unescape_uri $key $arg_key; # this requires ngx_set_misc
set_unescape_uri $val $arg_val; # this requires ngx_set_misc
redis2_query set $key $val;
redis2_pass redis1:6379;
}
}
样例验证
[root@zhaojiedi-elk-2 sites]# curl 'http://n-redis.linuxpanda.tech:8084/set?key=k1&val=v1'
+OK
[root@zhaojiedi-elk-2 sites]# curl 'http://n-redis.linuxpanda.tech:8084/get?key=k1'
$2
v1
nginx实现websocket代理
proxy模块提供 官方参考 https://nginx.org/en/docs/http/websocket.html
核心配置片段
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
配置
server {
listen 8085;
server_name n-websocket.linuxpanda.tech n-ws.linuxpanda.tech;
error_log myerror.log info;
access_log logs/ws.log ;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://121.40.165.18:8800;
}
}
验证

如果配置证书的话, 就是wss协议了。 这个样例仅仅支持ws协议。
使用分片提升效率
处理大文件的时候,每次都请求全部大小是很消耗资源的事情, 通过range方式配合slice方式即可请求特定部分。
准备一个大文件
dd if=/dev/zero of=big.avi bs=1M count=88
配置一个上游服务
就是简单配置的静态集群的。
配置openrestry
proxy_cache_path /root/openresty/nginx/cache levels=2:2 keys_zone=five:10m loader_threshold=300
loader_files=200 max_size=200m inactive=1m;
server {
listen 8084;
server_name n-slice.linuxpanda.tech;
error_log myerror.log debug;
root html;
location / {
# 这里为了可以在响应中看到是否命中,添加个header看看
proxy_cache five;
proxy_cache_valid 200 206 1m;
add_header X-Cache-Status $upstream_cache_status;
proxy_set_header Range $slice_range;
proxy_cache_key $scheme$uri$slice_range ;
proxy_pass http://localhost:8005;
}
}
验证下
[root@zhaojiedi-elk-2 nginx]# curl http://n-slice.linuxpanda.tech:8084/big.avi -r 100-200
[root@zhaojiedi-elk-2 nginx]# tail -n 2 /root/openresty/nginx/logs/access.log
10.157.89.215 - - [12/Jan/2022:10:47:08 +0800] "GET /big.avi HTTP/1.1" 502 173 "-" "curl/7.29.0" "-"request_filename=/root/openresty/nginx/html/big.avi document_root=/root/openresty/nginx/html realpath_root=/root/openresty/nginx/html
10.157.89.215 - - [12/Jan/2022:10:47:55 +0800] "GET /big.avi HTTP/1.1" 206 101 "-" "curl/7.29.0" "-"request_filename=/root/openresty/nginx/html/big.avi document_root=/root/openresty/nginx/html realpath_root=/root/openresty/nginx/html
[root@zhaojiedi-elk-2 nginx]# tail -n 2 /root/nginx/logs/access.log
127.0.0.1 - - [11/Jan/2022:15:47:39 +0800] "GET /index.html HTTP/1.0" 200 612 "-" "curl/7.29.0"
127.0.0.1 - - [12/Jan/2022:10:47:55 +0800] "GET /big.avi HTTP/1.0" 200 92274688 "-" "curl/7.29.0"
缓存优化-文件打开
open_file_cache: 打开文件缓存的个数,超过的个数使用lru算法。
open_file_cache_valid: 文件缓存的有效时间。
open_file_cache_errors: 是否缓存文件查询的错误信息。默认off.
open_file_cache_min_uses: 具体没有看明白文档。
文件缓存都缓存什么内容
文件句柄
文件修改时间
文件大小
文件查询时候的错误信息(比如文件不能存在,或者没有权限)
目录是否存在
配置如下
server {
listen 8084;
server_name n-openfilecache.linuxpanda.tech;
root html;
location / {
open_file_cache max=10 inactive=300s;
open_file_cache_min_uses 1;
open_file_cache_valid 300s;
open_file_cache_errors on;
}
}
验证
# 这里找到对应nginx的work进程,看看这个具体进程的系统调用
[root@zhaojiedi-elk-2 ~]# strace -p 14160
strace: Process 14160 attached
# 默认卡在wait这个地方,等待连接请求
epoll_wait(13,[{EPOLLIN, {u32=44802384, u64=44802384}}], 512, -1) = 1
# 收到一个请求
accept4(11, {sa_family=AF_INET, sin_port=htons(40254), sin_addr=inet_addr("10.157.89.215")}, [112->16], SOCK_CLOEXEC|SOCK_NONBLOCK) = 4
epoll_ctl(13, EPOLL_CTL_ADD, 4, {EPOLLIN|EPOLLRDHUP|EPOLLET, {u32=44803080, u64=44803080}}) = 0
epoll_wait(13, [{EPOLLIN, {u32=44803080, u64=44803080}}], 512, 60000) = 1
# 接受头部
recvfrom(4, "GET / HTTP/1.1\r\nUser-Agent: curl"..., 1024, 0, NULL, NULL) = 100
# 写响应
writev(4, [{iov_base="HTTP/1.1 200 OK\r\nServer: openres"..., iov_len=255}], 1) = 255
# 发送文件body
sendfile(4, 5, [0] => [1129], 1129) = 1129
lstat("/root", {st_mode=S_IFDIR|0550, st_size=4096, ...}) = 0
lstat("/root/openresty", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/root/openresty/nginx", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/root/openresty/nginx/html", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
write(3, "10.157.89.215 - - [12/Jan/2022:1"..., 232) = 232
setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0
epoll_wait(13, [{EPOLLIN|EPOLLRDHUP, {u32=44803080, u64=44803080}}], 512, 65000) = 1
recvfrom(4, "", 1024, 0, NULL, NULL) = 0
close(4) = 0
epoll_wait(13,
http2主要特性
- 传输数据量大幅减少
二进制数据传输 标头压缩
- 多路复用
消息优先级
- 服务器消息推送
并行推送
http2核心概念
连接: 1个tcp连接
流:一个双向流
消息: 对应http的请求或者响应
数据帧: 最小单位,以二进制压缩格存放http1中的内容。
协议分层和多路复用

传输是无序的,接收的时候组装。
优先级1-255
http2推送文件
http2_push_preload 跟进header指定, 上游服务器可以生成header.
http2_push 推送哪个url
http2_push_max_number: 推送最大数
http2_recv_timeout: 如果超过这个时间没有收到请求就关闭
http2_idle_timeout: 超过这个时间,就关闭连接
http2_max_concurrent_pusher: 最大推送个数
http2_max-concurrent_streams: 最大并发流个数
http2_max_field_size: header最大大小
http2_max_requests: 一个连接最大请求个数
nginx反向代理grpc
stream模块处理的7个阶段
POST_ACCEPT
PREACCESS
ACCESSS
SSL
PREFEAD
CONTENT
LOG
nginx代理4层样例
proxy_protocol 协议
- v1协议:
proxy tcp4 ip1 ip2 port1 port2 rn
- v2协议:
签名+ version_command + 地址族+ 长度
udp反向代理
nginx优化
优化方法论
软件方面提升使用率
硬件提升
使用dns
如何有效使用CPU
能够使用全部的CPU资源
work进程数量大于等于cpu number .
master worker 多进程架构
nginx进程不做无用功浪费CPU
不应该争抢cpu,worker进程数量大于等于cpu合数。
不应该调用第三方模块让出cpu
nginx不被其他进程抢用
提升优先级
减少非nginx进程存在
设置worker进程的数量
worker_processes: 设置数量,auto的话,自动和cpu数量保持一致。
为何cpu可以同时运行多个进程
时间片分割,进程被分配时间片,微观上是串行的,宏观是并行的。
阻塞(读文件,网络)等会导致主动让出。
确保处于运行态
减少进程切换
主动切换: 阻塞api
被动切换: 时间片耗尽
如何查看上下文切换
[zhaojiedi_dxm@instance-zj2zr2l1-15 conf]$ vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
4 0 0 824280 133348 123614624 0 0 8 115 0 0 8 4 87 0 0
[root@instance-dduk3gev-19 ~]# dstat
You did not select any stats, using -cdngy by default.
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read writ| recv send| in out | int csw
8 4 87 0 0 0| 264k 3671k| 0 0 | 0 0 |3168 110k
# cswch/s 主动的,nv 被动的
[root@instance-dduk3gev-19 ~]# pidstat -w |head -n 10
Linux 3.10.0-957.21.3.el7.x86_64 (instance-dduk3gev-19.bcc-bjdd) 01/21/2022 _x86_64_ (32 CPU)
07:18:27 PM UID PID cswch/s nvcswch/s Command
07:18:27 PM 0 1 1.32 0.08 systemd
07:18:27 PM 0 2 0.32 0.01 kthreadd
07:18:27 PM 0 3 4.66 0.00 ksoftirqd/0
07:18:27 PM 0 5 0.00 0.00 kworker/0:0H
07:18:27 PM 0 7 0.22 0.00 migration/0
07:18:27 PM 0 8 0.00 0.00 rcu_bh
什么决定cpu时间片的大小
nice优先级-20到19的。
o1调度算法优先级影响还是挺大的, 优先级对应的时间片可以在5ms-800ms的。
通过worker_priority 设置优先级。 也就是nice值。
多核间如何负载均衡
多队列网卡对多核cpu的优化
rss: 硬中断负载均衡
rps: 软中断负载均衡
rfs:
提升cpu缓存命中率
worker_cpu_affinity: 设置cpu粘性。
查看cpu缓存
[root@instance-dduk3gev-19 ~]# cat /sys/devices/system/cpu/cpu0/cache/index{0,1,2,3}/size
32K
32K
1024K
11264K
控制tcp握手参数

syn_sent 状态
net.ipv4.tcp_syn_retries=6 主动发送syn的重试次数
net.ipv4.ip_local_range = 32768 60999 建立连接时候的本地端口可用范围。
proxy_connect_time: 主动建立连接时间
syn_revd 状态
net.ip4.tcp_max_syn_backlog: syn_revd状态的最大个数
net.ipv4.tcp_synack_retries: 发送syn/ack的重试次数
服务器怎么处理三次握手

如何控制syn攻击
攻击者为准不同的ip地址的syn报文,快速占满backlog队列。
net.core.netdev_max_backlog: 接受自网卡,但是没有被内核协议栈处理的报文长度。
net.ipv4.tcp_max_syn_backlog: sync_rcvd状态的连接个数。
net.ipv4.tcp_abort_on_overflow: 超出处理能力对新来的syn直接回包RST,丢弃连接。
启用tcp_syncookies: 当syn队列满了,就不进入syn队列,计算cookie直接进入backlog队列。
建立tcp连接的优化
句柄的上限
操作系统级别
fs.file-max: 操作系统最大的句柄数
fs.file-nr: 当前分配和正使用以及上限。
用户级别
/etc/security/limits.conf
root soft nofile 65535
限制进程
# 限制work进程打开文件的个数
worker_rlimit_nofile number ;
# 限制work打开的连接个数
woker_connection number;
队列长度
syn队列: net.ipv4.tcp_max_syn_backlog
accept队列: net.core.somaxconn
backlog=number: 应用级别的。
tcp fast open

net.ipv4.tcp_fastopen
0: 关闭
1: 作为客户端可以使用tfo
2: 作为服务端可以使用tfo
3: 都是用tfo
fastopen=number 可以防止携带数据的syn攻击,限制以最大长度。
滑动窗口和缓冲区
滑动窗口
- 功能:
限制连接的网速,解决报文乱序和可靠传输问题。通过操作系统内核实现。
- 发送窗口:
用于发送内容
- 接收窗口:
用于接收内容
发送tcp消息

tcp接收消息

nginx的超时时间和滑动窗口
client_body_timeout: 2次读操作间的超时时间。
send_timeout: 2次写操作的超时时间。
proxy_timeout: 2次读或者2次写的超时时间。
丢包重传
net.ipv4.tcp_retries1 = 3 达到上限后更新路由缓存。
net.ipv4.tcp_retries2 = 15 达到上限后关闭tcp连接
优化滑动窗口和传输效率
tcp缓冲区
net.ipv4.tcp_rmem 设置读取缓冲区最小值,默认值和最大值。单位字节。
net.ipv4.tcp_wmem: 设置写缓冲区最小值,默认值和最大值。单位字节。
net.ipv4.tcp_mem: 系统无内存压力、启动压力模式阈值、最大值。单位为页的数量。
net.ipv4.tcp_moderate_rcvbuf=1: 开启自动调整缓存模式。
revbuf: 接受缓冲区大小
sndbuf: 发送缓冲大小
最大接受窗口应该=带宽x时延
nagle算法
避免一个连接上同事存在大量小报文。提升带宽利用率 tcp_nodelay on 禁用nagle算法。
postpone_output 不到足够大小不发送。
cork算法
仅仅针对sendfile on 开启时候生效,完全禁止小报文的发送,提升网络效率 tcp_nopush on 。
慢启动和拥塞窗口
流量控制
拥塞窗口: 发送端主动限制流量
通告窗口: 接受方限制流量
实际流量: 拥塞窗口和通告的最小值。
拥塞处理
慢启动方式: 指数扩展拥塞窗口。
拥塞避免: 窗口大于threshold.
拥塞发生: 计算降低拥塞窗口。
快速恢复:
tcp keepalive
- 应用场景:
检测实际断掉的连接 用于维持与客户端间的防火墙有活跃网络包。
netipv4.tcp_keepalive_time: 发送心跳周期
net.ipv4.tcp_keepalive_intvl: 探测包发送间隔。
net.ipv4.tcp_keepalive_probes: 探测包重试次数。
so_keepalive= nginx的tcp keep alive参数指定。
减少连接的timewait的状态数量
net.ipv4.tcp_orphan_retries: 发送fin的重试次数。
net.ipv4.tcp_fin_timeout: 保持在wait2的时间。
net.ipv4.tcp_tw_reuse=1 作为客户端可以服用tw的端口。
net.ipv4.tcp_timestamps :拒绝迟到的包
net.ipv4.tcp_tw_recycle 作为客户端和服务端都可以使用tw的端口。
net.ipv4.tcp_max_tw_buckets 设置最大数量超过就直接关闭了。
lingering_close 延迟关闭连接
nginx处理完成调用close关闭连接,可能会导致客户端收到rst忽略response.
lingering_close 会自动跟进实际情况关闭。
应用层协议优化
ssl_session_cache: 定义共享内存,为所有worker进程提供session缓存服务,1mb可以使用4ksession。
tls/ssl中的会话票证
nginx将会话session的信息作为tickets加密发送给客户端,下次客户端发起请求tls连接的时候带上tickets,nginx解密验证后复用会话session.
ssl_session_tickets: 是否启用ssl tickets
ssl_session_ticket_key: 秘钥文件。
http长连接
减少握手次数
降低tcp拥塞控制影响。
gzip压缩
通过实时压缩http包体,提升网络传输效率。
gzip on 开启
gzip_types: 哪些类型压缩
gzip_min_length: 低于特定大小不压缩
gzip_disable : 哪些不压缩。
gzip_proxied:是否压缩上游响应
升级更高效的http2.0协议
磁盘io的优化
优化读取
sendfile 0copy
内存盘ssd盘
减少写入
aio
增加日志级别
关闭access_log
压缩日志
syslog替代本地io
直接io
当磁盘的文件大小超过特定size后,启用直接io可以避免磁盘页缓存中的copy消耗。
directio 是否开启
directio_alignment: 超过的大小。
aio
aio 是否启用
aio_write:
定义线程池
适合静态集群
减少磁盘读写次数
empty_gif模块
这是一个1x1的图片,大小43个字节。
日志压缩
access_log 设置buffer flush等参数减少日志打印次数。
error_log日志输出到内存
开发环境中定位问题打开debug级别的日志,但对debug的级别大量日志引发的性能问题不能容忍,将日志打印到内存中。
sysylog
零copy和gzip_static

如果磁盘文件需要压缩的话, 直接有同名.gz的文件响应给用户。
gunzip当客户端不支持gzip,磁盘有压缩文件的话,则解压缩并发送客户端。
tcmalloc
分配内存的性能更高。
并发能力高
减少内存碎片
编译时候指定 –with-ld-opt=-ltcmalloc –with-google_perftools_module
使用google perf 分析
分析nginx哪些函数消耗的时间比较久。
statu模块监控nginx数据
stub-status可以通过http接口,返回实时的监控的nginx连接状态。
openresty及nginx源码
第三方模块源码的快速阅读方法
分析模块提供的config文件
分析nginx_module_t 模块
分析nginx_commmand_t数组
对于http模块,分析ngx_http_module_t
分析模块生效方法。
config结构
ngx_addon_name: 定义模块名称
HTTP_MODULES: 定义模块
NGX_ADDON_SRCS: 哪些模块的源文件需要编译
ngx_addon_name=ngx_http_headers_more_filter_module
HEADERS_MORE_SRCS=" \
$ngx_addon_dir/src/ngx_http_headers_more_filter_module.c \
$ngx_addon_dir/src/ngx_http_headers_more_headers_out.c \
$ngx_addon_dir/src/ngx_http_headers_more_headers_in.c \
$ngx_addon_dir/src/ngx_http_headers_more_util.c \
"
HEADERS_MORE_DEPS=" \
$ngx_addon_dir/src/ddebug.h \
$ngx_addon_dir/src/ngx_http_headers_more_filter_module.h \
$ngx_addon_dir/src/ngx_http_headers_more_headers_in.h \
$ngx_addon_dir/src/ngx_http_headers_more_headers_out.h \
$ngx_addon_dir/src/ngx_http_headers_more_headers_in.h \
$ngx_addon_dir/src/ngx_http_headers_more_util.h \
"
if test -n "$ngx_module_link"; then
ngx_module_type=HTTP_AUX_FILTER
ngx_module_name=$ngx_addon_name
ngx_module_incs=
ngx_module_deps="$HEADERS_MORE_DEPS"
ngx_module_srcs="$HEADERS_MORE_SRCS"
ngx_module_libs=
. auto/module
else
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $HEADERS_MORE_SRCS"
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $HEADERS_MORE_DEPS"
fi
nginx启动和退户回调方法
ngx_int_t (*init_master)(ngx_log_t *log);
ngx_int_t (*init_module)(ngx_cycle_t *cycle);
ngx_int_t (*init_process)(ngx_cycle_t *cycle);
ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
void (*exit_thread)(ngx_cycle_t *cycle);
void (*exit_process)(ngx_cycle_t *cycle);
void (*exit_master)(ngx_cycle_t *cycle);
nginx启动过程

master进程循环

work进程循环

http模块初始化

http模块的11个阶段
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;
添加模块到11个阶段的常用方法
直接覆盖式,通过 clcf->handler = nginx_http_proxy_handler;
通过链表。top->filter1(还有next指向后续filter2)
if指令连续出现
演示案例
具体原因分析
if指令是rewrite阶段的执行的,会在if条件为真的时候,替换掉当前请求的配置,if是向上继承的,在rewrite阶段顺序执行时, 每次if为真都会替换当前请求的配置。
正确姿势
熟练掌握rewrite的5个指令。
if是可以正确执行,不依赖外部的指令。
break会阻断后续rewrite的阶段指令的执行。
coredump 核心转储文件
worker_rlimit_core限制core文件大小,working_directory 控制coredump放置的目录。
官方参考: http://nginx.org/en/docs/ngx_core_module.html#worker_rlimit_core
如何生成coredump文件
配置nginx配置如下
worker_rlimit_core 100M;
working_directory /tmp/nginx;
发送信号
# 确认一个work进程id
[root@zhaojiedi-elk-2 nginx]# ps -ef |grep nginx
root 22358 1 0 20:35 ? 00:00:00 nginx: master process ./sbin/nginx
root 22622 22358 0 20:37 ? 00:00:00 nginx: worker process
root 22696 22358 0 20:37 ? 00:00:00 nginx: worker process
root 22894 20221 0 20:39 pts/0 00:00:00 grep --color=auto nginx
#确认下段异常错误为11
[root@zhaojiedi-elk-2 nginx]# kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
# send signal
[root@zhaojiedi-elk-2 nginx]# kill -11 22622 22696
[root@zhaojiedi-elk-2 nginx]# ll /tmp/nginx/
total 0
[root@zhaojiedi-elk-2 nginx]# ll /home/coresave/
total 9016
-rw------- 1 root root 5124096 Jan 17 20:39 core.nginx.22622.1642423167
-rw------- 1 root root 5124096 Jan 17 20:39 core.nginx.22696.1642423167
这里机器单独配置了core位置了,你是nginx配置的为啥不能覆盖系统的呢。
[root@zhaojiedi-elk-2 nginx]# sysctl -a |grep patt
kernel.core_pattern = /home/coresave/core.%e.%p.%t
gdb的基本使用
bt: 显示函数堆栈调用情况
f: 显示某1堆栈详细信息
p: 打印变量值
l: 显示附近代码
x: 显示具体内存值
i: 显示信息
gdb分析上面产生的core文件
# 开始gdb
[root@zhaojiedi-elk-2 nginx]# gdb /root/openresty/nginx/sbin/nginx /home/coresave/core.nginx.22622.1642423167
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/openresty/nginx/sbin/nginx...done.
[New LWP 22622]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `nginx: worker'.
Program terminated with signal 11, Segmentation fault.
#0 0x00007efcbd29dfb3 in __epoll_wait_nocancel () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install GeoIP-1.5.0-14.el7.x86_64 bzip2-libs-1.0.6-13.el7.x86_64 cyrus-sasl-lib-2.1.26-23.el7.x86_64 expat-2.1.0-12.el7.x86_64 fontconfig-2.13.0-4.3.el7.x86_64 freetype-2.8-14.el7_9.1.x86_64 gd-2.0.35-27.el7_9.x86_64 glibc-2.17-324.el7_9.x86_64 gperftools-libs-2.6.1-1.el7.x86_64 keyutils-libs-1.5.8-3.el7.x86_64 krb5-libs-1.15.1-50.el7.x86_64 libX11-1.6.7-4.el7_9.x86_64 libXau-1.0.8-2.1.el7.x86_64 libXpm-3.5.12-1.el7.x86_64 libcom_err-1.42.9-19.el7.x86_64 libgcc-4.8.5-44.el7.x86_64 libgcrypt-1.5.3-14.el7.x86_64 libgpg-error-1.12-3.el7.x86_64 libjpeg-turbo-1.2.90-8.el7.x86_64 libpng-1.5.13-8.el7.x86_64 libselinux-2.5-15.el7.x86_64 libstdc++-4.8.5-44.el7.x86_64 libuuid-2.23.2-65.el7_9.1.x86_64 libxcb-1.13-1.el7.x86_64 libxml2-2.9.1-6.el7.5.x86_64 libxslt-1.1.28-6.el7.x86_64 nspr-4.25.0-2.el7_9.x86_64 nss-3.53.1-7.el7_9.x86_64 nss-softokn-freebl-3.53.1-6.el7_9.x86_64 nss-util-3.53.1-1.el7_9.x86_64 openldap-2.4.44-24.el7_9.x86_64 openssl-libs-1.0.2k-21.el7_9.x86_64 pcre-8.32-17.el7.x86_64 perl-libs-5.16.3-299.el7_9.x86_64 postgresql-libs-9.2.24-7.el7_9.x86_64 xz-libs-5.2.2-1.el7.x86_64 zlib-1.2.7-19.el7_9.x86_64
# 看看函数堆栈
(gdb) bt
#0 0x00007efcbd29dfb3 in __epoll_wait_nocancel () from /lib64/libc.so.6
#1 0x0000000000455461 in ngx_epoll_process_events (cycle=0x1b5f060, timer=18446744073709551615, flags=1)
at src/event/modules/ngx_epoll_module.c:800
#2 0x000000000044a2e3 in ngx_process_events_and_timers (cycle=cycle@entry=0x1b5f060) at src/event/ngx_event.c:257
#3 0x00000000004530e5 in ngx_worker_process_cycle (cycle=cycle@entry=0x1b5f060, data=data@entry=0x1)
at src/os/unix/ngx_process_cycle.c:782
#4 0x0000000000451a6c in ngx_spawn_process (cycle=cycle@entry=0x1b5f060,
proc=proc@entry=0x4530a0 <ngx_worker_process_cycle>, data=data@entry=0x1,
name=name@entry=0x59d83f "worker process", respawn=respawn@entry=-4) at src/os/unix/ngx_process.c:199
#5 0x000000000045347c in ngx_start_worker_processes (cycle=cycle@entry=0x1b5f060, n=2, type=type@entry=-4)
at src/os/unix/ngx_process_cycle.c:382
#6 0x0000000000454354 in ngx_master_process_cycle (cycle=0x1b5f060, cycle@entry=0x1b28c40)
at src/os/unix/ngx_process_cycle.c:241
#7 0x00000000004281d2 in main (argc=<optimized out>, argv=<optimized out>) at src/core/nginx.c:386
# 查看各个线程的函数堆栈,这里只有1个线程的。
(gdb) thread apply all bt
Thread 1 (Thread 0x7efcc0bf28c0 (LWP 22622)):
#0 0x00007efcbd29dfb3 in __epoll_wait_nocancel () from /lib64/libc.so.6
#1 0x0000000000455461 in ngx_epoll_process_events (cycle=0x1b5f060, timer=18446744073709551615, flags=1)
at src/event/modules/ngx_epoll_module.c:800
#2 0x000000000044a2e3 in ngx_process_events_and_timers (cycle=cycle@entry=0x1b5f060) at src/event/ngx_event.c:257
#3 0x00000000004530e5 in ngx_worker_process_cycle (cycle=cycle@entry=0x1b5f060, data=data@entry=0x1)
at src/os/unix/ngx_process_cycle.c:782
#4 0x0000000000451a6c in ngx_spawn_process (cycle=cycle@entry=0x1b5f060,
proc=proc@entry=0x4530a0 <ngx_worker_process_cycle>, data=data@entry=0x1,
name=name@entry=0x59d83f "worker process", respawn=respawn@entry=-4) at src/os/unix/ngx_process.c:199
#5 0x000000000045347c in ngx_start_worker_processes (cycle=cycle@entry=0x1b5f060, n=2, type=type@entry=-4)
at src/os/unix/ngx_process_cycle.c:382
#6 0x0000000000454354 in ngx_master_process_cycle (cycle=0x1b5f060, cycle@entry=0x1b28c40)
at src/os/unix/ngx_process_cycle.c:241
#7 0x00000000004281d2 in main (argc=<optimized out>, argv=<optimized out>) at src/core/nginx.c:386
# 进入线程1
(gdb) t 1
[Switching to thread 1 (Thread 0x7efcc0bf28c0 (LWP 22622))]
#0 0x00007efcbd29dfb3 in __epoll_wait_nocancel () from /lib64/libc.so.6
# 进入堆栈1
(gdb) f 1
#1 0x0000000000455461 in ngx_epoll_process_events (cycle=0x1b5f060, timer=18446744073709551615, flags=1)
at src/event/modules/ngx_epoll_module.c:800
800 events = epoll_wait(ep, event_list, (int) nevents, timer);
# 打印这个变量的值看看
(gdb) p *cycle
$1 = {conf_ctx = 0x1b2a0d0, pool = 0x1b28c00, log = 0x1b5f078, new_log = {log_level = 4, file = 0x1b290a8,
connection = 0, disk_full_time = 0, handler = 0x0, data = 0x0, writer = 0x0, wdata = 0x0, action = 0x0,
next = 0x0}, log_use_stderr = 0, files = 0x0, free_connections = 0x7efcc0b562c8, free_connection_n = 1021,
modules = 0x1c21060, modules_n = 129, modules_used = 1, reusable_connections_queue = {prev = 0x1b5f100,
next = 0x1b5f100}, reusable_connections_n = 0, connections_reuse_time = 0, listening = {elts = 0x1b86440,
nelts = 1, size = 296, nalloc = 1, pool = 0x1b28c00, old_elts = 0x0}, paths = {elts = 0x1b2a900, nelts = 5,
size = 8, nalloc = 5, pool = 0x1b28c00, old_elts = 0x0}, config_dump = {elts = 0x1ba2840, nelts = 3, size = 24,
nalloc = 4, pool = 0x1b28c00, old_elts = 0x1ba28d0}, config_dump_rbtree = {root = 0x1baf200,
sentinel = 0x1b5f1c8, insert = 0x42fb80 <ngx_str_rbtree_insert_value>}, config_dump_sentinel = {key = 0,
left = 0x0, right = 0x0, parent = 0x0, color = 0 '\000', data = 0 '\000'}, open_files = {last = 0x1b5f1f8,
part = {elts = 0x1b29080, nelts = 2, next = 0x0}, size = 40, nalloc = 2, pool = 0x1b28c00}, shared_memory = {
last = 0x1b5f230, part = {elts = 0x1b29490, nelts = 0, next = 0x0}, size = 88, nalloc = 1, pool = 0x1b28c00},
connection_n = 1024, files_n = 0, connections = 0x7efcc0b56010, read_events = 0x1cddcf0, write_events = 0x1cf5d00,
old_cycle = 0x0, conf_file = {len = 37, data = 0x1b28ff0 "/root/openresty/nginx/conf/nginx.conf"}, conf_param = {
len = 0, data = 0x1b29060 "0\220\262\001"}, conf_prefix = {len = 27,
data = 0x1b28f20 "/root/openresty/nginx/conf/"}, prefix = {len = 22, data = 0x1b28f90 "/root/openresty/nginx/"},
error_log = {len = 14, data = 0x1b28fd0 "logs/error.log"}, lock_file = {len = 38,
data = 0x1bf8e60 "/root/openresty/nginx/logs/nginx.lock.accept"}, hostname = {len = 33,
data = 0x1b64620 "zhaojiedi-elk-2.epc.duxiaoman.com"}, intercept_error_log_handler = 0x0,
intercept_error_log_data = 0x0, entered_logger = 0}
(gdb) p *cycle->modules
$2 = (ngx_module_t *) 0x807360 <ngx_core_module>
# 查看具体命令
(gdb) p cycle->modules[10]->commands[15]
$19 = {name = {len = 3, data = 0x5c903e "ngx_openssl_module"}, type = 0, set = 0x0, conf = 1019009, offset = 5868632,
post = 0x8092c0 <ngx_openssl_module_ctx>}
(gdb) p ((ngx_listening_t*)(cycle->listening->elts))[1]
$24 = {fd = 4097, sockaddr = 0x0, socklen = 0, addr_text_max_len = 2, addr_text = {len = 0,
data = 0x1b9dd78 "\"h\233\321\a"}, type = 28981264, backlog = 0, rcvbuf = 0, sndbuf = 0, keepidle = 0,
keepintvl = 0, keepcnt = 10, handler = 0x0, servers = 0x1b9deb8, log = {log_level = 28981264, file = 0x0,
connection = 0, disk_full_time = 0, handler = 0x0, data = 0x1b9df68, writer = 0x1ba3810, wdata = 0x0,
action = 0x0, next = 0x2}, logp = 0x0, pool_size = 28958712, post_accept_buffer_size = 28981264, previous = 0x0,
connection = 0x0, rbtree = {root = 0x2, sentinel = 0x0, insert = 0x1b9e128}, sentinel = {key = 28949512,
left = 0x0, right = 0x0, parent = 0x2, color = 0 '\000', data = 0 '\000'}, worker = 28959336, open = 0,
remain = 0, ignore = 0, bound = 1, inherited = 1, nonblocking_accept = 1, listen = 0, nonblocking = 0, shared = 0,
addr_ntop = 0, wildcard = 1, ipv6only = 1, reuseport = 1, add_reuseport = 1, keepalive = 2, deferred_accept = 1,
delete_deferred = 0, add_deferred = 0, fastopen = 0}
debug定位问题
我们引入了第三方模块可能存在bug的,打开debug_points后则遇到问题后停止服务,方便定位问题。
abort: 生成coredump后结束进程
stop: 结束进程
控制debug级别的error.log日志输出
debug_connection针对特定客户端打印debug级别的日志,其他的日志正常打印。
Note
需要nginx编译的时候–with-debug编译选项。
debug日志分析
建立连接
ssl握手
接受请求的头部
解析行
解析头部
11阶段处理
查找location
反向代理构造上游的请求
接收客户端请求包体
构造响应头
发送响应
过滤模块
# 可以看到请求过来了。
2022/01/19 15:03:55 [debug] 46632#46632: *20 accept: 10.157.89.215:40240 fd:3
2022/01/19 15:03:55 [debug] 46632#46632: malloc: 0000000001BD4F20:64
2022/01/19 15:03:55 [debug] 46632#46632: malloc: 0000000001BFBC10:16
2022/01/19 15:03:55 [debug] 46632#46632: malloc: 0000000001C0AE30:24
2022/01/19 15:03:55 [debug] 46632#46632: malloc: 0000000001BFA720:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 event timer add: 3: 60000:10094575278
2022/01/19 15:03:55 [debug] 46632#46632: *20 reusable connection: 1
2022/01/19 15:03:55 [debug] 46632#46632: *20 epoll add event: fd:3 op:1 ev:80002001
2022/01/19 15:03:55 [debug] 46632#46632: *20 http wait request handler
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BAF200:80
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BFA580:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C86610:1024
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BAE800:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 recv: eof:0, avail:-1
2022/01/19 15:03:55 [debug] 46632#46632: *20 recv: fd:3 91 of 1024
2022/01/19 15:03:55 [debug] 46632#46632: *20 reusable connection: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B39230:48
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C26990:1544
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B9F340:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C84C10:960
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BB0FA0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001CD9AD0:192
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BAFC20:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C61CB0:680
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BAF720:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B390E0:272
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B9A380:16
# 开始处理请求行
2022/01/19 15:03:55 [debug] 46632#46632: *20 http process request line
2022/01/19 15:03:55 [debug] 46632#46632: *20 http request line: "GET / HTTP/1.1"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http uri: "/"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http args: ""
2022/01/19 15:03:55 [debug] 46632#46632: *20 http exten: ""
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B5AB30:960
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B4AAF0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http process request header line
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BCE0E0:10
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B91880:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http header: "User-Agent: curl/7.29.0"
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B56AC0:4
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B2F3F0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http header: "Host: n-ssl2.linuxpanda.tech:8012"
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B5E6D0:6
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BB3620:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http header: "Accept: */*"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http header done
2022/01/19 15:03:55 [debug] 46632#46632: *20 event timer del: 3: 10094575278
# http的阶段开始
2022/01/19 15:03:55 [debug] 46632#46632: *20 generic phase: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 rewrite phase: 1
2022/01/19 15:03:55 [debug] 46632#46632: *20 rewrite phase: 2
# 选择location 看到使用了/
2022/01/19 15:03:55 [debug] 46632#46632: *20 test location: "/"
2022/01/19 15:03:55 [debug] 46632#46632: *20 using configuration "/"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http cl:-1 max:1048576
2022/01/19 15:03:55 [debug] 46632#46632: *20 rewrite phase: 4
2022/01/19 15:03:55 [debug] 46632#46632: *20 rewrite phase: 5
2022/01/19 15:03:55 [debug] 46632#46632: *20 post rewrite phase: 6
2022/01/19 15:03:55 [debug] 46632#46632: *20 generic phase: 7
2022/01/19 15:03:55 [debug] 46632#46632: *20 generic phase: 8
2022/01/19 15:03:55 [debug] 46632#46632: *20 generic phase: 9
2022/01/19 15:03:55 [debug] 46632#46632: *20 generic phase: 10
2022/01/19 15:03:55 [debug] 46632#46632: *20 access phase: 11
2022/01/19 15:03:55 [debug] 46632#46632: *20 access phase: 12
2022/01/19 15:03:55 [debug] 46632#46632: *20 access phase: 13
2022/01/19 15:03:55 [debug] 46632#46632: *20 post access phase: 14
2022/01/19 15:03:55 [debug] 46632#46632: *20 generic phase: 15
2022/01/19 15:03:55 [debug] 46632#46632: *20 generic phase: 16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C82730:1184
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BB4070:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C7F370:176
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C04B80:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B950C0:304
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BEE440:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B29140:72
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C04A80:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http init upstream, client timer: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 epoll add event: fd:3 op:3 ev:80002005
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B72E80:80
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B8C0D0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BFA660:105
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C05F60:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C04880:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C04980:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http script copy: "Host"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http script var: "n-ssl2.linuxpanda.tech"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http script copy: "Connection"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http script copy: "close"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http script copy: ""
2022/01/19 15:03:55 [debug] 46632#46632: *20 http script copy: ""
2022/01/19 15:03:55 [debug] 46632#46632: *20 http proxy header: "User-Agent: curl/7.29.0"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http proxy header: "Accept: */*"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http proxy header:
# 可以看到发送给上游的请求详细信息。
"GET / HTTP/1.0
Host: n-ssl2.linuxpanda.tech
Connection: close
User-Agent: curl/7.29.0
Accept: */*
"
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C02E10:48
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C047A0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C7AB30:72
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C07050:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BB9E40:24
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B8BE70:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http cleanup add: 0000000001BB9E40
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BE9BA0:40
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B620F0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 get rr peer, try: 1
2022/01/19 15:03:55 [debug] 46632#46632: *20 stream socket 5
2022/01/19 15:03:55 [debug] 46632#46632: *20 epoll add connection: fd:5 ev:80002005
2022/01/19 15:03:55 [debug] 46632#46632: *20 connect to 127.0.0.1:8011, fd:5 #21
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream connect: -2
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C03270:48
2022/01/19 15:03:55 [debug] 46632#46632: *20 event timer add: 5: 60000:10094575278
2022/01/19 15:03:55 [debug] 46632#46632: *20 http finalize request: -4, "/?" a:1, c:2
2022/01/19 15:03:55 [debug] 46632#46632: *20 http request count:2 blk:0
2022/01/19 15:03:55 [debug] 46632#46632: *20 http run request: "/?"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream check client, write event:1, "/"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream request: "/?"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream send request handler
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BFEA40:96
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BB0EF0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 set session: 0000000000000000
2022/01/19 15:03:55 [debug] 46632#46632: *20 tcp_nodelay
# ssl
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_do_handshake: -1
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_get_error: 2
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL handshake handler: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 verify:1, error:0, depth:1, subject:"/C=cn/ST=henan/L=zhengzhou/O=linuxpanda/OU=opt/CN=n-ca.linuxpanda.tech", issuer:"/C=cn/ST=henan/L=zhengzhou/O=linuxpanda/OU=opt/CN=n-ca.linuxpanda.tech"
2022/01/19 15:03:55 [debug] 46632#46632: *20 verify:1, error:0, depth:0, subject:"/C=cn/ST=henan/O=linuxpanda/OU=opt/CN=n-ssl1.linuxpanda.tech", issuer:"/C=cn/ST=henan/L=zhengzhou/O=linuxpanda/OU=opt/CN=n-ca.linuxpanda.tech"
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_do_handshake: -1
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_get_error: 2
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL handshake handler: 1
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_do_handshake: -1
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_get_error: 2
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL handshake handler: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 save session: 0000000001C36CF0
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_do_handshake: 1
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream ssl handshake: "/?"
2022/01/19 15:03:55 [debug] 46632#46632: *20 X509_check_host(): match
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream send request
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream send request body
2022/01/19 15:03:55 [debug] 46632#46632: *20 chain writer buf fl:1 s:105
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B35710:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001CDD230:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 chain writer in: 0000000001B35710
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001CD4D30:80
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C3DE00:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C152D0:16384
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C2A640:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL buf copy: 105
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL to write: 105
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_write: 105
2022/01/19 15:03:55 [debug] 46632#46632: *20 chain writer out: 0000000000000000
2022/01/19 15:03:55 [debug] 46632#46632: *20 event timer del: 5: 10094575278
2022/01/19 15:03:55 [debug] 46632#46632: *20 event timer add: 5: 60000:10094575284
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream process header
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C6F870:4096
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C80700:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B85E20:384
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001CD4D90:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C477B0:96
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C708A0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_read: -1
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_get_error: 2
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream request: "/?"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream dummy handler
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream request: "/?"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream process header
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_read: 204
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_read: -1
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_get_error: 2
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B2D1E0:6
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C86C70:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http proxy status 200 "200 OK"
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C66C60:26
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C3EB20:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http proxy header: "Server: nginx/1.20.2"
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C3DD40:39
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C2A970:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http proxy header: "Date: Wed, 19 Jan 2022 07:03:55 GMT"
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B9E130:50
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C04730:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http proxy header: "Content-Type: application/octet-stream"
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B31780:32
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BE4C30:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http proxy header: "Content-Length: 47"
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001CB8A50:27
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BE4C50:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http proxy header: "Connection: close"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http proxy header done
2022/01/19 15:03:55 [debug] 46632#46632: *20 xslt filter header
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C51C50:80
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BA2990:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001CB8BB0:196
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BA29B0:16
# 上游的响应结果
2022/01/19 15:03:55 [debug] 46632#46632: *20 HTTP/1.1 200 OK
Server: openresty/1.19.9.1 (no pool)
Date: Wed, 19 Jan 2022 07:03:55 GMT
Content-Type: application/octet-stream
Content-Length: 47
Connection: keep-alive
2022/01/19 15:03:55 [debug] 46632#46632: *20 write new buf t:1 f:0 0000000001CB8BB0, pos 0000000001CB8BB0, size: 178 file: 0, size: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 http write filter: l:0 f:0 s:178
2022/01/19 15:03:55 [debug] 46632#46632: *20 http cacheable: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C83470:280
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B5E900:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B5E920:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B6A2C0:16
# filter
2022/01/19 15:03:55 [debug] 46632#46632: *20 http proxy filter init s:200 h:0 c:0 l:47
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream process upstream
2022/01/19 15:03:55 [debug] 46632#46632: *20 pipe read upstream: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 pipe preread: 47
2022/01/19 15:03:55 [debug] 46632#46632: *20 pipe buf free s:0 t:1 f:0 0000000001C6F870, pos 0000000001C6F90D, size: 47 file: 0, size: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 pipe length: 47
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001B6A2E0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BCDB60:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C47870:80
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BCDB80:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 input buf #0
2022/01/19 15:03:55 [debug] 46632#46632: *20 pipe write downstream: 1
2022/01/19 15:03:55 [debug] 46632#46632: *20 pipe write downstream flush in
2022/01/19 15:03:55 [debug] 46632#46632: *20 http output filter "/?"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http copy filter: "/?"
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C3EFC0:136
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C478D0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 image filter
2022/01/19 15:03:55 [debug] 46632#46632: *20 xslt filter body
2022/01/19 15:03:55 [debug] 46632#46632: *20 http postpone filter "/?" 0000000001B6A2E0
2022/01/19 15:03:55 [debug] 46632#46632: *20 write old buf t:1 f:0 0000000001CB8BB0, pos 0000000001CB8BB0, size: 178 file: 0, size: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 write new buf t:1 f:0 0000000001C6F870, pos 0000000001C6F90D, size: 47 file: 0, size: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 http write filter: l:0 f:0 s:225
2022/01/19 15:03:55 [debug] 46632#46632: *20 http copy filter: 0 "/?"
2022/01/19 15:03:55 [debug] 46632#46632: *20 pipe write downstream done
2022/01/19 15:03:55 [debug] 46632#46632: *20 event timer: 5, old: 10094575284, new: 10094575284
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream exit: 0000000000000000
2022/01/19 15:03:55 [debug] 46632#46632: *20 finalize http upstream request: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 finalize http proxy request
2022/01/19 15:03:55 [debug] 46632#46632: *20 free rr peer 1 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 SSL_shutdown: 1
2022/01/19 15:03:55 [debug] 46632#46632: *20 close http upstream connection: 5
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C2A640, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C3DE00, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BB0EF0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 event timer del: 5: 10094575284
2022/01/19 15:03:55 [debug] 46632#46632: *20 reusable connection: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 http upstream temp fd: -1
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001CD4D30:80
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BB0EF0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 http output filter "/?"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http copy filter: "/?"
2022/01/19 15:03:55 [debug] 46632#46632: *20 image filter
2022/01/19 15:03:55 [debug] 46632#46632: *20 xslt filter body
2022/01/19 15:03:55 [debug] 46632#46632: *20 http postpone filter "/?" 00007FFF07F3B090
2022/01/19 15:03:55 [debug] 46632#46632: *20 write old buf t:1 f:0 0000000001CB8BB0, pos 0000000001CB8BB0, size: 178 file: 0, size: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 write old buf t:1 f:0 0000000001C6F870, pos 0000000001C6F90D, size: 47 file: 0, size: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C3DE00:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C2A640:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 write new buf t:0 f:0 0000000000000000, pos 0000000000000000, size: 0 file: 0, size: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 http write filter: l:1 f:0 s:225
2022/01/19 15:03:55 [debug] 46632#46632: *20 http write filter limit 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 writev: 225 of 225
2022/01/19 15:03:55 [debug] 46632#46632: *20 http write filter 0000000000000000
2022/01/19 15:03:55 [debug] 46632#46632: *20 http copy filter: 0 "/?"
2022/01/19 15:03:55 [debug] 46632#46632: *20 http finalize request: 0, "/?" a:1, c:1
2022/01/19 15:03:55 [debug] 46632#46632: *20 set http keepalive handler
2022/01/19 15:03:55 [debug] 46632#46632: *20 http close request
2022/01/19 15:03:55 [debug] 46632#46632: *20 http log handler
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C7F320:28
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C3DD70:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C54BC0:26
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C54B80:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C70960:255
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C54BA0:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C54BA0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C54B80, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C3DD70, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C2A640, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BB0EF0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C478D0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BCDB80, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BCDB60, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001B6A2C0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001B5E900, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BA29B0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BA2990, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BE4C50, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BE4C30, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C04730, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C2A970, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C3EB20, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C86C70, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C708A0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001CD4D90, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C80700, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001CDD230, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001B620F0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001B8BE70, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C07050, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C047A0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C04980, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C05F60, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001B8C0D0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C04A80, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BEE440, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C04B80, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BB4070, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BB3620, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001B2F3F0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001B91880, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001B4AAF0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001B9A380, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BAF720, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BAFC20, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BB0FA0, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001B9F340, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001C86610
2022/01/19 15:03:55 [debug] 46632#46632: *20 hc free: 0000000000000000
2022/01/19 15:03:55 [debug] 46632#46632: *20 hc busy: 0000000000000000 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 tcp_nodelay
2022/01/19 15:03:55 [debug] 46632#46632: *20 reusable connection: 1
2022/01/19 15:03:55 [debug] 46632#46632: *20 event timer add: 3: 65000:10094580284
2022/01/19 15:03:55 [debug] 46632#46632: *20 http keepalive handler
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001C86610:1024
2022/01/19 15:03:55 [debug] 46632#46632: *20 malloc: 0000000001BAE800:16
2022/01/19 15:03:55 [debug] 46632#46632: *20 recv: eof:1, avail:-1
2022/01/19 15:03:55 [debug] 46632#46632: *20 recv: fd:3 0 of 1024
2022/01/19 15:03:55 [info] 46632#46632: *20 client 10.157.89.215 closed keepalive connection
2022/01/19 15:03:55 [debug] 46632#46632: *20 close http connection: 3
2022/01/19 15:03:55 [debug] 46632#46632: *20 event timer del: 3: 10094580284
2022/01/19 15:03:55 [debug] 46632#46632: *20 reusable connection: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BAE800, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BFA580, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BFA720, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BFBC10, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BFBD10, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001BFBE10, unused: 0
2022/01/19 15:03:55 [debug] 46632#46632: *20 free: 0000000001B5E280, unused: 0
openresty简介
官方地址: https://openresty.org/cn/
详细的需要看对应组件的帮助文档。 github有对应的功能描述。
主要组成

运行机制

openrestysdk分类
cosocket通信
共享内存的字典
定时器
基于携程的并发编程
修改请求
修改响应
自请求
openresty的使用要点
不破坏事件驱动实现,不要阻塞nginx进度调度。
不破坏nginx低内存的消耗优点
保持lua代码高效
openrestry的nginx核心模块
ndk_http_module: 开发工具包
ngx_http_lua_module:openrestry提供http服务lua编程能力的核心模块
ngx_http_lua_upstream_mudule: http_lua的补充,提供upstream api。
ngx_stream_lua_module: 提供四层服务lua编程能力的核心模块。
openrestry的nginx工具模块
ngx_http_headers_more_filter_module: rewrite阶段处理请求,修改请求响应的header头的。
ngx_http_rds_json——filter_module: 过滤模块,将rds格式的转换为json格式。
openrestry的官方lua模块
lua_redis_parser: 将redis相应解析为lua数据结构。
lua_rds_parser: 将mysql postgress数据库响应解析为lua数据结构
lua_restry_dns: 基于cosocket实现dns协议的通信。
lua_resty_redis: 基于ngx.socket.tcp实现的redis客户端。
lua_resty_string: 字符串转换函数
如何在nginx中嵌入lua

在nginx过程嵌入lua代码
init_by_lua , init_by_lua_block , init_by_lua_file : master启动。
init_worker_by_lua: work启动的时候调用
set_by_lua:
rewrite_by_lua:
access_by_lua:
content_by_lua:
log_by_lua:
lua ffi
提供一种lua语音使用c语言函数的功能。
系统级配置指令
lua_malloc_trim: 每N个请求使用mallock_trim方法,将缓存的空闲内存归还操作系统。
lua_code_cache: lua vm的所有请求共享
lua_package_path: 设置lua模块的路径
lua_package_cpath: 设置lua调用c模块的路径地址。
nginx的变量
ngx.var.VAR_NAME 可以访问和修改变量
ngx.req
ngx.req.get_headers
ngx.req.get_method
ngx.req.http_version
ngx.req.get_uri_args
ngx.arg[index]
ngx.req.get_post_args
ngx.req.read_body
nginx.req.get_body_data
nginx.req.get_body_file
发送响应sdk
ngx.print
ngx.say
ngx.flush
ngx.exit
ngx.eof
日志
cosocket
lua_socket_connect_time: 连接超时时间
lua_socket_send_timeout: 2次写超时时间
lua_socket_read_timeout: 2次读超时时间
lua_socket_bufer_size: 设置读缓冲区大小
lua_socket_pool_size: 设置连接池最大连接数
lua_socket_keepalive_timeout: 连接空闲时间
lua_socket_log_errors: 是否记录错误日志到nginx的error.log中。
ngx.socket.tcp : tcp相关方法函数
nginx.socket.socket: 获取socket对象
ngx.socket.udp: udp client
多协程方法
ngx.thread.spawn : 生成轻量级线程。
coroutine create : 创建lua协程。
la_resty_lock锁
lock: 锁定
unlock: 解锁
expire: timeout 最大等待时间。
定时器
ngx.timer.at 定时器触发后执行callback
ngx.timer.every: 每多久执行一次
ngx.timer.runing_count: 运行的定时器数量
ngx.timer.pending_count 等待执行的定时器数量
共享内存
提供跨work的共享内存共享内容机制。是原子的,线程安全的。ngx.shared.DICT.
nginx主请求和子请求
子请求的生命周期是依赖父请求
父请求可以通过postpone_filter处理子请求的响应。
ngx.location.capture 可以生成子请求。
基于openrestry的waf防火墙
github search waf