Nginx 常见面试题总结
1 说一下你对 Nginx 的认识?
Nginx—Ngine X,是一款免费的、自由的、开源的、高性能HTTP服务器和反向代理服务器;也是一个IMAP、POP3、SMTP代理服务器;Nginx以其高性能、稳定性、丰富的功能、简单的配置和低资源消耗而闻名。
也就是说Nginx本身就可以托管网站(类似于Tomcat一样),进行Http服务处理,也可以作为反向代理服务器 、负载均衡器和HTTP缓存。
Nginx 解决了服务器的C10K(就是在一秒之内连接客户端的数目为10k即1万)问题。它的设计不像传统的服务器那样使用线程处理请求,而是一个更加高级的机制—事件驱动机制,是一种异步事件驱动结构
2 列举 Nginx 的一些特性?
- 跨平台:可以在大多数Unix like 系统编译运行。而且也有Windows的移植版本。
配置异常简单:非常的简单,易上手。 - 非阻塞、高并发连接:数据复制时,磁盘I/O的第一阶段是非阻塞的。官方测试能支持5万并发连接,实际生产中能跑2~3万并发连接数(得益于Nginx采用了最新的epoll事件处理模型(消息队列)。
- Nginx代理和后端Web服务器间无需长连接;
- Nginx接收用户请求是异步的,即先将用户请求全部接收下来,再一次性发送到后端Web服务器,极大减轻后端Web服务器的压力。
- 发送响应报文时,是边接收来自后端Web服务器的数据,边发送给客户端。
- 网络依赖性低,理论上只要能够ping通就可以实施负载均衡,而且可以有效区分内网、外网流量。
- 支持内置服务器检测。Nginx能够根据应用服务器处理页面返回的状态码、超时信息等检测服务器是否出现故障,并及时返回错误的请求重新提交到其它节点上。
- 此外还有内存消耗小、成本低廉(比F5硬件负载均衡器廉价太多)、节省带宽、稳定性高等特点。
3 你知道 Nginx 与 Apache 的不同之处吗?
4 请解释 Nginx 如何处理 HTTP 请求的?
Nginx 是一个高性能的 Web 服务器,能够同时处理大量的并发请求。它结合多进程机制和异步机制 ,异步机制使用的是异步非阻塞方式 ,接下来就给大家介绍一下 Nginx 的多线程机制和异步非阻塞机制 。
多进程机制
服务器每当收到一个客户端时,就有 服务器主进程 ( master process )生成一个 子进程( worker process )出来和客户端建立连接进行交互,直到连接断开,该子进程就结束了。
使用进程的好处是各个进程之间相互独立,不需要加锁,减少了使用锁对性能造成影响,同时降低编程的复杂度,降低开发成本。其次,采用独立的进程,可以让进程互相之间不会影响 ,如果一个进程发生异常退出时,其它进程正常工作, master 进程则很快启动新的 worker 进程,确保服务不会中断,从而将风险降到最低。
缺点是操作系统生成一个子进程需要进行 内存复制等操作,在资源和时间上会产生一定的开销。当有大量请求时,会导致系统性能下降 。
异步非阻塞机制
每个工作进程 使用 异步非阻塞方式 ,可以处理 多个客户端请求 。
当某个 工作进程 接收到客户端的请求以后,调用 IO 进行处理,如果不能立即得到结果,就去 处理其他请求 (即为 非阻塞 );而 客户端 在此期间也 无需等待响应 ,可以去处理其他事情(即为 异步 )。
当 IO 返回时,就会通知此 工作进程 ;该进程得到通知,暂时 挂起 当前处理的事务去 响应客户端请求 。
5 请列举 Nginx 服务器的最佳用途?
Nginx服务器的最佳用法是在网络上部署动态HTTP内容,使用SCGI、WSGI应用程序服务器、用于脚本的FastCGI处理程序。它还可以作为负载均衡器。
6 请解释 Nginx 服务器上的 Master 和 Worker 进程分别是什么?
主程序 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 实现的管道来实现。
7 请解释代理设计中的正向代理和反向代理?
首先,代理服务器一般指局域网内部的机器通过代理服务器发送请求到互联网上的服务器,代理服务器一般作用在客户端。
反向代理服务器作用在服务器端,它在服务器端接收客户端的请求,然后将请求分发给具体的服务器进行处理,然后再将服务器的相应结果反馈给客户端。Nginx就是一个反向代理服务器软件。
从上图可以看出:客户端必须设置正向代理服务器,当然前提是要知道正向代理服务器的IP地址,还有代理程序的端口。反向代理正好与正向代理相反,对于客户端而言代理服务器就像是原始服务器,并且客户端不需要进行任何特别的设置。客户端向反向代理的命名空间(name-space)中的内容发送普通请求,接着反向代理将判断向何处(原始服务器)转交请求,并将获得的内容返回给客户端。
8 请解释 ngx_http_upstream_module 的作用是什么?
ngx_http_upstream_module用于定义可通过fastcgi传递、proxy传递、uwsgi传递、memcached传递和scgi传递指令来引用的服务器组。
9 请陈述 stub_status 和 sub_filter 指令的作用是什么?
Stub_status指令:该指令用于了解Nginx当前状态的当前状态,如当前的活动连接,接受和处理当前读/写/等待连接的总数;
Sub_filter指令:它用于搜索和替换响应中的内容,并快速修复陈旧的数据;
10 Nginx 支持的负载均衡算法有哪些?分别有哪些应用场景?
- rr (round robin) 轮询
依次将请求分配到各个后端服务器中,是 Nginx 默认的负载均衡方式。适用于后端服务器性能一致的情况。
upstream backend {
server 192.168.1.100:8080;
server 192.168.1.101:8080;
}
- wrr (weight round robin) 加权轮询
加权轮询,根据权重比率分发请求到各个后端服务器中。使用weight
指定权重。适用于后端服务器性能不一致的情况。
upstream backend {
server 192.168.1.102 weight=10;
server 192.168.1.103 weight=20;
}
- ip_has 客户端 IP 哈希
根据客户端 IP 地址的 hash 值将请求发送到后端服务器。可保证来自同一个客户端的请求被转发到固定的后端服务器中,可解决 session 问题。
upstream backend {
ip_hash;
server 192.168.1.104:8080;
server 192.168.1.105:8080;
}
- least_conn 最小连接数
根据后端服务器的连接数进行分发,同时考虑后端服务器的权重
upstream backend {
least_conn;
server 192.168.1.106:8080;
server 192.168.1.107:8080;
}
- least_time 最小平均响应时间
根据后端服务器的平均响应时间以及活动连接数进行分发,同时考虑后端服务器的权重
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 一致性哈希算法.
# 该算法可以确保向组中添加服务器或从组中删除时,只有很少的键被重新映射到与原来不同的服务器.有助于缓存服务器获得更高的缓存命中率
- random 完全随机
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`,将请求传递给活动连接数最少的服务器
11 Nginx location 匹配的顺序是什么?
12 Nginx servername 匹配的顺序是什么?
- 精确 server_name 匹配
- 以 * 通配符开始的泛域名
- 以 * 通配符结束的泛域名
- 匹配正则表达式
- listen 指定的 default server_name
- http 模块下的第一个 server 配置块中的 server_name
13 Nginx 重新加载配置文件的流程是什么?
- 向 master 发送 reload 信号
- master 校验配置文件语法
- master 进程打开新的监听端口
- master 进程用新配置启动新的 worker 子进程
- master 进程向 worker 子进程发送 quit 信号
- old worker 进程关闭监听句柄,处理完当前连接后结束进程
14 Nginx 调优有哪些?(重点)
- 合理设置 Nginx worker 进程数,并绑定到不同的 CPU 上
一般情况下,应将 worker 进程数设置为 CPU 核数,或设置为auto
根据系统 CPU 自动配置,可以通过worker_cpu_affinity
将 nginx worker 进程绑定到不同的 CPU 上,避免多个进程竞争同一个 CPU 资源,充分利用 CPU 多核资源。
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
- 使用 epoll 事件驱动模型,合理设置单个进程的最大连接数及最大打开文件数量
进程最大连接数受系统最大打开文件数限制,因此需要使用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;
}
- 开启高效文件传输模式,开启或 gzip 压缩
配置段 sendfile 参数用于开启文件高效传输模式
配置段 gzip 参数可用于开启压缩功能
http {
gzip on;
sendfile on;
}
- 优化 Nginx 连接超时时间
配置段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;
}
- 增大发送的消息体的大小
Request Entity Too Large (请求实体过大)
# 配置nginx请求体限制(nginx默认的request body为1M,远远小于我们上传文件的大小,所以需要配置为100M)
client_max_body_size 100m;
- nginx 限制连接和限制请求速率
limit_conn_zone 参数用于为共享内存区域设置参数
limit_conn 参数用于设置指定内存区域的最大连接数
limit_conn_status 参数用于设置超过最大连接数的请求状态码
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
}
- 合理配置 Nginx expires 缓存
expires 参数用于设置用户访问内容的缓存时间。用户会在本地浏览器中缓存这些内容,直到超过缓存时间。多用于配制静态内容
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|js|css)$ {
expires 3650d;
}
- 优化服务器域名的散列表大小
如果在 server_name 中配置了长域名,可能会出现如下错误:
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;
}
15 Nginx 安全?
- 隐藏 nginx 响应头 server 信息
在配置文件http
配置段中添加server_tokens off
; 配置项,即可隐藏 Nginx 版本号 - 只允许指定客户端访问
- allow,deny 参数用于配置可以 / 禁止访问 Nginx 指定内容的客户端。可配置在
http
、server
、location
、limit_except
配置段中
location / {
allow 192.168.1.1/24;
deny all;
}
- 配置 Nginx 防盗链
防盗链:简单地说,就是某些不法网站未经许可,通过在其自身网站程序里非法调用其他网站的资源,然后在自己的网站上显示这些调用的资源,使得被盗链的那一端消耗带宽资源
- 根据 HTTP referer 字段实现防盗链: referer 是 HTTP 的一个首部字段,用于指明用户请求的 URL 是从哪个页面通过链接跳转过来的
- 根据 cookie 实现防盗链: cookie 是服务器贴在客户端身上的 “标签”, 服务器用它来识别客户端
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
}
- nginx错误页面优雅显示
- 使用
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;
}
16 Nginx 常用信号?
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 进程 |