首页 > 服务器    日期:2026-07-20 / 浏览

Nginx 性能优化之三大法宝

动静分离

Web应用中的资源可分为两类:

☆ 动态内容

需后端程序实时生成的数据(如PHP/Java接口返回的JSON、用户登录状态页),通常由应用服务器(如Tomcat、Node.js)处理。

☆ 静态内容

无需后端计算、可直接返回的文件(如图片、CSS/JS、字体文件),由Nginx直接高效处理。

经典配置

server {
    listen 80;
    server_name example.com;
    # 动态请求:转发到后端应用服务器(如Tomcat/Node.js)
    location /api/ {
        proxy_pass http://backend_server:8080/;  # 指向后端服务地址
        proxy_set_header Host $host;             # 传递原始请求头
    }
    # 静态资源:直接由Nginx从本地目录返回
    location ~* \.(jpg|jpeg|png|gif|css|js|woff|woff2|ico)$ {
        root /var/www/static;                   # 静态资源存放目录
        expires 30d;                            # 缓存30天(可选优化)
    }
    # 默认动态请求(如PHP/HTML模板)
    location / {
        proxy_pass http://app_server:3000/;     # 指向应用服务器
    }
}

客户端缓存

告知浏览器获取的信息是在某个区间时间段是有效的,基本格式:

expires 30s; //表示把数据缓存30秒
expires 30m; //表示把数据缓存30分
expires 10h; //表示把数据缓存10小时
expires 3d;  //表示把数据缓存3天

禁止缓存配置说明

add_header Cache-Control no-store;

案例:缓存图片/js/css文件,缓存时间为1天

location ~* \.(jpg|jpeg|gif|png|js|css)$ {
    expires 1d;
    #add_header Cache-Control no-store;
}

开启 Gzip 压缩

压缩文件大小变小了,传输更快了,目前市场上大部分浏览器是支持GZIP的。

IE6以下支持不好,会出现乱码情况。

http://nginx.org/en/docs/http/ngx_http_gzip_module.html

gzip on;                     # 第1行:开启Gzip压缩功能
gzip_min_length 1k;          # 第2行:仅压缩大于1KB的文件(小于1KB的压缩后可能更大,不处理)
gzip_buffers 4 16k;          # 第3行:压缩时使用的缓冲区数量(4个)和大小(每个16KB)
gzip_http_version 1.1;       # 第4行:兼容HTTP/1.1协议(主流浏览器均支持)
gzip_comp_level 5;           # 第5行:压缩级别(1-10),数字越大压缩率越高但CPU消耗越大(推荐5~6)
gzip_types text/plain 
           text/css 
           text/javascript 
           application/javascript 
           application/x-javascript 
           image/jpeg 
           image/gif 
           image/png 
           image/x-ms-bmp;    # 第6行:指定要压缩的文件类型(优先压缩文本和图片)
gzip_vary on;                 # 第7行:在响应头中添加Vary: Accept-Encoding,帮助缓存服务器区分压缩/未压缩版本
gzip_disable "MSIE [1-6]\.";  # 第8行:禁用对IE6及以下版本的Gzip(兼容性问题)

vary 是差异,多样化的意思。
gzip_vary 是 Nginx 配置中的一条指令,它用于控制是否在响应头中设置 Vary: Accept-Encoding 头部。具体来说:
    gzip_vary on;:启用时,Nginx 会在响应头中加入 Vary: Accept-Encoding,表示不同的客户端可能会根据是否支持 gzip 压缩来收到不同的响应内容。这有助于缓存服务器(如 CDN)缓存压缩和未压缩的内容。
    gzip_vary off;:禁用时,Nginx 不会在响应头中加入 Vary: Accept-Encoding,这意味着缓存服务器不会区分压缩与未压缩的内容。这样做通常会减少缓存的复杂性,但可能会导致某些情况缓存不一致。

指令 作用 推荐值/说明
gzip on; 开关Gzip功能 必须为 on才生效
gzip_min_length 1k; 最小压缩文件大小 避免小文件压缩后体积反而增大(默认20B~1k,建议1k~10k)
gzip_buffers 4 16k; 压缩缓冲区配置 4个16KB的缓冲区(根据服务器内存调整)
gzip_http_version 1.1; 兼容的HTTP协议版本 现代浏览器均支持1.1
gzip_comp_level 5; 压缩级别 1(最快但压缩率低)~10(最慢但压缩率高),推荐5~6平衡性能与效果
gzip_types 指定压缩的文件MIME类型 优先压缩文本(如HTML/CSS/JS)、常用图片(如JPEG/PNG)
gzip_vary on; 是否添加Vary头 帮助CDN/代理服务器正确缓存压缩与未压缩版本
gzip_disable "MSIE [1-6]\."; 禁用低版本IE的Gzip IE6对Gzip支持差,可能引发乱码

常见压缩类型:

文本类(.html/.css/.js)

矢量图(.svg)

部分图片(.png/.jpg,但已压缩的图片效果有限)

总结

优化方向 核心目标 关键技术 适用场景
动静分离 提升资源处理效率,降低后端压力 Nginx路由分离(动态→后端,静态→本地/CDN) 所有Web应用(尤其是高并发场景)
客户端缓存 减少重复传输,加速二次访问 expires/Cache-Control控制缓存时间 图片、CSS/JS等长期不变的静态资源
Gzip压缩 减小传输体积,降低带宽消耗 gzip模块压缩文本/图片 文本类资源(HTML/CSS/JS)、未高度压缩的图片

Nginx 日志分析

日志分类

日志类型 默认文件名 核心记录内容 默认存储路径(不同安装方式)
访问日志 access.log 1、$remote_addr $upstream_status $request_time等变量组合(格式可自定义)
2、查看统计用户的访问信息与流量
源码安装:/usr/local/nginx/logs
yum/dnf/apt 安装:/var/log/nginx
错误日志 error.log 1、配置语法错误、进程异常、连接超时等信息,含行号与错误码(如[emerg] bind() failed)
2、错误信息以及重写信息
同上

参考地址:Module ngx_http_log_module

access 访问日志

cat /var/log/nginx/access.log
或者
cat /usr/local/nginx/logs/access.log

日志参数详解

参数

意义

$remote_addr

客户端的ip地址(代理服务器,显示代理服务ip)

$remote_user

用于记录远程客户端的用户名称(一般为“-”)

$time_local

用于记录访问时间和时区

$request

用于记录请求的url以及请求方法

$status

响应状态码,例如:200成功、404页面找不到等

$body_bytes_sent

给客户端发送的文件主体内容字节数

$http_referer

可以记录用户是从哪个链接访问过来的

$http_user_agent

用户所使用的代理(一般为浏览器)

$http_xforwarded_for

可以记录客户端IP,通过代理服务器来记录客户端的IP地址

设置access.log访问日志输出格式与文件路径:

vim /etc/nginx/nginx.conf
或者
vim /usr/local/nginx/conf/nginx.conf
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;

配置完成后,重载Nginx,访问站点,查看access.log日志,可以统计分析用户的流量的相关情况。

nginx -s reload

error 错误日志

作用:用于Nginx排错

error.log,默认记录配置启动错误信息和访问请求错误信息。

cat /var/log/nginx/error.log
或者
cat /usr/local/nginx/logs/error.log

配置error_log:

vim /etc/nginx/nginx.conf
或者
vim /usr/local/nginx/conf/nginx.conf

在配置nginx.conf 的时候,有一项是指定错误日志的,默认情况下你不指定也没有关系。

但有时出现问题时,是有必要记录一下错误日志的,方便我们排查问题。

参考地址:https://nginx.org/en/docs/ngx_core_module.html#error_log

error_log 级别分为 debug, info, notice, warn, error, crit(从低到高)。

级别 含义 适用场景
debug 调试信息(最详细) 开发/排查复杂问题
info 一般性事件记录 跟踪运行状态
notice 重要但非错误事件 生产环境常规监控
warn 警告事件(不影响服务) 潜在问题预警
error 默认级别,错误事件 服务异常排查
crit Critical,严重错误 紧急问题(如权限拒绝)

如果配置 error,会怎么样呢?

Nginx 只会记录 error级别及以上(即 error和 crit)的日志,而更低级别的日志(如 warn、notice、info、debug)将被忽略。

举例如下

cat /var/log/nginx/error.log
或者
cat /usr/local/nginx/logs/error.log

注意:

crit 记录的日志最少,而debug记录的日志最多。

有些模块突破了默认的error级别限制,也会记录一些日志,比如进程启动的一些notice通知。

小结:

错误日志的作用:用来查看错误信息,通过提示的错误信息,排除错误。

GoAccess 轻量级日志分析

作用:针对Apache/Nginx访问日志进行分析,优点:轻量级、开源、带图形化界面!

什么是GoAccess?

GoAccess 是一款开源的且具有交互视图界面的 实时 Web 日志分析工具,通过你的 Web 浏览器或者 Linux 系统下的 终端程序 即可访问。

能为系统管理员提供快速且有价值的 HTTP 统计,并以在线可视化服务器的方式呈现。

安装GoAccess:

安装 GoAccess
dnf install goaccess -y
如果安装GoAccess不成功,可以先完善一下 EPEL 仓库
安装 EPEL 仓库(Extra Packages for Enterprise Linux)
dnf install epel-release -y  

说明:

EPEL 是 RedHat/CentOS 官方维护的扩展软件源,提供大量常用但非默认包含的工具(如 GoAccess、htop 等)。

Nginx 默认访问日志通常位于

/usr/local/nginx/logs/access.log(若编译安装时未修改路径)

/var/log/nginx/access.log(若通过包管理器安装)

本例以 Nginx 源码编译安装到 /usr/local/nginx/ 为例

cd /usr/local/nginx/

注意:GoAccess分析的结果往往是一个html网页,如果想直接预览,建议直接把内容放置于Nginx访问目录

① 离线分析

离线分析,会生成静态 HTML 报告(推荐生产环境)

通过以下命令对访问日志进行分析,并将结果输出为 HTML 文件(便于通过浏览器查看)

goaccess -f /usr/local/nginx/logs/access.log  --log-format=COMBINED >  /usr/local/nginx/html/itheimadevops/report.html
或者
goaccess -f /usr/local/nginx/logs/access.log  --log-format=COMBINED > report.html
或者
goaccess -f /var/log/nginx/access.log  --log-format=COMBINED > report.html
-f:指定文件
--log-format:分析的文件格式
    COMBINED代表组合日志格式(XLF/ELF) Apache | Nginx
    COMMON代表通用日志格式(CLF) Apache

Nginx server 配置参考:

vi /usr/local/nginx/conf/nginx.conf
...
     server {
        # 监听端口
        listen 80;
        # 配置域名
        server_name www.itheimadevops.com;
        # 配置目录
        root html/itheimadevops;
        access_log logs/www.itheimadevops.com.access.log main;
        error_log logs/www.itheimadevops.com.error.log;
        # 配置uri匹配规则
        location / {
               index index.html index.htm;
        }
        location ~ \.(jpg|jpeg|gif|png|js|css)$ {
               add_header Cache-Control no-store;
        }
  }
...

查看 report.html

goaccess -f /var/log/nginx/access.log --log-format=COMBINED > report.html
ls -hl report.html
goaccess -f /usr/local/nginx/logs/access.log --log-format=COMBINED > report.html
ls -hl report.html
  • server1(dnf 版 Nginx)日志路径:/var/log/nginx/access.log
  • server2(源码版 Nginx)日志路径:/usr/local/nginx/logs/access.log
  • 作用:用 goaccess 解析 Nginx 访问日志,生成可视化报表 report.html
② 实时分析

除生成静态 HTML 外,GoAccess 还支持 终端实时动态展示(适合快速排查问题)

goaccess /usr/local/nginx/logs/access.log \
  --no-global-config \
  --log-format='%h %^ %^ [%d:%t %^] "%r" %s %b "%R" "%u"' \
  --date-format='%d/%b/%Y' \
  --time-format='%H:%M:%S'
或者
goaccess /var/log/nginx/access.log \
  --no-global-config \
  --log-format='%h %^ %^ [%d:%t %^] "%r" %s %b "%R" "%u"' \
  --date-format='%d/%b/%Y' \
  --time-format='%H:%M:%S'

更多参考:https://www.goaccess.cc/?mod=man

Nginx 企业级日志分析实战经典案例

GoAccess 不仅能生成基础的可视化报告,更能通过灵活的命令行参数与日志分析,帮助企业快速定位关键问题(如高频攻击 IP、异常 404 请求、热门业务路径)。

本章聚焦三大典型企业级场景,结合实战命令与结果解读,助你掌握日志分析的“进阶用法”。

统计访问量最高的IP地址

在生成日志分析报告时,GoAccess 默认会统计并展示 “Top IPs”(访问量最高的 IP 地址列表)。

☆ 场景背景

企业的 Web 服务可能面临两类与 IP 相关的风险:

  • 正常高频访问:如内部员工频繁调用 API、爬虫程序抓取公开数据(需评估是否合理)。
  • 恶意行为:如 DDoS 攻击(大量 IP 短时间内发起请求)、暴力破解(针对登录接口的重复尝试)、爬虫违规采集(超出正常频率)。

通过统计访问量最高的 IP,可以快速锁定 “谁在频繁访问我的服务”,进而判断是否需要封禁、限流或进一步分析其行为

☆ 脚本实现
# 提取日志中的 IP(假设为每行第一个字段,符合 Nginx 默认日志格式)并统计频次,按次数降序排序,取前 10
awk '{print $1}' /usr/local/nginx/logs/access.log | sort | uniq -c | sort -nr | head -n 10
说明:
    awk '{print $1}':提取日志每行的第一个字段(通常是客户端 IP,Nginx 默认日志格式中 $1为 IP)。
    sort:对 IP 列表进行排序(uniq -c要求输入已排序)。
    uniq -c:统计每个唯一 IP 的出现次数(-c表示计数)。
    sort -nr:按计数结果降序排序(-n数值排序,-r逆序)。
    head -n 10:仅显示前 10 条结果。

统计404错误的请求

☆ 场景背景

HTTP 404 状态码表示 “请求的资源不存在”,可能由以下原因导致:

  • 用户侧问题:用户手动输入了错误的 URL、点击了过期的书签或外链。
  • 业务侧问题:前端页面链接配置错误(如前端代码中的 API 地址拼写错误)、后端服务删除了文件但未更新前端引用、CDN 缓存了旧版本的无效链接。
  • 攻击行为:扫描器尝试访问常见的敏感路径(如 /admin.php、/config.json),试图探测系统漏洞。

通过统计 404 错误请求,可以快速定位 “哪些资源被频繁访问但不存在”,进而修复业务逻辑或加固安全防护。

☆ 脚本实现
# grep 查找关键状态码 404
grep '404' /usr/local/nginx/logs/access.log
或者
grep '404' /var/log/nginx/access.log
# 提取所有状态码为 404 的日志行(Nginx 默认日志格式中状态码是第9个字段)
awk '$9 == 404' /usr/local/nginx/logs/access.log
或者
awk '$9 == 404' /var/log/nginx/access.log

如果Nginx站点很正常,一般来讲就没有404,可以考虑查找一下200

awk '$9 == 200' /usr/local/nginx/logs/access.log|more

进阶实现

# 进阶:提取 404 请求的路径(第7个字段),统计频次并排序
awk '$9 == 404 {print $7}' /usr/local/nginx/logs/access.log | sort | uniq -c | sort -nr | head -n 10
或者
awk '$9 == 404 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -n 10
或者
awk '$9 == 404' /usr/local/nginx/logs/access.log | awk '{ print $7}' | sort | uniq -c | sort -nr | head -n 10
或者
awk '$9 == 404' /var/log/nginx/access.log | awk '{ print $7}' | sort | uniq -c | sort -nr | head -n 10

统计最热门的URL

☆ 场景背景

“最热门的 URL” 反映了用户最常访问的页面或接口,是企业分析 “用户关注什么” 和 “业务重点在哪里” 的关键指标。通过统计热门 URL,可以:

  • 优化资源配置:为高流量页面分配更多服务器资源(如 CDN 加速、数据库缓存)。
  • 改进用户体验:分析热门页面的加载速度、跳出率(需结合其他工具),针对性优化交互设计。
  • 验证业务策略:检查推广活动链接(如营销页 /promotion/2025)是否达到预期流量,或核心功能(如支付页 /checkout)是否易用。
☆ 脚本实现
# 提取日志中的请求路径(第11个字段),统计频次并排序,取前 10
awk '{print $11}' /usr/local/nginx/logs/access.log | sort | uniq -c | sort -nr | head -n 10
或者
awk '{print $11}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -n 10

日志轮转

作用:利用Shell脚本对日志进行切割,把大的访问日志切割为一个一个小日志,方便后期存储以及查看分析

☆脚本实现
mkdir /scripts
cd /scripts
vim logrotate.sh
------------------分割线-------------------
#!/bin/bash
date_info=$(date +%F-%H-%M)
mv /usr/local/nginx/logs/access.log /usr/local/nginx/logs/access.log.$date_info
/usr/local/nginx/sbin/nginx -s reload
------------------分割线-------------------
chmod +x /scripts/logrotate.sh
☆配置 crontab
crontab -e
* * * * * /bin/bash /scripts/logrotate.sh &>/dev/null
或者
0 */6 * * * /bin/bash /scripts/logrotate.sh &>/dev/null
或者
0 * * * * /bin/bash /scripts/logrotate.sh &>/dev/null
30 2 * * * /bin/bash /scripts/logrotate.sh &>/dev/null

改进版

mv /usr/local/nginx/logs/access.log /usr/local/nginx/logs/access.log.$(date +%F_%H-%M-%S) && /usr/local/nginx/sbin/nginx -s reopen

nginx -s reload 与 nginx -s reopen 对比表

对比项

reload

reopen

主要用途

重新加载配置文件

重新打开日志文件

是否创建新日志文件

❌ 否

✅ 是

是否重启工作进程

✅ 是(平滑重启)

❌ 否(继续使用原进程)

是否重新加载配置

✅ 是

❌ 否

是否中断现有连接

❌ 否(优雅关闭)

❌ 否

配置文件语法检查

✅ 会进行检查

❌ 不会检查

典型使用场景

nginx.conf 配置变更后生效

日志切割/轮转(配合 logrotate)

执行命令示例

nginx -s reload

nginx -s reopen

工作原理简述

reload:

  • 主进程检查新配置语法
  • 启动新工作进程(加载新配置)
  • 优雅关闭旧工作进程

reopen:

  • 主进程通知工作进程关闭当前日志文件
  • 工作进程重新打开日志文件(按配置路径)
  • 若文件不存在则自动创建

总结

日志轮转的本质就是把一个大的日志切割为若干个小的日志,防止文件过大。

Nginx 反向代理

反向代理(Reverse Proxy)是位于 客户端与后端服务器之间 的中间设备(或服务),客户端直接访问代理服务器,代理服务器再将请求转发给内部的后端服务器,并将后端服务器的响应返回给客户端。

反向代理的好处:

  • 隐藏后端架构:客户端只与代理服务器交互,后端服务的IP、端口、部署细节(如多台服务器集群)对客户端不可见。
  • 负载均衡:将客户端请求分发到多台后端服务器,提升整体处理能力(后续章节会深入讲解)。
  • 安全防护:代理服务器可过滤恶意请求(如SQL注入、XSS)、限制访问IP、提供SSL加密(HTTPS终止)。
  • 统一入口:通过一个域名/端口(如 http://example.com)访问多个后端服务(如API、静态资源、管理后台)。

环境准备

准备虚拟机

角色

IP

主机名

功能

nginx1

192.168.88.101

nginx1.itcast.cn

代理服务器

nginx2

192.168.88.102

nginx2.itcast.cn

后端服务器

修改主机名和 hosts

hostnamectl set-hostname nginx1.itcast.cn && bash
hostnamectl set-hostname nginx2.itcast.cn && bash
cat >/etc/hosts<<EOF
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.88.101   nginx1  nginx1.itcast.cn
192.168.88.102   nginx2  nginx2.itcast.cn
EOF

关闭防火墙与 SELinux

iptables -F
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i '/SELINUX=enforcing/cSELINUX=disabled' /etc/selinux/config

安装依赖包以及时间同步

# 安装依赖包
yum install vim wget rsync net-tools epel-release -y
# 更新安装ntp时间服务器(可选)
yum install ntpsec -y
ntpdate cn.ntp.org.cn
说明:
    ntpsec:是 NTP (Network Time Protocol) 的一个安全增强分支版本,用于系统时间同步;
    cn.ntp.org.cn:是中国国家授时中心维护的 NTP 服务器地址
# 如果Linux服务器通不了外网,可以考虑配置一下DNS解析地址
cat >/etc/resolv.conf<<EOF
nameserver 192.168.88.2
nameserver 114.114.114.114
EOF

部署实战

配置后端服务器

在后端服务器nginx2上执行

dnf安装的nginx

[root@nginx2 ~]# dnf install nginx -y
修改nginx服务运行端口为8080
[root@nginx2 ~]# vim /etc/nginx/nginx.conf
    ...
    server {
        listen       8080;
        listen       [::]:8080;
        server_name  _;
        root         /usr/share/nginx/html;
        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;
        error_page 404 /404.html;
        location = /404.html {
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
    ...
[root@nginx2 ~]# cat /etc/nginx/nginx.conf
# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;
    server {
        listen       8080;
        listen       [::]:8080;
        server_name  _;
        root         /usr/share/nginx/html;
        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;
        error_page 404 /404.html;
        location = /404.html {
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
# Settings for a TLS enabled server.
#
#    server {
#        listen       443 ssl http2;
#        listen       [::]:443 ssl http2;
#        server_name  _;
#        root         /usr/share/nginx/html;
#
#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_ciphers PROFILE=SYSTEM;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        error_page 404 /404.html;
#            location = /40x.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }
}
[root@nginx2 ~]# cat >/usr/share/nginx/html/index.html <<EOF
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>后端Web服务器</title>
</head>
<body>
    这是后端Web服务器
</body>
</html>
EOF
[root@nginx2 ~]# cat /usr/share/nginx/html/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>后端Web服务器</title>
</head>
<body>
    这是后端Web服务器
</body>
</html>
[root@nginx2 ~]#
检查nginx配置文件是否正确
[root@nginx2 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx2 ~]# systemctl restart nginx
[root@nginx2 ~]# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; preset: disabled)
     Active: active (running) since Thu 2025-12-11 11:34:51 CST; 4s ago
    Process: 29371 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
    Process: 29373 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
    Process: 29374 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
   Main PID: 29375 (nginx)
      Tasks: 3 (limit: 22927)
     Memory: 3.0M
        CPU: 25ms
     CGroup: /system.slice/nginx.service
             ├─29375 "nginx: master process /usr/sbin/nginx"
             ├─29376 "nginx: worker process"
             └─29377 "nginx: worker process"
Dec 11 11:34:51 nginx2.itcast.cn systemd[1]: Starting The nginx HTTP and reverse proxy server...
Dec 11 11:34:51 nginx2.itcast.cn nginx[29373]: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
Dec 11 11:34:51 nginx2.itcast.cn nginx[29373]: nginx: configuration file /etc/nginx/nginx.conf test is successful
Dec 11 11:34:51 nginx2.itcast.cn systemd[1]: Started The nginx HTTP and reverse proxy server.
[root@nginx2 ~]# systemctl enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
[root@nginx2 ~]# netstat -pantul|grep nginx
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      30551/nginx: master
tcp6       0      0 :::8080                 :::*                    LISTEN      30551/nginx: master
[root@nginx2 ~]#

源码安装的nginx

[root@nginx2 ~]# ls /usr/local/nginx/
client_body_temp  fastcgi_temp  logs        sbin       uwsgi_temp
conf              html          proxy_temp  scgi_temp
[root@nginx2 ~]# ls /usr/local/nginx/conf/
fastcgi.conf            mime.types          scgi_params.default
fastcgi.conf.default    mime.types.default  uwsgi_params
fastcgi_params          nginx.conf          uwsgi_params.default
fastcgi_params.default  nginx.conf.bak      win-utf
koi-utf                 nginx.conf.default
koi-win                 scgi_params
[root@nginx2 ~]# vim /usr/local/nginx/conf/nginx.conf
[root@nginx2 ~]# cat /usr/local/nginx/conf/nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       8080;
        server_name  192.168.88.102;
        root /usr/local/nginx/html;
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
[root@nginx2 ~]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@nginx2 ~]# nginx -s reload
[root@nginx2 ~]#  cat >/usr/local/nginx/html/index.html <<EOF
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>后端Web服务器</title>
</head>
<body>
    这是后端Web服务器
</body>
</html>
EOF
[root@nginx2 ~]# cat /usr/local/nginx/html/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>后端Web服务器</title>
</head>
<body>
    这是后端Web服务器
</body>
</html>
[root@nginx2 ~]# systemctl restart nginx
[root@nginx2 ~]# systemctl status nginx
● nginx.service - Nginx Web Server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: d>
     Active: active (running) since Tue 2026-03-24 09:40:53 CST; 5s ago
    Process: 4706 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, sta>
    Process: 4708 ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/co>
   Main PID: 4709 (nginx)
      Tasks: 2 (limit: 22927)
     Memory: 2.1M
        CPU: 17ms
     CGroup: /system.slice/nginx.service
             ├─4709 "nginx: master process /usr/local/nginx/sbin/nginx -c /usr>
             └─4710 "nginx: worker process"
Mar 24 09:40:53 nginx2.itcast.cn systemd[1]: Starting Nginx Web Server...
Mar 24 09:40:53 nginx2.itcast.cn systemd[1]: Started Nginx Web Server.
[root@nginx2 ~]# netstat -pantul|grep nginx
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      4709/nginx: master
[root@nginx2 ~]#

测试后端服务器的Web服务

[root@nginx2 ~]# curl 192.168.88.102:8080
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>后端Web服务器</title>
</head>
<body>
    这是后端Web服务器
</body>
</html>
[root@nginx2 ~]#

http://192.168.88.102:8080/

配置代理服务器

在前端服务器nginx1上执行

dnf安装的nginx

[root@nginx1 ~]# dnf install nginx -y
修改nginx1配置文件,对接nginx2
[root@nginx1 ~]# find / -name nginx.conf
/etc/nginx/nginx.conf
/usr/lib/sysusers.d/nginx.conf
[root@nginx1 ~]# vim /etc/nginx/nginx.conf
user nginx;
worker_processes  auto;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  _;
        # root         /usr/share/nginx/html;
        location / {
            proxy_pass http://192.168.88.102:8080;      # 关键!指定后端服务器的IP和端口
            proxy_set_header Host $host;                # 传递原始请求的Host头(重要!)
            proxy_set_header X-Real-IP $remote_addr;    # 传递客户端真实IP(后端可通过此头获取)
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;   # 传递完整的代理链路IP
        }
        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            # root   html;
        }
    }
}
[root@nginx1 ~]# cat /etc/nginx/nginx.conf
# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;
    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        # root         /usr/share/nginx/html;
        location / {
            proxy_pass http://192.168.88.102:8080;      # 关键!指定后端服务器的IP和端口
            proxy_set_header Host $host;                # 传递原始请求的Host头(重要!)
            proxy_set_header X-Real-IP $remote_addr;    # 传递客户端真实IP(后端可通过此头获取)
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;   # 传递完整的代理链路IP
        }
        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;
        error_page 404 /404.html;
        location = /404.html {
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
# Settings for a TLS enabled server.
#
#    server {
#        listen       443 ssl http2;
#        listen       [::]:443 ssl http2;
#        server_name  _;
#        root         /usr/share/nginx/html;
#
#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_ciphers PROFILE=SYSTEM;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        error_page 404 /404.html;
#            location = /40x.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }
}
[root@nginx1 ~]#

源码安装的nginx

[root@nginx1 ~]# vim /usr/local/nginx/conf/nginx.conf
[root@nginx1 ~]# cat /usr/local/nginx/conf/nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  _;
        # root /usr/local/nginx/html;
        location / {
          proxy_pass http://192.168.88.102:8080;      # 关键!指定后端服务器的IP和端口
          proxy_set_header Host $host;                # 传递原始请求的Host头(重要!)
          proxy_set_header X-Real-IP $remote_addr;    # 传递客户端真实IP(后端可通过此头获取)
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;   # 传递完整的代理链路IP
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}
[root@nginx1 ~]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@nginx1 ~]# nginx -s reload
[root@nginx1 ~]#

检查Nginx配置文件并启动Nginx服务

[root@nginx1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx1 ~]# systemctl restart nginx
[root@nginx1 ~]# systemctl enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.
[root@nginx1 ~]# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: d>
     Active: active (running) since Sat 2025-12-13 12:07:24 CST; 7s ago
   Main PID: 30749 (nginx)
      Tasks: 3 (limit: 22926)
     Memory: 3.0M
        CPU: 37ms
     CGroup: /system.slice/nginx.service
             ├─30749 "nginx: master process /usr/sbin/nginx"
             ├─30750 "nginx: worker process"
             └─30751 "nginx: worker process"
Dec 13 12:07:24 nginx1.itcast.cn systemd[1]: Starting The nginx HTTP and rever>
Dec 13 12:07:24 nginx1.itcast.cn nginx[30747]: nginx: the configuration file />
Dec 13 12:07:24 nginx1.itcast.cn nginx[30747]: nginx: configuration file /etc/>
Dec 13 12:07:24 nginx1.itcast.cn systemd[1]: Started The nginx HTTP and revers>
# nginx -s reload # 可选

验证测试

http://192.168.88.101/

http://192.168.88.102:8080/

Nginx代理服务器暴力broken测试

server {
    listen 80;
    server_name _;
    location / {
        return 500 "broken\n";
    }
}
[root@nginx1 ~]# cd /etc/nginx
[root@nginx1 nginx]# pwd
/etc/nginx
[root@nginx1 nginx]# vim nginx.conf
[root@nginx1 nginx]# cat nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    #include /etc/nginx/conf.d/*.conf;
    server {
        listen       80;
        server_name  _;
        location / {
        return 500 "broken\n";
       }
        #root         /usr/share/nginx/html;
#       location / {
#            proxy_pass http://192.168.88.102:8080;      # 关键!指定后端服务器的IP和端口
#            proxy_set_header Host $host;                # 传递原始请求的Host头(重要!)
#            proxy_set_header X-Real-IP $remote_addr;    # 传递客户端真实IP(后端可通过此头获取)
#            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;   # 传递完整的代理链路IP
#        }
        #include /etc/nginx/default.d/*.conf;
        error_page 404 /404.html;
        location = /404.html {
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
}
[root@nginx1 nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx1 nginx]# nginx -s reload
[root@nginx1 nginx]# curl 127.0.0.1
broken
[root@nginx1 nginx]#

http://192.168.88.101/

结论1:

Nginx 在没有配置 locationroot 时,会使用默认 root /usr/share/nginx/html 提供静态资源。

结论2:

只要定义了 location /,就会覆盖默认行为。

结论3:

return 指令优先级非常高,可以直接终止请求处理流程。

Nginx 的配置是具备兜底机制的,即使没有显式配置 root 和 location,也会使用默认 root 提供服务。因此在排查问题时,如果发现配置改了但结果没变,要考虑是否命中了默认行为或者其他 location。

HTTP/1.0与HTTP/1.1

HTTP/1.1 和 HTTP/1.0 是 Web 协议演进中的两个重要版本,主要区别如下:

主要区别对比表

特性 HTTP/1.0 HTTP/1.1
连接方式 默认短连接,每个请求建立新TCP连接 默认长连接(Keep-Alive),连接可复用
Host头 可选,不支持虚拟主机 必需,支持多域名共享IP
缓存控制 简单的 Expires、Pragma 强大的 Cache-Control、ETag、Last-Modified
状态码 基本状态码 新增 100 Continue, 206 Partial Content 等
分块传输 不支持 支持 Transfer-Encoding: chunked
管道化 不支持 支持(但有限制)
带宽优化 不支持范围请求 支持 Range 和 Accept-Ranges
错误处理 简单 更完善的错误处理和恢复机制
请求方法 GET, POST, HEAD 新增 OPTIONS, PUT, DELETE, TRACE, CONNECT
[root@nginx1 ~]# vim /etc/nginx/nginx.conf
[root@nginx1 ~]# cat /etc/nginx/nginx.conf
# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;
    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        # root         /usr/share/nginx/html;
        location / {
            proxy_http_version 1.1;
            proxy_pass http://192.168.88.102:8080;      # 关键!指定后端服务器的IP和端口
            proxy_set_header Host $host;                # 传递原始请求的Host头(重要!)
            proxy_set_header X-Real-IP $remote_addr;    # 传递客户端真实IP(后端可通过此头获取)
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;   # 传递完整的代理链路IP
            proxy_set_header X-Original-Protocol $server_protocol;
        }
        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;
        error_page 404 /404.html;
        location = /404.html {
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
# Settings for a TLS enabled server.
#
#    server {
#        listen       443 ssl http2;
#        listen       [::]:443 ssl http2;
#        server_name  _;
#        root         /usr/share/nginx/html;
#
#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_ciphers PROFILE=SYSTEM;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        error_page 404 /404.html;
#            location = /40x.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }
}
[root@nginx1 ~]#
[root@nginx1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx1 ~]# nginx -s reload

访问代理服务器地址

http://192.168.88.101/

总结

代理一共有两种:(正向代理) + (反向代理)

  1、正向代理用户可以感知到,比较典型应用(科学上网)

  2、反向代理用户无感知,比较典型的应用(请求转发,更多应用在于负载均衡技术)

Nginx 负载均衡

四层负载 vs 七层负载

① 底层实现 => 四层负载均衡基于网络层与传输层,也就是IP + Port(套接字 socket)实现请求转发;七层负载基于应用层,通过URL地址请求转发

② 性能不同 => 四层相当于转发器,效率更高;七层需要通过URL判断才能实现转发,需要做额外的处理

③ 安全性不同 => 七层需要对用户URL请求,判断可以屏蔽异常请求,相对而言更加安全

环境准备

角色

IP

主机名

功能

lb1

192.168.88.100

lb1.itcast.cn

负载均衡

web1

192.168.88.101

web1.itcast.cn

Web服务

web2

192.168.88.102

web2.itcast.cn

Web服务

修改IP、主机名和域名解析

hostnamectl set-hostname lb1.itcast.cn && bash
hostnamectl set-hostname web1.itcast.cn && bash
hostnamectl set-hostname web2.itcast.cn && bash
cat >/etc/hosts<<EOF
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.88.100   lb1   lb1.itcast.cn
192.168.88.101   web1  web1.itcast.cn
192.168.88.102   web2  web2.itcast.cn
EOF

关闭防火墙与 SELinux

iptables -F
systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i '/SELINUX=enforcing/cSELINUX=disabled' /etc/selinux/config

安装依赖包时间同步

yum install vim wget rsync net-tools epel-release -y
yum install ntpsec -y
ntpdate cn.ntp.org.cn
cat >/etc/resolv.conf<<EOF
nameserver 192.168.88.2
nameserver 114.114.114.114
EOF

NTPsec vs Chrony

特性 NTPsec Chrony
起源 从经典 NTP(ntpd)分支而来,由 NTPsec 团队维护 独立开发,最初为嵌入式系统设计
设计目标 增强安全性和性能,修复 ntpd 的历史问题 快速同步、低延迟,适合不稳定网络环境
社区活跃度 活跃,但用户基数小于 Chrony 广泛采用,尤其在云环境和现代 Linux 发行版

安装nginx

【Nginx】安装部署-CSDN博客

三个服务器都要按照nginx

如果网络有问题,请执行以下命令

cat >/etc/resolv.conf<<EOF
nameserver 192.168.88.2
nameserver 114.114.114.114
EOF
systemctl status nginx --no-pager

配置 Web1 & Web2

这节课我们聚焦 Nginx 负载均衡,关于 backend 服务,用 html 简单内容代替。

# 在LB1上执行,统一 一下三台的nginx配置文件(可选)
scp /etc/nginx/nginx.conf 192.168.88.101:/etc/nginx/
scp /etc/nginx/nginx.conf 192.168.88.102:/etc/nginx/
# 在 Web1 上执行
echo "This is Web Server1" > /usr/share/nginx/html/index.html
或者
echo "This is Web Server1" > /usr/local/nginx/html/index.html
# 在 Web2 上执行
echo "This is Web Server2" > /usr/share/nginx/html/index.html
或者
echo "This is Web Server2" > /usr/local/nginx/html/index.html

验证测试

curl 127.0.0.1

配置 LB1

下面的操作,都是在 LB1 上操作

第一步:查看 nginx.cnf

在 LB1 上,备份配置文件nginx.conf,然后删除注释与空行

第一步,备份
[root@lb1 ~]# cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak # 这是 dnf/yum 安装的 Nginx
第二步,去掉注释,空行
[root@lb1 ~]# grep -Ev '#|^$' /etc/nginx/nginx.conf.bak > /etc/nginx/nginx.conf
第三步,简单查看配置
[root@lb1 ~]# cat /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    include /etc/nginx/conf.d/*.conf;
    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        root         /usr/share/nginx/html;
        include /etc/nginx/default.d/*.conf;
        error_page 404 /404.html;
        location = /404.html {
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
}
[root@lb1 ~]#
第二步:配置负载均衡

Nginx 在 http 块中实现七层负载均衡,默认使用轮询算法;同时也支持通过 stream 块实现四层负载均衡

在 LB1 上操作

vim /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    # include /etc/nginx/conf.d/*.conf;
    ####################  配置开始  ######################
    upstream my_web_service {
        server 192.168.88.101:80;
        server 192.168.88.102:80;
    }
    ####################  配置结束  ######################
    server {
        listen       80;
        listen       [::]:80;
        ####################  配置开始  ######################
        server_name  192.168.88.100;             # 替换为实际域名或 IP
        location / {
            proxy_pass http://my_web_service;    # 将请求转发到负载均衡组
            proxy_set_header HOST $host;
        }
        ####################  配置结束  ######################
        # server_name  _;
        # root         /usr/share/nginx/html;
        # include /etc/nginx/default.d/*.conf;
        error_page 404 /404.html;
        location = /404.html {
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
}
第三步:重载配置,验证测试第三步:重载配置,验证测试

在 LB1 上操作

nginx -t
nginx -s reload
[root@lb1 ~]# curl 192.168.88.100
This is Web Server1
[root@lb1 ~]# curl 192.168.88.100
This is Web Server2
[root@lb1 ~]# curl 192.168.88.100
This is Web Server1
[root@lb1 ~]# curl 192.168.88.100
This is Web Server2

注意:如果无法访问Nginx Web服务,请在所有Linux服务器上执行以下命令!

sed  -i -r 's/SELINUX=[ep].*/SELINUX=disabled/g' /etc/selinux/config
setenforce 0
systemctl stop firewalld &> /dev/null
systemctl disable firewalld &> /dev/null
iptables -F
iptables -t nat -F
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT

回到浏览器,多次访问,会发现

页面在 Web1 和 Web2 之间来回切换(这是为了方便验证而设计的内容),从而验证负载均衡配置成功。

炫酷技能(拓展)

旋转星空

cat >index.html<<EOF
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
 <HEAD>
  <TITLE> New Document </TITLE>
  <META NAME="Generator" CONTENT="EditPlus">
  <META NAME="Author" CONTENT="">
  <META NAME="Keywords" CONTENT="">
  <META NAME="Description" CONTENT="">
  <style>
   body {
  background: #060e1b;
  overflow: hidden;
}
  </style>
 </HEAD>
 <BODY>
  <canvas id="canvas"></canvas>
  <script>
   "use strict";
var canvas = document.getElementById('canvas'),
  ctx = canvas.getContext('2d'),
  w = canvas.width = window.innerWidth,
  h = canvas.height = window.innerHeight,
  hue = 217,
  stars = [],
  count = 0,
  maxStars = 1400;
// Thanks @jackrugile for the performance tip! https://codepen.io/jackrugile/pen/BjBGoM
// Cache gradient
var canvas2 = document.createElement('canvas'),
    ctx2 = canvas2.getContext('2d');
    canvas2.width = 100;
    canvas2.height = 100;
var half = canvas2.width/2,
    gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);
    gradient2.addColorStop(0.025, '#fff');
    gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)');
    gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)');
    gradient2.addColorStop(1, 'transparent');
    ctx2.fillStyle = gradient2;
    ctx2.beginPath();
    ctx2.arc(half, half, half, 0, Math.PI * 2);
    ctx2.fill();
// End cache
function random(min, max) {
  if (arguments.length < 2) {
    max = min;
    min = 0;
  }
  if (min > max) {
    var hold = max;
    max = min;
    min = hold;
  }
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
function maxOrbit(x,y) {
  var max = Math.max(x,y),
      diameter = Math.round(Math.sqrt(max*max + max*max));
  return diameter/2;
}
var Star = function() {
  this.orbitRadius = random(maxOrbit(w,h));
  this.radius = random(60, this.orbitRadius) / 12;
  this.orbitX = w / 2;
  this.orbitY = h / 2;
  this.timePassed = random(0, maxStars);
  this.speed = random(this.orbitRadius) / 50000;
  this.alpha = random(2, 10) / 10;
  count++;
  stars[count] = this;
}
Star.prototype.draw = function() {
  var x = Math.sin(this.timePassed) * this.orbitRadius + this.orbitX,
      y = Math.cos(this.timePassed) * this.orbitRadius + this.orbitY,
      twinkle = random(10);
  if (twinkle === 1 && this.alpha > 0) {
    this.alpha -= 0.05;
  } else if (twinkle === 2 && this.alpha < 1) {
    this.alpha += 0.05;
  }
  ctx.globalAlpha = this.alpha;
    ctx.drawImage(canvas2, x - this.radius / 2, y - this.radius / 2, this.radius, this.radius);
  this.timePassed += this.speed;
}
for (var i = 0; i < maxStars; i++) {
  new Star();
}
function animation() {
    ctx.globalCompositeOperation = 'source-over';
    ctx.globalAlpha = 0.8;
    ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 1)';
    ctx.fillRect(0, 0, w, h)
  ctx.globalCompositeOperation = 'lighter';
  for (var i = 1, l = stars.length; i < l; i++) {
    stars[i].draw();
  };
  window.requestAnimationFrame(animation);
}
animation();
  </script>
 </BODY>
</HTML>
EOF

黑客数字雨

cat >index.html<<EOF
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
 <HEAD>
  <TITLE> New Document </TITLE>
  <META NAME="Generator" CONTENT="EditPlus">
  <META NAME="Author" CONTENT="">
  <META NAME="Keywords" CONTENT="">
  <META NAME="Description" CONTENT="">
  <style>
  /*Twitter @locoalien*/
/*Sitio web www.locoaliensoft.com*/
/*www.facebook.com/CulturaInformatica*/
                * {margin: 0; padding: 0;}
                canvas {display: block;}
                body {background: black;}
  </style>
 </HEAD>
 <BODY>
 <html>
<head>
        <title>Hacking locoalien Matrix console</title>
        <meta charset="UTF-8">
</head>
<body>
<canvas id="locoalien"></canvas>
<script type="text/javascript">
        </script>
</body>
</html>
  <script>
  //*--------------------------------------*
//* Desarrollado por Locoalien           *
//* Twitter @locoalien                   *
//* Sitio web: www.locoaliensoft.com     *
//*--------------------------------------*
//+++++++++++++++++++++++++++++++++++++
// El objetivo de este ejemplo es aprender a dar animacion y utilizar las propiedades
// Mas comunes de JavaScript. Veremos el poder que tiene HTML5 implementando el Canvas
// Espero les guste este ejemplo
// Para mas informacion visitar nuestra pagina de Facebook: https://www.facebook.com/CulturaInformatica
//+++++++++++++++++++++++++++++++++++++
window.onload = hacking;//Llamamos a la funcion despues de que el documento ha sido cargado completamente
function hacking(){
        var c = document.getElementById("locoalien");
        c.height = window.innerHeight;  //innerHeight se utiliza para saber la altura de la pantalla
        c.width = window.innerWidth;    //innerHeight se utiliza para saber la altura de la pantalla
        var letraTam=12; //Tamaño de la letras por pixel
        var columnas=c.width/letraTam; //El ancho dividido por el tamano que tendra las letras
        var Texto="0"; //El testo que aparecera en pantalla
        Texto=Texto.split("");//La función split() permite dividir una cadena de caracteres (string) en varios bloques y crear un array con estos
        var Texto2="1";
        Texto2=Texto2.split("");
        var letras=[];
        for(var i=0; i<columnas;i++){
                letras[i]=1;//Siver para saber la cantidad de letras que tendra en la pantalla
        }
        contexto= c.getContext('2d');//Muy importante especificar el contexto en el cual vamos a trabajar
        function dibujar(){
                contexto.fillStyle="rgba(0,0,0,0.05)";//Damos el color que tendra el recuadro en el que estara la animacion. en este caso sera transparente 0.05
                contexto.fillRect(0,0,c.width,c.height);//Damos las dimensiones alto y ancho que tendra el cuadrado, que en este caso es de toda la pantalla
                contexto.fillStyle= "#0f0";//Color de las letras
                contexto.font= letraTam+"px arial";//Tamaño de la letra
                for(var i=0;i<letras.length;i++){
                        text=Texto; //Le asigno el texto que definimos en la parte de arriba
                        //El ciclo for me permite darle las coordenadas correctas para posicionar el text x, y 
                        text2=Texto2;//El texto dos que mostrara solo el 1
                        if(i%2==1){contexto.fillText(text,i*letraTam, letras[i]*letraTam);//Para imprimir texto disponesmos de fillText(texto,x,y)
                        }else{
                                contexto.fillText(text2,i*letraTam, letras[i]*letraTam);//Para imprimir texto disponesmos de fillText(texto,x,y)        
                        }
                        if(letras[i]*letraTam > c.height && Math.random()>0.975){
                                letras[i]=0;
                        }
                        letras[i]++;
                }
        }
        setInterval(dibujar,120);//velocidad a la que se ejecuta la funcion en milisegundos
}
  </script>
 </BODY>
</HTML>
EOF

扩展: 解决无法显示真实IP的问题

我们观察 Web1 和 Web2 的 access日志,会发现

# 在 Web1 和 Web2 上分别执行
tail /var/log/nginx/access.log

为了解决 Web1/Web2 访问日志的显示问题(无法获取客户端真实的IP地址)

回到 LB1 服务器上,找到配置文件

vi /etc/nginx/nginx.conf
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    ####################  配置开始  ######################
    upstream my_web_service {
        server 192.168.88.101:80;
        server 192.168.88.102:80;
    }
    ####################  配置结束  ######################
    server {
        listen       80;
        listen       [::]:80;
        ####################  配置开始  ######################
        server_name  192.168.88.100;             # 替换为实际域名或 IP
        location / {
            proxy_pass http://my_web_service;    # 将请求转发到负载均衡组
            proxy_set_header HOST $host;
            proxy_set_header X-Real-IP $remote_addr;                      # 添加这两行  
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        ####################  配置结束  ######################
        server_name  _;
        root         /usr/share/nginx/html;
        include /etc/nginx/default.d/*.conf;
        error_page 404 /404.html;
        location = /404.html {
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
}
/usr/sbin/nginx -s reload

Nginx 变量:

$remote_addr:Nginx 变量,表示直接连接到当前服务器的客户端 IP。

X-Real-IP:记录原始客户端 IP,适用于单级代理场景。

X-Forwarded-For:记录完整代理链,适用于多级代理和日志分析。

最佳实践:两者同时设置,兼顾简单性和可追溯性。

在Web01和Web02服务器上,打开配置文件(默认就是配置好的),定制日志显示格式

在Web01和Web02服务器上
# vi /etc/nginx/nginx.conf
...
http {
    ...
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  logs/access.log main;
    ...
}
在Web01和Web02服务器上,分别重启
# /usr/sbin/nginx -s reload

在 Web1 上和web2 上,都验证测试

tail -3 /var/log/nginx/access.log

验证宿主机 IP

# 在宿主机(笔记本 Windows 电脑)上,执行
ipconfig

分发请求关键字

backup关键字:其他的没有backup标识的服务器都无响应,才分发到backup服务器。

# vim conf/nginx.conf
http {
        ...
        upstream my_web_service {
                server 192.168.88.101:80 backup;    # 优先访问其他的服务器
                server 192.168.88.103:80;
        }
        ...
}

down关键字:任何时候,请求都不分发给配置了down关键字的服务器

# vim conf/nginx.conf
http {
        ...
        upstream my_web_service {
                server 192.168.88.101:80;
                server 192.168.88.103:80 down;    # 下线了
        }
        ...
}

用的最多的还是backup,关键时刻起到热备作用!

负载均衡的3种调度算法(请求规则)

Nginx 官方默认3种负载均衡的算法:

Round-Robin RR轮询(默认): 一次一个的来(理论上的,实际实验可能会有间隔)

Weight 权重: 权重高多分发一些,服务器硬件更好的设置权重更高一些

比如,当我们设置成 1:9,会发现大部分情况,都是访问的 Web2

# vim conf/nginx.conf
http {
        ...
        upstream my_web_service {
                server 192.168.88.101:80 weight=4;
                server 192.168.88.103:80 weight=6;
        }
        ...
}

IP_HASH:代表把同一个IP来源的请求分到到同一个后端服务器

# vim conf/nginx.conf
http {
        ...
        upstream my_web_service {
                ip_hash;                    # 加上这个 IP Hash 就可以
                server 192.168.88.101:80;
                server 192.168.88.103:80;
        }
        ...
}

小结:

Round-Robin:rr轮询算法,请求均分

weight:weight=8

ip_hash:淘宝、京东 => 同一个IP所有请求都由同一个服务器处理

Session共享解决方案(调度算法)

① http协议,http协议是一个无状态协议,无法记录用户的浏览轨迹。

② cookie技术,可以把用户的信息记录在浏览器的缓存中(缓存存在过期时间)

③ session技术,可以把用户的浏览轨迹保存在服务器端(默认为/tmp目录)

验证码也是Session文件,其产生的验证码会保存在这个文件中。

模拟负载均衡与Session共享问题:

第一步:配置负载均衡(默认算法使用轮询算法)

第二步:使用账号密码登录功能,登录后台管理界面(admin,123456)

我们发现了一个问题,无论我们这么输入这个验证码,始终提示验证失败,主要原因:由于使用轮询算法,所以生成验证码时,相当于一次请求,验证验证码时也是一次请求。两次请求所在的服务器不同,所以最终验证总是失败。

解决办法:想办法让同一个IP的请求,分发到同一个Web服务器。

第三步:使用IP_HASH算法,问题解决

# vim conf/nginx.conf
http {
        ...
        upstream my_web_service {        # 加上这个 IP Hash 就可以
                ip_hash;
                server 192.168.88.101:80;
                server 192.168.88.103:80;
        }
        ...
}

注:其实Session共享的解决方案,非常多,不仅仅只有IP_HASH一种算法,还可以基于MySQL或Redis实现Session共享

觉得上面的内容有用吗?快来点个赞吧!

点赞() 我要打赏

温馨提示 : 本站内容来自会员投稿以及互联网,所有源码及教程均为作者总结编辑,请大家在使用过程中提前做好备份,以免发生无法预知的错误,源码类教程请勿直接用于生产环境!

 可能感兴趣的文章