Nginx入门学习笔记
Nginx学习笔记
1-什么是Nginx?
Nginx (engine x) 是一款轻量级的 Web 服务器 、反向代理服务器及电子邮件(IMAP/POP3)代理服务器。
Nginx因为它的稳定性、丰富的模块库、灵活的配置和低系统资源的消耗而闻名.业界一致认为它是Apache2.2+mod_proxy_balancer的轻量级代替者,不仅是因为响应静态页面的速度非常快,而且它的模块数量达到Apache的近2/3。对proxy和rewrite模块的支持很彻底,还支持mod_fcgi、ssl、vhosts ,适合用来做mongrel clusters的前端HTTP响应。
Nginx和Apache一样使用模块化设计,nginx模块包括内置模块和第三方模块,其中内置模块中包含主模块和事件模块。
Nginx处理请求逻辑图
2-正向代理和反向代理
2.1-什么是正向代理?
正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。
- 客户端请求目标服务器之间的代理服务器
- 请求会先经过代理服务器,然后再转发请求到目标服务器,获得内容后,最后再响应给客户端
2.2-什么是反向代理?
反向代理,客户端是无感知代理的存在,以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端。
反向代理(Reverse Proxy)方式是指以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
作用:
- 保证内网的安全,公网作为访问地址,web服务器谁内网;
- 负载均衡
3-Nginx的作用
3.1-Nginx可以提供的服务
正向代理
反向代理
HTTP服务器
Nginx本身也是一个静态资源的服务器,当只有静态资源的时候,就可以使用Nginx来做服务器,同时现在也很流行动静分离,就可以通过Nginx来实现,首先看看Nginx做静态资源服务器。
现在很多项目流行前后分离,也就是前端服务器和后端服务器分离,分别部署,这样的方式能让前后端人员能各司其职,不需要互相依赖,而前后分离中,前端项目的运行是不需要用Tomcat、Apache等服务器环境的,因此可以直接用nginx来作为静态服务器。
负载均衡
负载均衡也是Nginx常用的一个功能,负载均衡其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。简单而言就是当有2台或以上服务器时,根据规则随机的将请求分发到指定的服务器上处理,负载均衡配置一般都需要同时配置反向代理,通过反向代理跳转到负载均衡。
3.2-Nginx的优点
- 高并发。静态小文件
- 占用资源少。2万并发、10个线程,内存消耗几百M。
- 功能种类比较多。web,cache,proxy。每一个功能都不是特别强。
- 支持epoll模型,使得nginx可以支持高并发。
- nginx 配合动态服务和Apache有区别。(FASTCGI 接口)
- 利用nginx可以对IP限速,可以限制连接数。
- 配置简单,更灵活。
4-Nginx的安装与使用
4.1-Nginx的安装
详细安装方法请参考:
https://github.com/dunwu/nginx-tutorial/blob/master/docs/nginx-ops.md
4.2-Nginx的使用
nginx 的使用比较简单,就是几条命令。
常用到的命令如下:
nginx -s stop 快速关闭Nginx,可能不保存相关信息,并迅速终止web服务。 |
如果不想每次都敲命令,可以在 nginx 安装目录下新添一个启动批处理文件startup.bat,双击即可运行。内容如下:
off |
如果是运行在 Linux 下,写一个 shell 脚本,大同小异。
5-Nginx配置实战
5.1-http 反向代理配置
nginx.conf 配置文件如下:
注:conf / nginx.conf 是 nginx 的默认配置文件。你也可以使用 nginx -c 指定你的配置文件
#运行用户 |
- 启动 webapp,注意启动绑定的端口要和 nginx 中的
upstream
设置的端口保持一致。 - 更改 host:在 C:\Windows\System32\drivers\etc 目录下的 host 文件中添加一条 DNS 记录
127.0.0.1 www.helloworld.com |
- 启动前文中 startup.bat 的命令
- 在浏览器中访问
www.helloworld.com
,不出意外,已经可以访问了。
5.2-Nginx跨域解决方案
为什么会有跨域问题?
浏览器的同源策略拒绝了我们的请求。 所谓同源是指,域名,协议,端口相同,浏览器执行一个脚本时同源的脚本才会被执行。如果非同源,那么在请求数据时,浏览器会在控制台中报上面的异常,提示拒绝访问。这是为了同一浏览器打开多个网站时,保护你的A网站登陆信息不被B网站拿去访问A网站,B网站登陆信息同理。
web 领域开发中,经常采用前后端分离模式。这种模式下,前端和后端分别是独立的 web 应用程序,例如:后端是 Java 程序,前端是 React 或 Vue 应用。如果项目没做前后端分离,是不会有跨域问题的。前后端分离的项目中,前端调用后台服务时,报错 No 'Access-Control-Allow-Origin' header is present on the requested resource
,你就是遇到了跨域问题。
各自独立的 web app 在互相访问时,势必存在跨域问题。解决跨域问题一般有两种思路:
CORS
在后端服务器设置 HTTP 响应头,把你需要运行访问的域名加入加入
Access-Control-Allow-Origin
中。jsonp
把后端根据请求,构造 json 数据,并返回,前端用 jsonp 跨域。
需要说明的是,nginx 根据第一种思路,也提供了一种解决跨域的解决方案。
举例:
www.helloworld.com
网站是由一个前端 app ,一个后端 app 组成的。前端端口号为 9000, 后端端口号为 8080。
前端和后端如果使用 http 进行交互时,请求会被拒绝,因为存在跨域问题。来看看,nginx 是怎么解决的吧:
location / { |
1. Access-Control-Allow-Origin
服务器默认是不被允许跨域的。给Nginx服务器配置`Access-Control-Allow-Origin *`后,表示服务器可以接受所有的请求源(Origin),即接受所有跨域的请求。 |
2. Access-Control-Allow-Headers 是为了防止出现以下错误:
Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response. |
这个错误表示当前请求Content-Type的值不被支持。其实是我们发起了”application/json”的类型请求导致的。这里涉及到一个概念:预检请求(preflight request)
,请看下面”预检请求”的介绍。
3. Access-Control-Allow-Methods 是为了防止出现以下错误:
Content-Type is not allowed by Access-Control-Allow-Headers in preflight response. |
4.给OPTIONS
添加 204
的返回,是为了处理在发送POST请求时Nginx依然拒绝访问的错误
发送”预检请求”时,需要用到方法 OPTIONS
,所以服务器需要允许该方法。
5.3-Nginx防盗链
防盗链的意义在于防止网站中的文件链接在其他网站中被使用,盗链的文件或图片在其他网站中加载,在这个过程中,实质上加载的请求是被盗链服务器上响应的,这就造成了一些不正常流量(并非自己网站的正常打开页面加载的处理请求)造成了消耗不必要的带宽。
要实现防盗链,需要了解HTTP协议中的请求头部的Referer头域和采用URL的格式表示访问当前网页或者文件的源地址。通过该头域的值,我们可以检测到访问目标资源的源地址。这样,如果我们检测到Referer(rui’fe~)头域中的值并不是自己站点内的URL,就采取组织措施,实现防盗链。
nginx防盗链使用到了valid_referers这个名单定义项(相当是定义白名单域名,如需定义多个域名使用空格分隔,非这里定义的域名会在转跳中返回403状态码),if中定义:非名单里里的域名可以定义返回403状态拒绝访问或返回一个盗链显示图片,如果使用盗链显示图片就定义rewrite跳转到那个图片的URL。
- location中定义防止盗链的文件类型,以正则的语法进行匹配
- expires、access_log定义了这些文件过期时间和日志不记录类型的配置,防盗链与静态文件过期时间和访问日志不记录可以在一个location中定义配置
- rewrite设定指定转跳,设定指定转跳的URL地址,返回状态码302
- return跟rewrite类似,只不过在最后处理请求时是直接拒绝掉这个盗链的请求,返回状态码403
server{ |
5.4-负载均衡配置
反向代理的例子中,代理仅仅指向一个服务器。
但是,网站在实际运营过程中,多半都是有多台服务器运行着同样的 app,这时需要使用负载均衡来分流。
nginx 也可以实现简单的负载均衡功能。
假设这样一个应用场景:将应用部署在 192.168.1.11:80、192.168.1.12:80、192.168.1.13:80 三台 linux 环境的服务器上。网站域名叫 www.helloworld.com
,公网 IP 为 192.168.1.11。在公网 IP 所在的服务器上部署 nginx,对所有请求做负载均衡处理。
nginx.conf 配置如下:
http { |
Nginx的负载均衡策略
1. 轮循(round-robin)默认策略(RR-默认)
根据请求次数,将每个请求均匀分配到每台服务器,如果后端服务器宕机,自动剔除。
#动态服务器组 |
最基本的配置方法,上面的例子就是轮询的方式,它是upstream模块默认的负载均衡默认策略。每个请求会按时间顺序逐一分配到不同的后端服务器。
有如下参数:
fail_timeout | 与max_fails结合使用。 |
---|---|
max_fails | 设置在fail_timeout参数设置的时间内最大失败次数,如果在这个时间内,所有针对该服务器的请求都失败了,那么认为该服务器会被认为是停机了, |
fail_time | 服务器会被认为停机的时间长度,默认为10s。 |
backup | 标记该服务器为备用服务器。当主服务器停止时,请求会被发送到它这里。 |
down | 标记服务器永久停机了。 |
注意:
- 在轮询中,如果服务器down掉了,会自动剔除该服务器。
- 缺省配置就是轮询策略。
- 此策略适合服务器配置相当,无状态且短平快的服务使用。
2. 权重(Weight)
权重方式,在轮询策略的基础上指定轮询的几率,指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
upstream load_balance_server { |
注意:
- 权重越高分配到需要处理的请求越多。
- 此策略可以与least_conn和ip_hash结合使用。
- 此策略比较适合服务器的硬件配置差别比较大的情况。
3. ip_hash
在负载均衡系统中,假如用户在某台服务器上登录了,那么该用户第二次请求的时候,因为我们是负载均衡系统,每次请求都会重新定位到服务器集群中的某一个,那么已经登录某一个服务器的用户再重新定位到另一个服务器,其登录信息将会丢失,这样显然是不妥的。
我们可以采用ip_hash指令解决这个问题,如果客户已经访问了某个服务器,当用户再次访问时,会将该请求通过哈希算法,自动定位到该服务器。
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
指定负载均衡器按照基于客户端IP的分配方式,这个方法确保了相同的客户端的请求一直发送到相同的服务器,以保证session会话。这样每个访客都固定访问一个后端服务器,可以解决session不能跨服务器的问题。
同一客户端的Web请求被分发到同一个后端服务器进行处理,使用该策略可以有效的避免用户Session失效的问题。该策略可以连续产生1045个互异的value,经过20次hash仍然找不到可用的机器时,算法会退化成轮循。
#动态服务器组 |
注意:
- 在nginx版本1.3.1之前,不能在ip_hash中使用权重(weight)。
- ip_hash不能与backup同时使用。
- 此策略适合有状态服务,比如session。
- 当有服务器需要剔除,必须手动down掉。
4. 最少连接(least_conn)
把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。
#动态服务器组 |
注意:
- 此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况。
5. 参数说明
weight
启用权重策略,总数按照10进行计算,如果分配为3,则表示所有连接中的30%分配给该服务器,默认值为1;
max_fail/fail_timeout
某台服务器允许请求失败的次数,超过最大数后,在fail_timeout时间内,新的请求不会分配给这台机器,等fail_timeout时间过去后, 会再尝试请求这台服务器,如此循环往复;如果设置为0,反向代理服务器则会将这台服务器设置为永久无效状态。max_fail默认为1,fail_timeout默认为10秒;
backup
将某台服务器设定为备用机,当列表中的其他服务器都不可用时,启用备用机;
down
将某台服务器设定为不可用状态;
max_conns
限制分配给某台服务器的最大连接数,超过这个数量,反向代理服务器将不会分配新的连接,默认为0,表示不限制;
6. 第三方策略
扩展策略默认不被编译进nginx内核,如果启用该策略,需要自行编译安装,需要安装第三方插件。
fair
按照服务器端的响应时间来分配请求,响应时间短的优先分配。
根据后台服务器的响应时间判断负载情况,从中选出负载最轻的后端服务。但是在实际请款中,网络环境往往不那么简单,所以慎用。
在编译安装后,如果需要启用该策略,需要在upstream标签中添加
fair;
,启用该策略后,加权轮循将失效。#动态服务器组
upstream load_balance_server {
server localhost:8080; #tomcat 7.0
server localhost:8081; #tomcat 8.0
server localhost:8082; #tomcat 8.5
server localhost:8083; #tomcat 9.0
#实现响应时间短的优先分配
}url_hash
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,要配合缓存命中来使用。同一个资源多次请求,可能会到达不同的服务器上,导致不必要的多次下载,缓存命中率不高,以及一些资源时间的浪费。而使用url_hash,可以使得同一个url(也就是同一个资源请求)会到达同一台服务器,一旦缓存住了资源,再此收到请求,就可以从缓存中读取。
- 按照请求url的hash结果来分配请求,试每个url定向到同一个后端服务器,在1.7.2之后的nginx版本中,该模块应集成到内核中,不需要单独安装;
- 启用该策略,需要在upstream标签中添加`hash $request_url;。
#动态服务器组
upstream load_balance_server {
hash $request_uri; #实现每个url定向到同一个后端服务器
server localhost:8080; #tomcat 7.0
server localhost:8081; #tomcat 8.0
server localhost:8082; #tomcat 8.5
server localhost:8083; #tomcat 9.0
}
5.5-网站有多个 webapp 的配置
当一个网站功能越来越丰富时,往往需要将一些功能相对独立的模块剥离出来,独立维护。这样的话,通常,会有多个 webapp。
举个例子:假如 www.helloworld.com
站点有好几个 webapp,finance(金融)、product(产品)、admin(用户中心)。访问这些应用的方式通过上下文(context)来进行区分:
我们知道,http 的默认端口号是 80,如果在一台服务器上同时启动这 3 个 webapp 应用,都用 80 端口,肯定是不成的。所以,这三个应用需要分别绑定不同的端口号。
那么,问题来了,用户在实际访问 www.helloworld.com
站点时,访问不同 webapp,总不会还带着对应的端口号去访问吧。所以,你再次需要用到反向代理来做处理。
配置也不难,来看看怎么做吧:
http { |
5.6-https 反向代理配置
一些对安全性要求比较高的站点,可能会使用 HTTPS(一种使用 ssl 通信标准的安全 HTTP 协议)。
这里不科普 HTTP 协议和 SSL 标准。但是,使用 nginx 配置 https 需要知道几点:
- HTTPS 的固定端口号是 443,不同于 HTTP 的 80 端口
- SSL 标准需要引入安全证书,所以在 nginx.conf 中你需要指定证书和它对应的 key
其他和 http 反向代理基本一样,只是在 Server
部分配置有些不同。
首先要确定 Nginx有没安装了ssl 模块。
nginx -V |
#HTTP服务器 |
5.7-静态站点配置
有时候,我们需要配置静态站点(即 html 文件和一堆静态资源)。
举例来说:如果所有的静态资源都放在了 /app/dist
目录下,我们只需要在 nginx.conf
中指定首页以及这个站点的 host 即可。
配置如下:
worker_processes 1; |
然后,添加 HOST:
127.0.0.1 static.zp.cn
此时,在本地浏览器访问 static.zp.cn ,就可以访问静态站点了。
5.8-搭建文件服务器
有时候,团队需要归档一些数据或资料,那么文件服务器必不可少。使用 Nginx 可以非常快速便捷的搭建一个简易的文件服务。
Nginx 中的配置要点:
- 将 autoindex 开启可以显示目录,默认不开启。
- 将 autoindex_exact_size 开启可以显示文件的大小。
- 将 autoindex_localtime 开启可以显示文件的修改时间。
- root 用来设置开放为文件服务的根路径。
- charset 设置为
charset utf-8,gbk;
,可以避免中文乱码问题(windows 服务器下设置后,依然乱码,本人暂时没有找到解决方法)。
一个最简化的配置如下:
autoindex on;# 显示目录 |
5.9-Nginx缓存配置
面对第一次客户端的应用Nginx需要从后端的服务获取数据,对于后续的请求,Nginx若进行了缓存就不再从后端服务获取数据。
1. proxy_cache_path
语法:proxy_cache_path path [levels=levels].只能用在http中。
指定缓存位置、缓存名称、内存中缓存内容元数据信息大小限制、缓存总大小限制。缓存位置是一个目录应该先创建好,nginx并不会帮我们创建这个缓存目录
proxy_cache_path /root/cache levels=1:2 keys_zone=zzm_cache:10m max_size=1g inactive=60m use_temp_path=off; |
- /root/cache:定义 proxy_cache 生成文件的根路径
- levels:默认所有缓存文件都放在上面指定的根路径中,从而可能影响缓存的性能。推荐指定为 2 级目录来存储缓存文件
- key_zone:这个的值是字符串,可以随意写。用于在共享内存中定义一块存储区域来存放缓存的 key 和 metadata(类似于使用次数),这样 nginx 可以快速判断一个 request 是否命中缓存。1m 可以存储 8000 个key,10m可以存在80000个key
- max_size:最大 cache 空间。如果不指定,会使用掉所有 disk space。当达到 disk 上限后,会删除最少使用的 cache
- inactive:内存中缓存的过期检查周期。示例配置中如果 1h 内都没有被访问,则不论状态是否为 expired,都会清除缓存。需要注意的是,inactive 和 expired 配置项的含义是不同的,expired 只是判断过期时间,不会删除缓存;而 inactive 是直接删除过期缓存
- use_temp_path:如果为 off,则 nginx 会将缓存文件直接写入指定的 cache 文件中,而不使用 temp_path 指定的临时存储路径
2. proxy_cache
proxy_cache zone | off。默认是关闭的,可以用在http,server,location中。
指定使用前面设置的缓存名称
location / { |
- proxy_cache:对应 http 段的 key_zone,是你定义的 proxy_cache 所使用的共享空间的名称,我在1.1中定义的是zzm_cache,所以在这里也写的是zzm_cache。
- proxy_cache_valid:对指定的 HTTP 状态进行缓存,并指定缓存时间。可以自定义写入多个配置项。这里我们对200和304的返回码缓存12小时。其余的缓存10分钟
- proxy_cache_key:缓存的维度
- is_args:如果$args设置,值为”?”,否则为””
- proxy_next_upstream 当请求服务器发生错误或超时时,会尝试到下一台服务器
3. 静态资源缓存浏览器
expires 指令
location /static{ |
4. 服务器资源缓存到 Nginx端
# 设置缓存保存的目录 |
5.10-常见问题
- 使用Nginx的反向代理,让同一个用户的请求一定转发到同一台服务器上,这种均衡策略会消耗更多的服务器资源,也增加了代理服务器的负担;
- 使用其他策略作为负载均衡时,会出现用户Session丢失的情况,为避免出现这种情况,可以将用户的Session存放到缓存服务器中,比较常用的方案时redis/memchache;
- 反向代理服务器也可以开启缓存服务,但是开启该项服务会增加代理服务器的负担,影响整体的负载均衡效率;
- 使用Nginx反向代理布置负载均衡,操作相对简单,但是会有“单点故障”的问题,如果后台某台服务器宕机,会带来很多的麻烦,后期如果后台服务器继续增加,反向代理服务器会成为负载均衡方案的瓶颈。
6-Nginx的架构和原理
6.1-Nginx的整体架构
1. 主进程
Nginx启动时,会生成两种类型的进程,一个是主进程(master),一个(windows版本的目前只有一个)或多个工作进程(worker)。
主进程并不处理网络请求,主要负责调度工作进程,也就是图示的3项:加载配置、启动工作进程、非停升级
因此,Nginx启动以后,查看操作系统的进程列表,我们就能看到至少有两个Nginx进程。
2. 工作进程
服务器实际处理网络请求及响应的是工作进程(worker),在类unix系统上,Nginx可以配置多个worker,而每个worker进程都可以同时处理数以千计的网络请求。
3.模块化设计
Nginx的worker进程,包括核心和功能性模块,核心模块负责维持一个运行循环(run-loop),执行网络请求处理的不同阶段的模块功能。
比如:网络读写、存储读写、内容传输、外出过滤,以及将请求发往上游服务器等。
而其代码的模块化设计,也使得我们可以根据需要对功能模块进行适当的选择和修改,编译成具有特定功能的服务器。
4. 事件驱动模型
基于异步及非阻塞的事件驱动模型,可以说是Nginx得以获得高并发、高性能的关键因素,同时也得益于对Linux、Solaris及类BSD等操作系统内核中事件通知及I/O性能增强功能的采用,如kqueue、epoll及eventports。
5. 代理(proxy)设计
代理设计,可以说是Nginx深入骨髓的设计,无论是对于HTTP,还是对于FastCGI、Memcache、Redis等的网络请求或响应,本质上都采用了代理机制。所以,Nginx天生就是高性能的代理服务器。
6.2-Nginx的模块化设计
高度模块化的设计是Nginx的架构基础。Nginx服务器被分解为多个模块,每个模块就是一个功能模块,只负责自身的功能,模块之间严格遵循“高内聚,低耦合”的原则。
如下图所示:
1. 核心模块
核心模块是Nginx服务器正常运行必不可少的模块,提供错误日志记录、配置文件解析、事件驱动机制、进程管理等核心功能。
2. 标准HTTP模块
标准HTTP模块提供HTTP协议解析相关的功能,比如:端口配置、网页编码设置、HTTP响应头设置等等。
3. 可选HTTP模块
可选HTTP模块主要用于扩展标准的HTTP功能,让Nginx能处理一些特殊的服务,比如:Flash多媒体传输、解析GeoIP请求、网络传输压缩、安全协议SSL支持等。
4. 邮件服务模块
邮件服务模块主要用于支持Nginx的邮件服务,包括对POP3协议、IMAP协议和SMTP协议的支持。
5. 第三方模块
第三方模块是为了扩展Nginx服务器应用,完成开发者自定义功能,比如:Json支持、Lua支持等。
6.3-Nginx的请求方式处理
Nginx是一个高性能的Web服务器,能够同时处理大量的并发请求。它结合多进程机制和异步机制,异步机制使用的是异步非阻塞方式,接下来就给大家介绍一下Nginx的多线程机制和异步非阻塞机制。
1. 多进程机制
服务器每当收到一个客户端时,就有服务器主进程(master process)生成一个子进程(worker process)出来和客户端建立连接进行交互,直到连接断开,该子进程就结束了。
使用进程的好处是各个进程之间相互独立,不需要加锁,减少了使用锁对性能造成影响,同时降低编程的复杂度,降低开发成本。
其次,采用独立的进程,可以让进程互相之间不会影响,如果一个进程发生异常退出时,其它进程正常工作,master进程则很快启动新的worker进程,确保服务不会中断,从而将风险降到最低。
缺点是操作系统生成一个子进程需要进行内存复制等操作,在资源和时间上会产生一定的开销。当有大量请求时,会导致系统性能下降。
2. 异步非阻塞机制
每个工作进程使用异步非阻塞方式,可以处理多个客户端请求。
当某个工作进程接收到客户端的请求以后,调用IO进行处理,如果不能立即得到结果,就去处理其他请求(即为非阻塞),而客户端在此期间也无需等待响应,可以去处理其他事情(即为异步)
当IO返回时,就会通知此工作进程,该进程得到通知,暂时挂起当前处理的事务去响应客户端请求。
6.4-Nginx事件驱动模型
在Nginx的异步非阻塞机制中,工作进程在调用IO后,就去处理其他的请求,当IO调用返回后,会通知该工作进程。
对于这样的系统调用,主要使用Nginx服务器的事件驱动模型来实现,如下图所示:
如上图所示,Nginx的事件驱动模型由事件收集器、事件发送器和事件处理器三部分基本单元组成。
- 事件收集器:负责收集worker进程的各种IO请求;
- 事件发送器:负责将IO事件发送到事件处理器;
- 事件处理器:负责各种事件的响应工作。
事件发送器将每个请求放入一个待处理事件列表,使用非阻塞I/O方式调用事件处理器来处理该请求。
其处理方式称为“多路IO复用方法”,常见的包括以下三种:select模型、poll模型、epoll模型。
6.5-Nginx进程处理模型
Nginx服务器使用 master/worker 多进程模式,多线程启动和执行的流程如下:
主程序Masterprocess启动后,通过一个for循环来接收和处理外部信号
主进程通过fork()函数产生worker子进程,每个子进程执行一个for循环来实现Nginx服务器对事件的接收和处理
一般推荐worker进程数与CPU内核数一致,这样一来不存在大量的子进程生成和管理任务,避免了进程之间竞争CPU资源和进程切换的开销。
而且Nginx为了更好的利用多核特性,提供了CPU亲缘性的绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来Cache的失效。
对于每个请求,有且只有一个工作进程对其处理。首先,每个worker进程都是从master进程fork过来。在master进程里面,先建立好需要listen的socket(listenfd)之后,然后再fork出多个worker进程。
所有worker进程的listenfd会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有worker进程在注册listenfd读事件前抢占accept_mutex
抢到互斥锁的那个进程注册listenfd读事件,在读事件里调用accept接受该连接。
当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,一个完整的请求就是这样。
我们可以看到,一个请求,完全由worker进程来处理,而且只在一个worker进程中处理。
如下图所示:
在Nginx服务器的运行过程中,主进程和工作进程需要进程交互。交互依赖于Socket实现的管道来实现。
1. 主进程与工作进程交互
这条管道与普通的管道不同,它是由主进程指向工作进程的单向管道,包含主进程向工作进程发出的指令工,作进程ID等。同时主进程与外界通过信号通信;每个子进程具备接收信号,并处理相应的事件的能力。
2. 工作进程与工作进程交互
这种交互和主进程-工作进程交互基本一致,但是会通过主进程间接完成,工作进程之间是相互隔离的。
所以当工作进程W1需要向工作进程W2发指令时,首先找到W2的进程ID,然后将正确的指令写入指向W2的通道,W2收到信号采取相应的措施。
参考:
https://www.jianshu.com/p/5026ab611d4e
https://www.jb51.net/article/143985.htm