Nginx—Ngine X,是一款免费的、自由的、开源的、高性能HTTP服务器和反向代理服务器;也是一个IMAP、POP3、SMTP代理服务器;Nginx以其高性能、稳定性、丰富的功能、简单的配置和低资源消耗而闻名。
也就是说Nginx本身就可以托管网站(类似于Tomcat一样),进行Http服务处理,也可以作为反向代理服务器 、负载均衡器和HTTP缓存。
Nginx 解决了服务器的C10K(就是在一秒之内连接客户端的数目为10k即1万)问题。它的设计不像传统的服务器那样使用线程处理请求,而是一个更加高级的机制—事件驱动机制,是一种异步事件驱动结构
Nginx 是一个高性能的 Web 服务器,能够同时处理大量的并发请求。它结合多进程机制和异步机制 ,异步机制使用的是异步非阻塞方式 ,接下来就给大家介绍一下 Nginx 的多线程机制和异步非阻塞机制 。
服务器每当收到一个客户端时,就有 服务器主进程 ( master process )生成一个 子进程( worker process )出来和客户端建立连接进行交互,直到连接断开,该子进程就结束了。
使用进程的好处是各个进程之间相互独立,不需要加锁,减少了使用锁对性能造成影响,同时降低编程的复杂度,降低开发成本。其次,采用独立的进程,可以让进程互相之间不会影响 ,如果一个进程发生异常退出时,其它进程正常工作, master 进程则很快启动新的 worker 进程,确保服务不会中断,从而将风险降到最低。
缺点是操作系统生成一个子进程需要进行 内存复制等操作,在资源和时间上会产生一定的开销。当有大量请求时,会导致系统性能下降 。
每个工作进程 使用 异步非阻塞方式 ,可以处理 多个客户端请求 。
当某个 工作进程 接收到客户端的请求以后,调用 IO 进行处理,如果不能立即得到结果,就去 处理其他请求 (即为 非阻塞 );而 客户端 在此期间也 无需等待响应 ,可以去处理其他事情(即为 异步 )。
当 IO 返回时,就会通知此 工作进程 ;该进程得到通知,暂时 挂起 当前处理的事务去 响应客户端请求 。
Nginx服务器的最佳用法是在网络上部署动态HTTP内容,使用SCGI、WSGI应用程序服务器、用于脚本的FastCGI处理程序。它还可以作为负载均衡器。
主程序 Master process 启动后,通过一个 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 实现的管道来实现。
首先,代理服务器一般指局域网内部的机器通过代理服务器发送请求到互联网上的服务器,代理服务器一般作用在客户端。例如:GoAgent软件。我们的客户端在进行操作的时候,我们使用的正是正向代理,通过正向代理的方式,在我们的客户端运行一个软件,将我们的HTTP请求转发到其他不同的服务器端,实现请求的分发。
反向代理服务器作用在服务器端,它在服务器端接收客户端的请求,然后将请求分发给具体的服务器进行处理,然后再将服务器的相应结果反馈给客户端。Nginx就是一个反向代理服务器软件。
从上图可以看出:客户端必须设置正向代理服务器,当然前提是要知道正向代理服务器的IP地址,还有代理程序的端口。反向代理正好与正向代理相反,对于客户端而言代理服务器就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端。
ngx_http_upstream_module用于定义可通过fastcgi传递、proxy传递、uwsgi传递、memcached传递和scgi传递指令来引用的服务器组。
Stub_status指令:该指令用于了解Nginx当前状态的当前状态,如当前的活动连接,接受和处理当前读/写/等待连接的总数;
Sub_filter指令:它用于搜索和替换响应中的内容,并快速修复陈旧的数据;
upstream backend {
server 192.168.1.100:8080;
server 192.168.1.101:8080;
}
weight
指定权重。适用于后端服务器性能不一致的情况。upstream backend {
server 192.168.1.102 weight=10;
server 192.168.1.103 weight=20;
}
upstream backend {
ip_hash;
server 192.168.1.104:8080;
server 192.168.1.105:8080;
}
upstream backend {
least_conn;
server 192.168.1.106:8080;
server 192.168.1.107:8080;
}
upstream backend {
least_time header | last_byte [inflight];
server 192.168.1.108:8080;
server 192.168.1.109:8080;
}
# 如果指定 `header`,则使用 `$upstream_header_time`(请求头的响应时间)作为响应时间的判断依据
# 如果指定 `last_byte`,则使用 `$upstream_response_time`(请求响应时间)作为响应时间的判断依据.如果同时指定了 `inflight` 参数,则不完整的请求也会计算在内.
hash key
自定义 hash 键轮询key
的值进行哈希从而选择后端服务器,key 可以包含文本,变量及其组合。upstream bakend {
hash <key> [consistent];
server 172.16.1.2:8080;
server 172.16.1.3:8080;
}
# 如果指定了 `consistent` 参数,则将使用 ketama 一致性哈希算法.
# 该算法可以确保向组中添加服务器或从组中删除时,只有很少的键被重新映射到与原来不同的服务器.有助于缓存服务器获得更高的缓存命中率
nginx version >=1.15.1
将请求随机转发到后端服务器,同时考虑后端服务器权重
upstream bakend {
random [two [method]];
server 172.16.1.2:8080;
server 172.16.1.3:8080;
}
# 可选的 `two` 参数随机选择两个后端服务器,然后使用指定的 `method` 选择一个后端服务器.默认方法是 `least_conn`,将请求传递给活动连接数最少的服务器
auto
根据系统 CPU 自动配置,可以通过 worker_cpu_affinity
将 nginx worker 进程绑定到不同的 CPU 上,避免多个进程竞争同一个 CPU 资源,充分利用 CPU 多核资源。worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
ulimit
设置打开的文件数。或者在 /etc/security/limits.conf
, /etc/security/limits.d/nginx.conf
进行配置。配置如下:ulimit -n $max_open_files # 设置系统最大打开文件数
cat /etc/security/limits.d/nginx.conf
* soft nproc 131072
* hard nproc 131072
* soft nofile 131072
* hard nofile 131072
events {
use epoll;
worker_connections 15000;
worker_rlimit_nofile 65535;
}
http {
gzip on;
sendfile on;
}
keepalive_timeout
参数用于设置客户端连接保持会话的超时时间,超过这个时间服务器会关闭该连接client_header_timeout
参数用于设置读取客户端请求头数据的超时时间。如果读取请求头超时,服务器将返回 “Request time out (408)” 错误client_body_timeout
参数用于设置读取客户端请求主体数据的超时时间。如果请求体超时,服务器将返回 "Request time out (408)"错误send_timeout
参数用于指定响应客户端的超时时间,如果超时,nginx 将会关闭连接http {
# 在大并发时,需要合理调小如下参数
keepalive_timeout 65;
client_header_timeout 15;
client_body_timeout 15;
send_timeout 25;
}
# 配置nginx请求体限制(nginx默认的request body为1M,远远小于我们上传文件的大小,所以需要配置为100M)
client_max_body_size 100m;
http {
limit_conn_zone $binary_remote_addr zone=addr:10m; # 设置 $binary_remote_addr 客户端地址的地址区域为 10m
limit_conn ${zone} ${num}; # 设置指定 zone 的最大连接数
limit_conn_status ${http_code}; # 设置超过最大连接数的状态码,默认 503
}
limit_req_zone 参数用于为共享内存区域设置参数
limit_req 参数用于设置指定内存区域的最大连接数
limit_req_status 参数用于设置超过最大连接数的请求状态码
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
# 设置 $binary_remote_addr 客户端地址的地址区域为 10m,平均请求速率最大为 1r/s
limit_req zone=${zone} burst=${num}; # 设置指定 zone 的最大并发请求
limit_req_status ${http_code}; # 设置超过最大请求数的状态码,默认 503
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js|css)$ {
expires 3650d;
}
nginx: [emerg] could not build the server_names_hash, you should increase server_names_hash_bucket_size: 64
nginx: configuration file /usr/local/nginx/conf/nginx.conf test failed
此时需要对 http 配置段 server_names_hash_bucket_size
进行调整,如下:
# ngx_http_core_module
http {
server_names_hash_bucket_size 512;
}
隐藏 nginx 响应头 server 信息
在配置文件 http
配置段中添加 server_tokens off
; 配置项,即可隐藏 Nginx 版本号
只允许指定客户端访问
http
、server
、location
、limit_except
配置段中location / {
allow 192.168.1.1/24;
deny all;
}
location ~ .*\.(gif|jpg|jpeg|png|bm|swf|flv|rar|zip|gz|bz2)$ {
valid_referers none blocked *.test.com *.abc.com; # 表示这些地址可以访问上面的媒体资源
if ($invalid_referer) {
# 如果不是从以上域名访问,则返回 403
return 403
}
error_page
参数可对指定错误码返回的页面location / {
root html/www;
index index.html index.htm;
error_page 400 401 402 403 404 405 408 410 412 413 414 415 500 501 502 503 506 = http://www.xxxx.com/error.html;
}
kill 信号 | 解释 | nginx 命令 |
---|---|---|
TERM(15), INT(2) | 快速停止 | nginx -s stop |
QUIT(3) | 优雅的停止 | nginx -s quit |
HUP(1) | 优雅的启动新的进程重新加载配置文件 | nginx -s reload |
USR1(10) | 日志文件滚动 | nginx -s reopen |
USER2(12) | 升级二进制可执行文件 | - |
WINCH(28) | 优雅的关闭 worker 进程 |