你真的懂Nginx吗?从小白到高手的生产实战全攻略
最近在面试一些运维工程师的时候,问到nginx相关的问题,发现很多人只会简单的安装启动,真正深入的配置和优化几乎答不出来。今天我就来聊聊nginx这个神器,从基础安装到生产环境的深度优化,保证让你看完之后对nginx有个全新的认识。
说实话,nginx在现在的互联网架构中几乎是必不可少的组件。无论是做反向代理、负载均衡、还是静态文件服务,nginx都表现得相当出色。我在生产环境中使用nginx也有好几年了,踩过不少坑,今天把这些经验分享给大家。
从零开始:Ubuntu 22.04上的nginx安装
我们先从最基础的安装开始。Ubuntu 22.04默认源里的nginx版本可能不是最新的,建议直接使用官方源:
# 更新系统包
sudo apt update
# 安装nginx官方源的依赖
sudo apt install curl gnupg2 ca-certificates lsb-release
# 添加nginx官方源
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add -
echo "deb http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
# 更新源并安装
sudo apt update
sudo apt install nginx安装完成后,nginx的主要文件路径:
- 主配置文件:
/etc/nginx/nginx.conf - 虚拟主机配置:
/etc/nginx/conf.d/ - 默认网站根目录:
/var/www/html/ - 日志文件:
/var/log/nginx/
启动nginx服务:
sudo systemctl start nginx
sudo systemctl enable nginx
sudo systemctl status nginxnginx的核心架构和工作原理
nginx采用的是master-worker多进程模型。master进程负责读取配置文件、管理worker进程,而worker进程才是真正处理客户端请求的。这种设计让nginx在高并发场景下表现优异。
每个worker进程都是单线程的,通过异步非阻塞的方式处理多个连接。这就是为什么nginx能用很少的内存处理大量并发连接的原因。我在一台4核8G的服务器上,nginx轻松处理几万并发连接,CPU使用率都不到20%。
worker进程数量的设置是个学问。一般建议设置为CPU核心数,但也要根据具体应用场景调整:
# 自动检测CPU核心数
worker_processes auto;
# 或者手动指定
worker_processes 4;负载均衡:四成负载 vs 七成负载的真实差别
很多人都知道nginx可以做负载均衡,但是对于不同负载水平下的表现差异却不太清楚。我来详细说说四成负载和七成负载的区别。
先看一个简单的负载均衡配置:
upstream backend_servers {
server 192.168.1.10:8080 weight=3;
server 192.168.1.11:8080 weight=2;
server 192.168.1.12:8080 weight=1;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://backend_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}四成负载的特点:
- 响应时间稳定,基本在50-100ms之间
- CPU使用率在30-40%
- 内存使用平稳
- 连接处理游刃有余
- 出现问题时有充足的缓冲空间
七成负载的特点:
- 响应时间开始有波动,可能出现200-500ms的情况
- CPU使用率在60-70%
- 内存使用率较高,可能出现swap
- 连接排队现象明显
- 一旦有突发流量很容易造成服务不稳定
我在生产环境中的经验是,长期保持七成负载是很危险的。曾经有次促销活动,服务器平时跑在六成负载,结果活动开始后瞬间飙到九成,直接导致服务不可用。所以现在我们的策略是平时保持在四成左右,给突发流量留足缓冲。
负载均衡算法的选择也很重要:
upstream backend_servers {
# 轮询(默认)
server 192.168.1.10:8080;
server 192.168.1.11:8080;
# 或者使用ip_hash,同一IP总是访问同一台服务器
# ip_hash;
# 或者最少连接
# least_conn;
}nginx的核心功能模块详解
nginx的模块化设计是它的一大优势。我们来看看生产环境中最常用的几个模块:
1. HTTP核心模块
这是nginx最基础的模块,处理HTTP请求:
http {
# 隐藏nginx版本信息
server_tokens off;
# 设置客户端请求体大小限制
client_max_body_size 50m;
# 设置超时时间
client_header_timeout 60s;
client_body_timeout 60s;
send_timeout 60s;
# keepalive连接
keepalive_timeout 65;
keepalive_requests 1000;
}2. Gzip压缩模块
这个模块能显著减少传输数据量:
http {
gzip on;
gzip_vary on;
gzip_min_length 1000;
gzip_comp_level 6;
gzip_types
application/atom+xml
application/geo+json
application/javascript
application/x-javascript
application/json
application/ld+json
application/manifest+json
application/rdf+xml
application/rss+xml
application/xhtml+xml
application/xml
font/eot
font/otf
font/ttf
image/svg+xml
text/css
text/javascript
text/plain
text/xml;
}我测试过,开启gzip后,CSS和JS文件能压缩到原来的20-30%,效果相当明显。
3. SSL/TLS模块
现在HTTPS已经是标配了:
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
# SSL优化配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# SSL会话缓存
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# HSTS
add_header Strict-Transport-Security "max-age=63072000" always;
}4. 限流模块
这个在防DDOS攻击时特别有用:
http {
# 定义限制规则
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
server {
location /login {
limit_req zone=login burst=3 nodelay;
# 其他配置...
}
location /api/ {
limit_req zone=api burst=20 nodelay;
# 其他配置...
}
}
}5. 实时状态模块
监控nginx运行状态:
server {
listen 8080;
server_name localhost;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
allow 192.168.1.0/24;
deny all;
}
}nginx升级:从新手到专家的完整升级指南
nginx升级是运维工作中经常遇到的场景,特别是当有安全漏洞或者需要新功能时。很多人担心升级会影响线上服务,其实掌握了正确的方法,nginx升级可以做到完全不停机。
升级前的准备工作
在开始升级之前,必须做好充分的准备。我吃过没准备充分的亏,有一次直接升级导致配置不兼容,服务直接挂了半小时。
首先要备份当前的nginx配置:
# 备份配置文件
sudo cp -r /etc/nginx /etc/nginx.backup.$(date +%Y%m%d)
# 备份可执行文件
sudo cp /usr/sbin/nginx /usr/sbin/nginx.backup.$(date +%Y%m%d)
# 查看当前版本和编译参数
nginx -V记录当前版本的编译参数特别重要,新版本需要保持相同的编译选项才能保证兼容性。
方法一:平滑升级(生产环境推荐)
这是生产环境中最佳的升级方式,可以做到完全不停机。nginx支持热升级,原理是通过信号机制实现新老进程的平稳过渡。
步骤1:下载并编译新版本
# 下载新版本源码(以1.24.0为例)
cd /opt
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar -zxf nginx-1.24.0.tar.gz
cd nginx-1.24.0
# 使用与当前版本相同的编译参数
nginx -V
# 使用相同参数编译新版本
./configure --prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_gzip_static_module
make
# 注意:不要执行 make install步骤2:备份旧版本并安装新版本
# 备份旧版本的可执行文件
sudo mv /usr/sbin/nginx /usr/sbin/nginx.old
# 复制新版本的可执行文件
sudo cp objs/nginx /usr/sbin/nginx
# 测试新版本配置
sudo nginx -t步骤3:发送平滑升级信号
这是关键步骤,通过USR2信号启动新的master进程:
# 获取当前nginx主进程PID
sudo cat /var/run/nginx.pid
# 发送USR2信号启动新的master进程
sudo kill -USR2 `cat /var/run/nginx.pid`此时会看到系统中同时存在两个nginx master进程,新的master进程会创建新的worker进程。
步骤4:平滑关闭旧进程
# 向老的master进程发送QUIT信号,让它优雅关闭worker进程
sudo kill -QUIT `cat /var/run/nginx.pid.oldbin`这时候老的worker进程会处理完当前请求后优雅退出,新的worker进程接管所有新请求。
如果升级过程中发现问题,可以快速回滚:
# 向新的master进程发送QUIT信号
sudo kill -QUIT `cat /var/run/nginx.pid`
# 向老的master进程发送HUP信号重新加载
sudo kill -HUP `cat /var/run/nginx.pid.oldbin`
# 恢复旧版本文件
sudo mv /usr/sbin/nginx.old /usr/sbin/nginx方法二:使用官方源升级
这是我比较推荐的方法,既方便又能获得最新版本:
# 添加nginx官方源(如果之前没有添加)
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add -
echo "deb http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
# 更新并升级
sudo apt update
sudo apt upgrade nginx
# 重启服务
sudo systemctl restart nginx生产环境常见应用场景
根据我这几年的经验,nginx在生产环境中主要有这几种应用场景:
1. 反向代理场景
这是最常见的用法,nginx作为前端代理,后端跑应用服务:
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 代理超时设置
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}2. 动静分离场景
静态文件直接由nginx处理,动态请求转发给应用服务器:
server {
listen 80;
server_name www.example.com;
root /var/www/html;
# 静态文件处理
location ~* \.(jpg|jpeg|png|gif|css|js|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
# 动态请求转发
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}3. API网关场景
nginx作为API网关,处理路由、认证、限流等:
server {
listen 80;
server_name api.example.com;
# 用户服务
location /api/user/ {
proxy_pass http://user_service_backend/;
include proxy_params;
}
# 订单服务
location /api/order/ {
proxy_pass http://order_service_backend/;
include proxy_params;
}
# 支付服务
location /api/payment/ {
proxy_pass http://payment_service_backend/;
include proxy_params;
# 支付接口需要更严格的限流
limit_req zone=payment burst=5 nodelay;
}
}4. 缓存代理场景
利用nginx的缓存功能减轻后端压力:
http {
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;
server {
listen 80;
server_name cache.example.com;
location / {
proxy_cache my_cache;
proxy_cache_valid 200 302 60m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout invalid_header updating;
proxy_pass http://backend;
add_header X-Cache-Status $upstream_cache_status;
}
}
}性能优化的实战经验
性能优化这块是重点,也是很多人容易忽略的地方。
worker进程优化
# 根据CPU核心数设置
worker_processes auto;
# 绑定worker进程到CPU核心
worker_cpu_affinity auto;
# 单个worker进程的最大连接数
events {
worker_connections 65535;
use epoll;
multi_accept on;
}内存优化
http {
# 调整buffer大小
client_body_buffer_size 128k;
client_header_buffer_size 32k;
large_client_header_buffers 4 64k;
# 输出buffer
output_buffers 1 32k;
postpone_output 1460;
}文件描述符优化
# nginx.conf中
worker_rlimit_nofile 65535;
events {
worker_connections 65535;
}还需要修改系统限制:
# /etc/security/limits.conf
nginx soft nofile 65535
nginx hard nofile 65535
# /etc/systemd/system/nginx.service.d/override.conf
[Service]
LimitNOFILE=65535日志优化
生产环境中,日志写入也会影响性能:
http {
# 关闭不必要的访问日志
access_log off;
# 或者使用buffer
access_log /var/log/nginx/access.log combined buffer=64k flush=5s;
# 错误日志级别设置
error_log /var/log/nginx/error.log warn;
}常见面试问题及答案
作为一个经常面试别人的人,我总结了一些nginx相关的高频面试问题:
Q: nginx和apache的区别?
A: nginx采用异步非阻塞的事件驱动模型,内存占用小,并发能力强;apache采用同步阻塞模型,每个请求都需要一个进程或线程处理。在高并发场景下,nginx的性能明显优于apache。
Q: nginx如何实现负载均衡?
A: nginx通过upstream模块实现负载均衡,支持轮询、ip_hash、least_conn等多种算法。还可以设置权重、备份服务器等。
Q: nginx如何处理高并发?
A: 主要通过以下几点:
- 事件驱动的异步非阻塞模型
- master-worker多进程架构
- 内存池和连接池复用
- sendfile零拷贝技术
Q: 如何优化nginx性能?
A: 这个问题我前面已经详细讲过了,主要包括worker进程优化、内存优化、文件描述符优化等。
Q: nginx如何实现动静分离?
A: 通过location匹配不同的请求,静态文件直接由nginx处理,动态请求转发给后端应用服务器。
Q: nginx如何进行平滑升级?
A: 通过USR2信号启动新的master进程,然后用QUIT信号优雅关闭旧的worker进程,整个过程不会中断服务。
故障排查经验
在生产环境中,nginx难免会遇到各种问题。我分享几个常见的故障和排查方法:
1. 502 Bad Gateway
这是最常见的错误,通常是后端服务有问题:
# 检查后端服务是否正常
curl -I http://backend_server:port
# 检查nginx错误日志
tail -f /var/log/nginx/error.log
# 检查upstream配置
nginx -t2. 504 Gateway Timeout
通常是后端响应超时:
# 增加超时时间
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;3. 413 Request Entity Too Large
请求体过大:
# 调整客户端请求体大小限制
client_max_body_size 100m;4. 性能问题排查
# 查看nginx进程状态
ps aux | grep nginx
# 查看连接状态
ss -tuln | grep :80
# 查看nginx状态
curl http://localhost:8080/nginx_status安全配置要点
生产环境的nginx安全配置也很重要:
http {
# 隐藏nginx版本
server_tokens off;
# 防止点击劫持
add_header X-Frame-Options DENY;
# XSS保护
add_header X-XSS-Protection "1; mode=block";
# 内容类型嗅探保护
add_header X-Content-Type-Options nosniff;
# CSP策略
add_header Content-Security-Policy "default-src 'self'";
}
server {
# 禁止访问隐藏文件
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# 限制访问敏感文件
location ~* \.(conf|htaccess|htpasswd)$ {
deny all;
}
}监控和日志分析
生产环境必须要有完善的监控:
# 自定义日志格式
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time';
access_log /var/log/nginx/access.log detailed;可以结合ELK stack进行日志分析,或者使用简单的脚本:
#!/bin/bash
# 分析nginx访问日志脚本
LOG_FILE="/var/log/nginx/access.log"
echo "=== Top 10 访问IP ==="
awk '{print $1}' $LOG_FILE | sort | uniq -c | sort -nr | head -10
echo "=== Top 10 请求页面 ==="
awk '{print $7}' $LOG_FILE | sort | uniq -c | sort -nr | head -10
echo "=== HTTP状态码统计 ==="
awk '{print $9}' $LOG_FILE | sort | uniq -c | sort -nr写在最后
nginx确实是个非常强大的工具,但要真正用好它需要大量的实践经验。我在生产环境中使用nginx这几年,从最开始的简单配置到现在的深度优化,踩了不少坑,也积累了很多经验。
特别是nginx的平滑升级功能,这个真的太赞了。记得以前用apache的时候,每次升级都要停服务,现在用nginx可以做到完全无感升级。不过要注意,升级前一定要充分测试,备份工作也要做好。
希望这篇文章能帮到正在学习nginx的朋友们。nginx的学习没有捷径,只有多动手、多实践、多思考。遇到问题不要怕,每个坑都是成长的机会。
记住一点:生产环境的稳定性永远比性能更重要。优化是好事,但不要为了追求极致性能而牺牲稳定性。四成负载虽然看起来"浪费"了资源,但关键时刻能救命。
如果你觉得这篇文章对你有帮助,别忘了点赞转发,让更多的朋友看到。有什么问题也欢迎在评论区讨论,我会尽量回复。
公众号:运维躬行录
个人博客:躬行笔记