最近在面试一些运维工程师的时候问到nginx相关的问题发现很多人只会简单的安装启动真正深入的配置和优化几乎答不出来。今天我就来聊聊nginx这个神器从基础安装到生产环境的深度优化保证让你看完之后对nginx有个全新的认识。说实话nginx在现在的互联网架构中几乎是必不可少的组件。无论是做反向代理、负载均衡、还是静态文件服务nginx都表现得相当出色。我在生产环境中使用nginx也有好几年了踩过不少坑今天把这些经验分享给大家。从零开始Ubuntu 22.04上的nginx安装我们先从最基础的安装开始。Ubuntu 22.04默认源里的nginx版本可能不是最新的建议直接使用官方源# 更新系统包sudoaptupdate# 安装nginx官方源的依赖sudoaptinstallcurlgnupg2 ca-certificates lsb-release# 添加nginx官方源curl-fsSLhttps://nginx.org/keys/nginx_signing.key|sudoapt-keyadd-echodeb http://nginx.org/packages/ubuntu$(lsb_release-cs)nginx|sudotee/etc/apt/sources.list.d/nginx.list# 更新源并安装sudoaptupdatesudoaptinstallnginx安装完成后nginx的主要文件路径主配置文件/etc/nginx/nginx.conf虚拟主机配置/etc/nginx/conf.d/默认网站根目录/var/www/html/日志文件/var/log/nginx/启动nginx服务sudosystemctl start nginxsudosystemctlenablenginxsudosystemctl 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 weight3; server 192.168.1.11:8080 weight2; server 192.168.1.12:8080 weight1; } 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/atomxml application/geojson application/javascript application/x-javascript application/json application/ldjson application/manifestjson application/rdfxml application/rssxml application/xhtmlxml application/xml font/eot font/otf font/ttf image/svgxml 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-age63072000 always; }4. 限流模块这个在防DDOS攻击时特别有用http { # 定义限制规则 limit_req_zone $binary_remote_addr zonelogin:10m rate1r/s; limit_req_zone $binary_remote_addr zoneapi:10m rate10r/s; server { location /login { limit_req zonelogin burst3 nodelay; # 其他配置... } location /api/ { limit_req zoneapi burst20 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配置# 备份配置文件sudocp-r/etc/nginx /etc/nginx.backup.$(date%Y%m%d)# 备份可执行文件sudocp/usr/sbin/nginx /usr/sbin/nginx.backup.$(date%Y%m%d)# 查看当前版本和编译参数nginx-V记录当前版本的编译参数特别重要新版本需要保持相同的编译选项才能保证兼容性。方法一平滑升级生产环境推荐这是生产环境中最佳的升级方式可以做到完全不停机。nginx支持热升级原理是通过信号机制实现新老进程的平稳过渡。步骤1下载并编译新版本# 下载新版本源码以1.24.0为例cd/optwgethttp://nginx.org/download/nginx-1.24.0.tar.gztar-zxfnginx-1.24.0.tar.gzcdnginx-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_modulemake# 注意不要执行 make install步骤2备份旧版本并安装新版本# 备份旧版本的可执行文件sudomv/usr/sbin/nginx /usr/sbin/nginx.old# 复制新版本的可执行文件sudocpobjs/nginx /usr/sbin/nginx# 测试新版本配置sudonginx-t步骤3发送平滑升级信号这是关键步骤通过USR2信号启动新的master进程# 获取当前nginx主进程PIDsudocat/var/run/nginx.pid# 发送USR2信号启动新的master进程sudokill-USR2cat/var/run/nginx.pid此时会看到系统中同时存在两个nginx master进程新的master进程会创建新的worker进程。步骤4平滑关闭旧进程# 向老的master进程发送QUIT信号让它优雅关闭worker进程sudokill-QUITcat/var/run/nginx.pid.oldbin这时候老的worker进程会处理完当前请求后优雅退出新的worker进程接管所有新请求。如果升级过程中发现问题可以快速回滚# 向新的master进程发送QUIT信号sudokill-QUITcat/var/run/nginx.pid# 向老的master进程发送HUP信号重新加载sudokill-HUPcat/var/run/nginx.pid.oldbin# 恢复旧版本文件sudomv/usr/sbin/nginx.old /usr/sbin/nginx方法二使用官方源升级这是我比较推荐的方法既方便又能获得最新版本# 添加nginx官方源如果之前没有添加curl-fsSLhttps://nginx.org/keys/nginx_signing.key|sudoapt-keyadd-echodeb http://nginx.org/packages/ubuntu$(lsb_release-cs)nginx|sudotee/etc/apt/sources.list.d/nginx.list# 更新并升级sudoaptupdatesudoaptupgrade nginx# 重启服务sudosystemctl 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 zonepayment burst5 nodelay; } }4. 缓存代理场景利用nginx的缓存功能减轻后端压力http { proxy_cache_path /var/cache/nginx levels1:2 keys_zonemy_cache:10m max_size1g inactive60m; 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.confnginx soft nofile65535nginx hard nofile65535# /etc/systemd/system/nginx.service.d/override.conf[Service]LimitNOFILE65535日志优化生产环境中日志写入也会影响性能http { # 关闭不必要的访问日志 access_log off; # 或者使用buffer access_log /var/log/nginx/access.log combined buffer64k flush5s; # 错误日志级别设置 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-Ihttp://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进程状态psaux|grepnginx# 查看连接状态ss-tuln|grep:80# 查看nginx状态curlhttp://localhost:8080/nginx_status安全配置要点生产环境的nginx安全配置也很重要http { # 隐藏nginx版本 server_tokens off; # 防止点击劫持 add_header X-Frame-Options DENY; # XSS保护 add_header X-XSS-Protection 1; modeblock; # 内容类型嗅探保护 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.logecho Top 10 访问IP awk{print $1}$LOG_FILE|sort|uniq-c|sort-nr|head-10echo Top 10 请求页面 awk{print $7}$LOG_FILE|sort|uniq-c|sort-nr|head-10echo HTTP状态码统计 awk{print $9}$LOG_FILE|sort|uniq-c|sort-nr写在最后nginx确实是个非常强大的工具但要真正用好它需要大量的实践经验。我在生产环境中使用nginx这几年从最开始的简单配置到现在的深度优化踩了不少坑也积累了很多经验。特别是nginx的平滑升级功能这个真的太赞了。记得以前用apache的时候每次升级都要停服务现在用nginx可以做到完全无感升级。不过要注意升级前一定要充分测试备份工作也要做好。希望这篇文章能帮到正在学习nginx的朋友们。nginx的学习没有捷径只有多动手、多实践、多思考。遇到问题不要怕每个坑都是成长的机会。记住一点生产环境的稳定性永远比性能更重要。优化是好事但不要为了追求极致性能而牺牲稳定性。四成负载虽然看起来浪费了资源但关键时刻能救命。如果你觉得这篇文章对你有帮助别忘了点赞转发让更多的朋友看到。有什么问题也欢迎在评论区讨论我会尽量回复。公众号运维躬行录个人博客躬行笔记