【充电】《Nginx核心知识100讲》Nginx变量的运行原理
极客专栏《Nginx核心知识100讲》72小节,笔记
注意:这个是看专栏视频,敲的哈。这个专栏让我收货蛮大的。
72 | Nginx变量的运行原理
在nginx 中,变量是一个非常强大的工具,我们可以在nginx config中通过各个模块处理请求的方式,所以变量是非常好的解耦工具。变量也可以在Openresty lua里面中大有用处。
变量使用的原理
image.png变量的模块怎么样提供一个nginx呢?首先启动nginx,启动nginx之后发现,这个是一个http模块,http模块有个回调方法叫做preconfiguragtion。这个模块开始读取配置文件了,这个模块可能对它的一些指令感兴趣,所以要读取配置文件。pre呢就是在读取之前。这个模块还没有在读nginx配置文件之前,就开始添加它提供的新变量了。比如referer模块提供了一个valid referer,还有real ip模块,它也提供了remote real ip、remote real port等等
这个定义变量到底是怎样的过程呢? 定义了一个变量名,和解析变量的方法。就是给定输入,输入就是请求的header,输出呢?就是这个变量名的值。比如说变量名是host。那Host的值是多少呢?给定你所有请求的header,从header中找某个以大写的H小写的ost打头的后面的值,作为Host变量的输出。
这个模块只是定义了规则。当需要变量名的值的时候请使用解析变量的方法
,根据用户请求的内容,把我们变量名的值找出来。使用变量的模块通过变量名完成了解耦。因为各自(提供变量的模块跟使用变量的模块)的关注点不一样。real ip模块专注于修改客户端的ip提供一些新的变量或者referer。它(提供变量的模块)只专注于提供一个vaild referer。用户是否盗链了。至于盗链以后到底应该怎样处理。我这个referer模块一点都不担心。这样的话,每个模块专注提供自己的东西。这是一个非常好的架构设计。
到了使用变量的模块。比如说rewrite模块,它提供了一个if指令。if指令只关注判断。如果某个变量为真或者为假,我们调用return指令,向用户返回403或者401等等。这是我使用变量模块。它们通过一个vaild referer或者remote addr等等这样变量名的值,实现了完全的解耦。
使用变量的模块是怎样做的呢?首先,这个使用变量的模块,比如说rewrite模块。它通过它的if指令。它在解析nginx.conf中它有个 if指令。if指令后面我们跟上了vaild referer,这个时候请求还没有来。定义好 了怎么样使用if指令。使用if指令的方法是基于vaild referer去判断的。接下来,请求真的来了以后,看下白色的框(http头部读取完毕了),这个请求读取完了。处理请求的时候呢?根据找到这个vaild referer变量名(提供变量的模块
),然后根据这个变量名的求取方法找到对应的值。根据这个值,按照本身模块的指令开始处理。
变量的特性
在上面流程中两个特性。
image.png惰性求值:使用变量的模块只有在请求接收到的时候,并且到了我们11个http阶段或者过滤模块等,开始读取变量的值的时候,才会去求值。否则这个变量实际上不会对我们的性能产生任何影响。因为它没有机会或没有得到执行。我们就不会实际的求值。
惰性求值有性能上的好处。它带来了另外一个问题,变量值在请求处理的过程中是时刻变化的。有一些是不会变化的。比如是http头部,或者方法名。但是有一些是在变化的,比如说限流、限速。每一秒中发送给用户的字节数不同的话。我们的发送速率也是不一样的。所以这个变量也是在时刻变化的。所以当我们读取变量值的那一刻。它的值并不代表这个请求处理之前的值。所以有一些时刻变化的变量值,在使用的时候需要注意。它只反应在使用的那一刻时的值。
作为这样频繁被使用对nginx功能扩展非常有帮助的变量,nginx为提升它的性能,专门设计了一个哈希表来存储这些变量。
image.png以上介绍了nginx,http模块中的变量的用法。nginx 四层反向代理的stream模块或者mail系列模块。它们使用变量的方式也是相同的。使用好变量对于我们发挥nginx的强大功能是非常用帮助的。
留言问题
1.感谢老师的详细讲解,初步了解原理和基本用法后更期待后续的性能优化经验。
目前我们使用 Web Socket 实现消息推送时加上 Nginx 后给客户端推送消息就存在传输时延问题
作者回复
第4部分有一节课讲websocket反向代理:-)
2.root指令和proxy_pass都存在时,谁的优先级更高?
作者回复
proxy_pass
3.,由于第二部分的内容我不是很能理解,又自己学习了下linux的socket编程。有三个问题想跟您请教一下。
一。 可以利用socket编程接口,把socket设置成阻塞或者非阻塞的,对吧。
二。
epoll这种方式是操作系统本身提供的,是吧?
三。编程接口为什么要由进程(比如nginx)主动(recv方法)去读取内容,而不是把网络端接受到的消息直接推送给进程呢?
作者回复
- 1.对。
- 2.是的。
- 3.消息存放在内核态,需要进程读取到用户态内存才能处理。