Nginx Learning Notes

This article introduces the basic concepts of Nginx.

Oh Sorry!

This blog has’t been translated to English, please wait for a little while…

  • 高效的HTTP和反向代理服务器,转发请求到后面的服务,可以有一定负载均衡(如加权轮询,把更多请求打到资源更充足的服务端)的能力。
  • 占用内存小,并发能力强,官方数据支持5w个并发连接响应。
  • 正向代理和反向代理:VPN-帮忙代理客户端,转发请求。反向代理:代理服务端,让客户端只访问一个域名就可以转到多个服务端。
  • iphash:相同ip的请求都发到一个服务端,解决session不共享问题,不建议直接用nginx,考虑最前面用redis来作为最前端的server。
  • 动静分离:静态资源交给nginx直接返回
  • 重写rewrite:比如访问80的都转到443

image

master-slave架构,事件驱动模型,异步进行,主要由三部分构成

  • master:一个master thread,接受client请求,转发给worker并立刻接收下一个请求(不等待worker);有worker返回数据后返回response给client
  • workers:多个worker thread,处理master转发的client请求
  • cache:用于缓存页面并快速返回,而不是从server中再次获取

image

一个nginx process有一个master thread、多个worker threads、一个cache loader 和一个cache manager thread。

  • master负责的内容主要有:
    • 读取和验证配置
    • 创建、绑定和关闭sockets
    • 开始、终止worker
    • 热配置(修改配置而不需要重新启动,reconfiguring)
    • 热升级(non-stop binary upgrades)
  • worker负责接受、处理连接,反向代理等多种功能,实际干活的
  • cache loader:负责检查在磁盘上的缓存项及更新内存中的 cache metadata
  • cache manager:主要是处理cache 过期和 cache 失效
  • nginx不会spawn一个process或thread来处理每个新接入的请求,而是在每个worker process(single thread)中执行一个高效的run-loop来处理数以千计的请求。
  • nginx worker监听和发送请求使用OS kernel机制——socket
  • 在worker的run-loop里,为了实现高效异步处理请求,nginx使用modularityevent notificationcallback functiontimers等多种机制来尽可能保证处理不阻塞
  • 由于没有对每一个请求新建线程/进程处理,nginx的内存消耗和CPU使用都很低。spawn的多个worker也便于扩展和利用多核处理器。
  • worker数量配置建议:如果主要是CPU处理的(大量TCP/IP请求、SSL、compression等)则worker数量等于CPU核数;如果有许多disk io的(如从存储中提供内容-静态代理)则worker数量为CPU核数的1.5~2倍
  • nginx的缓存是以文件系统上的分层数据存储形式实现的,文件树结构可通过directory配置
  • cache key和cache metadata存储在shared memory中,worker、cache loader和cache manager都可以访问。
  • 生成缓存的过程:当nginx从上游服务中获取response时,内容会先写进一个临时文件在cache directory之外,当nginx完整处理这个请求后该cache落盘到cache directory中
  • nginx的配置项从配置文件中读取,可能是/usr/local/etc/nginx/etc/nginx目录下,主要的配置文件为nginx.conf
  • 现在也支持从template中生成配置文件,使得动态环境变量成为可能。例如:
1
2
3
4
5
6
7
# nginx.template
server {
  listen ${LISTEN PORT};
  location / {
    proxy_pass ${NGINX_PROXY_PASS};
  }
}
  • nginx的配置项由master线程读取和校验,并通过进程中的内存共享方式给到worker
  • 配置项分为不同的block上下文,有mainhttpserverlocationupstreammail(mail proxy)等。上下文不会交叠(overlap)
  • nginx通过一个流水线(pipeline)或者说链路(chain)来处理连接,该pipeline有许多不同的modules构成。

  • functional modules包括event modules, phase handlers, output filters, variable handlers, protocols, upstreams and load balancers

  • httpmail module位于 core 和 functional module间,提供额外一层抽象,保证对functional module的调用是有序的。

  • 一个典型的http调用过程如下

    1. 客户端发送http 请求
    2. nginx core基于配置的location选择合适的phase handler
    3. 如果有配置,load balancer选择一个上游server做代理
    4. phase handler处理工作,将output buffer传给第一个filter(filter处理handler的输出)
    5. 第一个filter将output传给第二个filter
    6. 第二个filter将output传给第三个filter(以此类推,但并不需要等待上一个filter完全处理好,只要input available后即可)
    7. 最终的response发送给client
  • 对于worker,其工作的内部的action如下

    1. 开始ngx_worker_process_cycle()
    2. 通过OS机制(如epollkqueue)处理events
    3. 接收events并执行event对应相关操作
    4. 处理/代理 请求的 header和body
    5. 创建response content(header、body)并将它发送给client(流式传输)
    6. 结束一个请求
    7. 重新初始化timer和events
  • nginx对于一个请求,会依次执行processing phases来处理(每个phase选择对应的handler),例如,有一个virtual server时,request经过以下六个phase

    1. server rewrite phase
    2. location phase
    3. location rewrite phase (可能会把rewrite带到上一个阶段)
    4. access control phase
    5. try_files phase
    6. log phase
  • subrequests

    • 一些web框架也叫internal redirect,可以发起多个请求组织成一个response给client
    • nginx的subrequest还可以嵌套和继承,如一个subrequest发起很多sub-subrequests
    • subrequest可以映射到磁盘文件、其他handler、上游server等多处
  • upstream:与proxy_pass相关,将请求发送到upstream server(backend)并接受上游server的response

  • load balancer:与proxy_pass相关,有多个upstream时选择合适的server route请求,常用方法如round-robinip-hash

  • nginx的memory管理主要基于传递指针共享,尽可能减少在内存中的复制操作

  • 概念:nginx缓存upstream的响应,再用合适的速度发送给客户端。使用proxy_buffering配置

  • 为什么有代理缓冲?一般而言,nginx和server通信速度快,和clinet通信较慢(在同一个机房)。如果和client通信太慢,则nginx和server的通信也会被拖慢,造成一次连接请求耗时太长,对server可能造成连接积压。

  • 优点:nginx尽快缓存响应体,以合适的速度发给客户端,server连接就断开了,减少资源消耗。

  • 缺点:占用nginx内存,如果响应较大缓冲区存不下还需要写到磁盘中占用IO;

  • 因此,如果客户端到nginx的请求速度也很快就关闭代理缓冲,效率会更高。

  • 延伸:proxy_request_buffering即缓冲client的request再发给服务

一些常用配置,详解用注释写在一旁:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 将请求代理转发到另一个url,支持正则
proxy_pass http://10.198.32.254/;

# 传递client的真实ip
proxy_set_header X-Real-IP $remote_addr;

# nginx会记录并前向传递ip chain e.g: client1, proxy1, proxy2
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

# proto: http/https
proxy_set_header X-Forwarded-Proto $scheme;    

# `$host` equals the server name in the “Host” request Header
# if it is not set by request, it equals to the primary server name
proxy_set_header Host $host;


# Default is HTTP/1, keepalive is only enabled in HTTP/1.1
# In HTTP/1.1, nginx's Default Connection is `close`
# So we use "" to overwrite it to allow keepalive
proxy_http_version 1.1;
proxy_set_header Connection "";