ithuang
ithuang
发布于 2025-11-30 / 4 阅读
0

企业级 Web 服务 Nginx 进阶

企业级 Web 服务 Nginx 进阶

一、Nginx 性能优化之三大法宝

1. 动静分离

分类

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

☆ 动态内容

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

☆ 静态内容

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

动静分离的本质

将静态资源与动态请求分离到不同的服务或目录,通过Nginx精准路由,避免动态请求阻塞静态资源的高效传输,同时降低后端压力。

动静分离图解

企业级 Web 服务 Nginx 进阶1.png

经典配置

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/;     # 指向应用服务器
    }
}

2. 客户端缓存

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

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;
}

3. 开启 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,这意味着缓存服务器不会区分压缩与未压缩的内容。这样做通常会减少缓存的复杂性,但可能会导致某些情况缓存不一致。

企业级 Web 服务 Nginx 进阶2.png

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

常见压缩类型:

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

矢量图(.svg)

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

4. 总结

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

二、Nginx 日志分析

1. 日志分类

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

参考地址:http://nginx.org/en/docs/http/ngx_http_log_module.html

企业级 Web 服务 Nginx 进阶3.png

access 访问日志

cat /var/log/nginx/access.log

或者

cat /usr/local/nginx/logs/access.log

企业级 Web 服务 Nginx 进阶4.png

日志参数详解

参数意义
$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

企业级 Web 服务 Nginx 进阶5.png

企业级 Web 服务 Nginx 进阶6.png

企业级 Web 服务 Nginx 进阶7.png

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

nginx -s reload

error 错误日志

作用:用于Nginx排错

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

cat /var/log/nginx/error.log

或者

cat /usr/local/nginx/logs/error.log

企业级 Web 服务 Nginx 进阶8.png

配置error_log:

vim /etc/nginx/nginx.conf

或者

vim /usr/local/nginx/conf/nginx.conf

企业级 Web 服务 Nginx 进阶9.png

在配置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默认级别,错误事件服务异常排查
critCritical,严重错误紧急问题(如权限拒绝)

如果配置 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/ithuang/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

企业级 Web 服务 Nginx 进阶10.png

Nginx server 配置参考:

vi /usr/local/nginx/conf/nginx.conf
...
     server {
        # 监听端口
        listen 80;
        # 配置域名
        server_name www.ithuang.com;
        
        # 配置目录
        root html/ithuang;
        access_log logs/www.ithuang.com.access.log main;
        error_log logs/www.ithuang.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

企业级 Web 服务 Nginx 进阶11.png

企业级 Web 服务 Nginx 进阶12.png

② 实时分析

除生成静态 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'

企业级 Web 服务 Nginx 进阶13.png

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

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

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

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

2.1. 统计访问量最高的IP地址

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

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

企业级 Web 服务 Nginx 进阶14.png

☆ 场景背景

企业的 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 条结果。
[root@server1 nginx]# awk '{print $1}' /usr/local/nginx/logs/access.log | sort | uniq -c | sort -nr | head -n 10
    883 192.168.80.1
      1 192.168.80.11
[root@server1 nginx]#

企业级 Web 服务 Nginx 进阶15.png

2.2. 统计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
[root@server1 nginx]# awk '$9 == 404 {print $7}' /usr/local/nginx/logs/access.log | sort | uniq -c | sort -nr | head -n 10
     22 /images/404.jpg
     22 /css/demo.css
      6 /favicon.ico
[root@server1 nginx]#

2.3. 统计最热门的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
[root@server1 nginx]# awk '{print $11}' /usr/local/nginx/logs/access.log | sort | uniq -c | sort -nr | head -n 10
    244 "http://192.168.80.11/link/0.html"
    243 "http://www.ithuang666.com/link/0.html"
    168 "-"
     81 "http://192.168.80.11:2026/link/0.html"
     59 "http://192.168.80.11/"
     57 "http://www.ithuang666.com/"
     13 "http://192.168.80.11:2026/"
      5 "http://www.opponentdevops.com/"
      4 "http://192.168.80.11/yxmb/2/index.html"
      3 "http://www.ithuang666.com/css/font-awesome-4.7.0/css/font-awesome.min.css"
[root@server1 nginx]#

2.4. 日志轮转

作用:利用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 对比表

对比项reloadreopen
主要用途重新加载配置文件重新打开日志文件
是否创建新日志文件❌ 否✅ 是
是否重启工作进程✅ 是(平滑重启)❌ 否(继续使用原进程)
是否重新加载配置✅ 是❌ 否
是否中断现有连接❌ 否(优雅关闭)❌ 否
配置文件语法检查✅ 会进行检查❌ 不会检查
典型使用场景nginx.conf 配置变更后生效日志切割/轮转(配合 logrotate)
执行命令示例nginx -s reloadnginx -s reopen
工作原理简述

reload:

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

reopen:

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

总结

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

三、Nginx 反向代理(重点)

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

反向代理的好处:

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

1. 环境准备

1.1. 准备虚拟机

角色IP主机名功能
nginx1192.168.80.11nginx1.itcast.cn代理服务器
nginx2192.168.80.12nginx2.itcast.cn后端服务器

1.2. 修改主机名和 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.80.11   nginx1  nginx1.itcast.cn
192.168.80.12   nginx2  nginx2.itcast.cn
EOF

1.3. 关闭防火墙与 SELinux

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

1.4. 安装依赖包以及时间同步(可选)

# 安装依赖包
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.80.2
nameserver 114.114.114.114
EOF

2. 部署实战

2.1. 配置后端服务器

在后端服务器nginx2上执行

dnf安装的nginx

dnf install nginx -y
# 配置nginx主配置文件
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 {
        }
}
...

#编辑测试页
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

# 语法检测
nginx -t

#重启查看状态
systemctl restart nginx
systemctl status nginx
systemctl enable nginx

#查看端口号
netstat -pantul|grep nginx

源码安装的nginx

# 编写主配置文件
vim /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.80.12;
        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;
        }
    }
}
...

# 检测并重载
nginx -t
nginx -s reload

# 编写后端服务器测试页
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

# 重启查看状态
systemctl restart nginx
systemctl status nginx
systemctl enable nginx

# 查看端口号
netstat -pantul|grep nginx

测试后端服务器的Web服务

[root@nginx2 ~]# curl 192.168.80.12: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.80.12:8080/

企业级 Web 服务 Nginx 进阶16.png

2.2. 配置代理服务器

在前端服务器nginx1上执行

dnf安装的nginx

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.80.12: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 ~]# 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_pass http://192.168.80.12: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配置文件并启动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
[root@nginx1 ~]# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: di>
     Active: active (running) since Sun 2026-05-24 21:58:39 CST; 12s ago
   Main PID: 28751 (nginx)
      Tasks: 3 (limit: 22926)
     Memory: 3.1M
        CPU: 30ms
     CGroup: /system.slice/nginx.service
             ├─28751 "nginx: master process /usr/sbin/nginx"
             ├─28752 "nginx: worker process"
             └─28753 "nginx: worker process"

5月 24 21:58:39 nginx1.itcast.cn systemd[1]: Starting The nginx HTTP and revers>
5月 24 21:58:39 nginx1.itcast.cn nginx[28748]: nginx: the configuration file /e>
5月 24 21:58:39 nginx1.itcast.cn nginx[28748]: nginx: configuration file /etc/n>
5月 24 21:58:39 nginx1.itcast.cn systemd[1]: Started The nginx HTTP and reverse>
[root@nginx1 ~]#

2.3. 验证测试

http://192.168.80.11/

企业级 Web 服务 Nginx 进阶17.png

http://192.168.80.12:8080/

企业级 Web 服务 Nginx 进阶18.png

企业级 Web 服务 Nginx 进阶19.png

企业级 Web 服务 Nginx 进阶20.png

2.4. Nginx代理服务器暴力broken测试(拓展)

server {
    listen 80;
    server_name _;

    location / {
        return 500 "broken\n";
    }
}
[root@nginx1 nginx]# vim nginx.conf
[root@nginx1 nginx]# cat 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;
        server_name  _;
        location / {
        return 500 "broken\n";
       }
        #root         /usr/share/nginx/html;

        #location / {
            #proxy_pass http://192.168.80.12: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]# 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

http://192.168.80.11/

企业级 Web 服务 Nginx 进阶21.png
结论1:

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

结论2:

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

结论3:

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

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

3. HTTP/1.0与HTTP/1.1(拓展)

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

3.1. 主要区别对比表

特性HTTP/1.0HTTP/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.80.12: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 ~]# 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.80.11/

企业级 Web 服务 Nginx 进阶22.png

[root@nginx2 ~]# cat /usr/local/nginx/logs/access.log | tail -n 25
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y61.png HTTP/1.1" 200 10512 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y62.png HTTP/1.1" 200 16390 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y63.png HTTP/1.1" 200 20140 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y64.png HTTP/1.1" 200 20081 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y65.png HTTP/1.1" 200 3050 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y66.png HTTP/1.1" 200 5995 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y67.png HTTP/1.1" 200 86690 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y68.png HTTP/1.1" 200 9213 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y69.png HTTP/1.1" 200 754 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y70.png HTTP/1.1" 200 4318 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y71.png HTTP/1.1" 200 30447 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y72.png HTTP/1.1" 200 2614 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y73.png HTTP/1.1" 200 2242 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y74.png HTTP/1.1" 200 1383 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y75.png HTTP/1.1" 200 10319 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y76.png HTTP/1.1" 200 1571 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y77.png HTTP/1.1" 200 6055 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y78.png HTTP/1.1" 200 3401 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y79.png HTTP/1.1" 200 2284 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/y80.png HTTP/1.1" 200 3762 "http://192.168.80.12:8080/link/0.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /css/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2?v=4.7.0 HTTP/1.1" 200 77160 "http://192.168.80.12:8080/css/font-awesome-4.7.0/css/font-awesome.min.css" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.1 - - [24/May/2026:22:17:36 +0800] "GET /images/404.jpg HTTP/1.1" 404 555 "http://192.168.80.12:8080/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.11 - - [24/May/2026:22:29:23 +0800] "GET / HTTP/1.1" 200 6217 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.11 - - [24/May/2026:22:29:23 +0800] "GET /css/demo.css HTTP/1.1" 404 555 "http://192.168.80.11/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
192.168.80.11 - - [24/May/2026:22:29:24 +0800] "GET /images/404.jpg HTTP/1.1" 404 555 "http://192.168.80.11/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0"
[root@nginx2 ~]#

通过浏览器多次访问http://192.168.80.11/

企业级 Web 服务 Nginx 进阶23.png

3.2. 总结

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

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

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

四、Nginx 负载均衡(重点)

1. 业务背景

时间:2018.6.-2020.9

发布产品类型:互联网动态站点商城

用户数量: 20000-50000(用户量猛增)

PV:100000~200000(24小时访问次数总和)

DAU:8000(每日活跃用户数)

随着业务量骤增,之前单点服务器,已经不能够满足业务使用需要;因为流量太大,单点服务器宕机后无法提供业务,需要多台服务器,同时提供服务,业务才能稳定。

PV 和 DAU 是什么意思?

PV(Page View,页面浏览量)

DAU(Daily Active User,日活跃用户数)

2. 负载分类

企业级 Web 服务 Nginx 进阶24.png

2.1. 1)四层负载均衡(tcp)

网络层面的负载均衡

用ip+port接收请求,再转发到对应的机器

www.shop.com/ => 负载均衡器(192.168.80.100) => IP + 端口把请求转发出去

2.2. 2)七层负载均衡(http)

智能型负载均衡

根据虚拟的url地址,主机接收请求,再转向(反向代理)相应的处理服务器

www.shop.com/index.php => location .php$ {proxy_pass xxx}

www.shop.com/images/avatar.png => location .(jpg|jpeg|png|gif) {proxy_pass yyy}

2.3. 面试题:四层负载 vs 七层负载

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

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

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

企业级 Web 服务 Nginx 进阶25.png

3. 环境准备

角色IP主机名功能
lb1192.168.80.100lb1.itcast.cn负载均衡
web1192.168.80.11web1.itcast.cnWeb服务
web2192.168.80.12web2.itcast.cnWeb服务

企业级 Web 服务 Nginx 进阶26.png

3.1. 修改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.80.100  lb1   lb1.itcast.cn
192.168.80.11   web1  web1.itcast.cn
192.168.80.12   web2  web2.itcast.cn
EOF

3.2. 关闭防火墙与 SELinux

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

3.3. 安装依赖包时间同步(可选)

安装依赖包
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 服务器地址
    
如果遇到网络不通的问题,请执行以下命令
cat >/etc/resolv.conf<<EOF
nameserver 192.168.80.2
nameserver 114.114.114.114
EOF

3.3.1. NTPsec vs Chrony

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

4. 部署实践

4.1. 安装 Nginx

注意:如果遇到 Nginx 安装很慢或者失败等问题,请配置好 dnf/yum 源!

阿里源

cat >/etc/yum.repos.d/aliyun.repo<<EOF
[baseos]
name=CentOS Stream \$releasever - BaseOS
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1

[baseos-debug]
name=CentOS Stream \$releasever - BaseOS - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[baseos-source]
name=CentOS Stream \$releasever - BaseOS - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/BaseOS/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[appstream]
name=CentOS Stream \$releasever - AppStream
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1

[appstream-debug]
name=CentOS Stream \$releasever - AppStream - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[appstream-source]
name=CentOS Stream \$releasever - AppStream - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/AppStream/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[crb]
name=CentOS Stream \$releasever - CRB
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0

[crb-debug]
name=CentOS Stream \$releasever - CRB - Debug
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[crb-source]
name=CentOS Stream \$releasever - CRB - Source
baseurl=https://mirrors.aliyun.com/centos-stream/\$stream/CRB/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[highavailability]
name=CentOS Stream \$releasever - HighAvailability
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0

[highavailability-debug]
name=CentOS Stream \$releasever - HighAvailability - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[highavailability-source]
name=CentOS Stream \$releasever - HighAvailability - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/HighAvailability/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[nfv]
name=CentOS Stream \$releasever - NFV
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0

[nfv-debug]
name=CentOS Stream \$releasever - NFV - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[nfv-source]
name=CentOS Stream \$releasever - NFV - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/NFV/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[rt]
name=CentOS Stream \$releasever - RT
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0

[rt-debug]
name=CentOS Stream \$releasever - RT - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[rt-source]
name=CentOS Stream \$releasever - RT - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/RT/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[resilientstorage]
name=CentOS Stream \$releasever - ResilientStorage
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/os/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=0

[resilientstorage-debug]
name=CentOS Stream \$releasever - ResilientStorage - Debug
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/\$basearch/debug/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[resilientstorage-source]
name=CentOS Stream \$releasever - ResilientStorage - Source
baseurl=http://mirrors.aliyun.com/centos-stream/\$stream/ResilientStorage/source/tree/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[extras-common]
name=CentOS Stream \$releasever - Extras packages
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/\$basearch/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1

[extras-common-source]
name=CentOS Stream \$releasever - Extras packages - Source
baseurl=http://mirrors.aliyun.com/centos-stream/SIGs/\$stream/extras/source/extras-common/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-Extras-SHA512
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
EOF

清华源

cat >/etc/yum.repos.d/tsinghua.repo<<'EOF'
[baseos]
name=CentOS Stream $releasever - BaseOS
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/BaseOS/$basearch/os
# metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1

[baseos-debuginfo]
name=CentOS Stream $releasever - BaseOS - Debug
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/BaseOS/$basearch/debug/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-debug-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[baseos-source]
name=CentOS Stream $releasever - BaseOS - Source
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/BaseOS/source/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-baseos-source-$stream&arch=source&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[appstream]
name=CentOS Stream $releasever - AppStream
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/AppStream/$basearch/os
# metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1

[appstream-debuginfo]
name=CentOS Stream $releasever - AppStream - Debug
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/AppStream/$basearch/debug/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-debug-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[appstream-source]
name=CentOS Stream $releasever - AppStream - Source
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/AppStream/source/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-appstream-source-$stream&arch=source&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[crb]
name=CentOS Stream $releasever - CRB
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/CRB/$basearch/os
# metalink=https://mirrors.centos.org/metalink?repo=centos-crb-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
countme=1
enabled=1

[crb-debuginfo]
name=CentOS Stream $releasever - CRB - Debug
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/CRB/$basearch/debug/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-crb-debug-$stream&arch=$basearch&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0

[crb-source]
name=CentOS Stream $releasever - CRB - Source
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos-stream/$releasever-stream/CRB/source/tree/
# metalink=https://mirrors.centos.org/metalink?repo=centos-crb-source-$stream&arch=source&protocol=https,http
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
gpgcheck=1
repo_gpgcheck=0
metadata_expire=6h
enabled=0
EOF

在三台Linux服务器上都安装Nginx

# 在 Web1 和 Web2 和 LB1 上安装 Nginx
dnf install -y nginx
systemctl start nginx
systemctl enable nginx

查看Nginx状态

systemctl status nginx --no-pager

企业级 Web 服务 Nginx 进阶27.png

4.2. 配置 Web1 & Web2

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

# 在LB1上执行,统一 一下三台的nginx配置文件(可选)
scp /etc/nginx/nginx.conf 192.168.80.11:/etc/nginx/
scp /etc/nginx/nginx.conf 192.168.80.12:/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 Server1" > /usr/local/nginx/html/index.html

企业级 Web 服务 Nginx 进阶28.png

企业级 Web 服务 Nginx 进阶29.png

企业级 Web 服务 Nginx 进阶30.png

4.3. 配置 LB1

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

4.3.1. 第一步:查看 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 ~]#

4.3.2. 第二步:配置负载均衡

说明:

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

在 LB1 上操作

[root@lb1 ~]# vim /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;

    upstream my_web_service {
        server 192.168.80.11:80;
        server 192.168.80.12:80;
    }

    server {
        listen       80;
        listen       [::]:80;

        server_name  192.168.80.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 {
        }
    }
}
[root@lb1 ~]#

4.3.3. 第三步:重载配置,验证测试

在 LB1 上操作

[root@lb1 ~]# nginx -s reload
[root@lb1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@lb1 ~]# nginx -s reload
[root@lb1 ~]# curl 192.168.80.100
This is Web Server1
[root@lb1 ~]# curl 192.168.80.100
This is Web Server2
[root@lb1 ~]# curl 192.168.80.100
This is Web Server1
[root@lb1 ~]# curl 192.168.80.100
This is Web Server2
[root@lb1 ~]#

注意:如果无法访问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

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

企业级 Web 服务 Nginx 进阶31.png

企业级 Web 服务 Nginx 进阶32.png

页面在 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

企业级 Web 服务 Nginx 进阶33.png

黑客数字雨
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

企业级 Web 服务 Nginx 进阶34.png

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

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

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

企业级 Web 服务 Nginx 进阶35.png

企业级 Web 服务 Nginx 进阶36.png

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

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

[root@lb1 ~]# vi /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;

    upstream my_web_service {
        server 192.168.80.11:80;
        server 192.168.80.12:80;
    }

    server {
        listen       80;
        listen       [::]:80;

        server_name  192.168.80.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 {
        }
    }
}
[root@lb1 ~]# /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 上,验证测试

企业级 Web 服务 Nginx 进阶37.png

在 Web2 上, 验证测试

企业级 Web 服务 Nginx 进阶38.png

验证宿主机 IP

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

企业级 Web 服务 Nginx 进阶39.png

5. 负载均衡常见错误汇总

常见错误1:请求已经转发了,但是一会正常一会不正常

答:默认情况下,负载均衡采用的是轮询算法,Web01一次,Web02一次,如果其中某台Web服务器有异常,则会出现以上问题。异常大部分都是Nginx没有启动。

6. 分发请求关键字

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

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

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

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

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

7. 扩展

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

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

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

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

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

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

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

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

小结:

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

weight:weight=8

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

7.2. 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.80.11:80;
                server 192.168.80.12:80;
        }
        ...
}

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

五、扩展: HAProxy

1. Introduction

官方地址:https://www.haproxy.org/

企业级 Web 服务 Nginx 进阶40.png

企业级 Web 服务 Nginx 进阶41.png

HAProxy, which stands for High Availability Proxy(这个就是HA简写的来历), is a popular opensource software TCP/HTTP LoadBalancer and proxying solution which can be run on Linux, Solaris, and FreeBSD. Its most common use is to improve the performance and reliability of a server environment by distributing the workload across multiple servers(e.g. web, application, database). It is used in many high-profile environments, including: GitHub, Imgur, Instagram, and Twitter. In this guide, we will provide a general overview of what HAProxy is,basic load-balancing terminology, and examples of how it might be used to improve the performance and reliability of your own server environment.

简言之:HAProxy就是一款高性能的负载均衡器,而是一个开源的软件。支持TCP以及HTTP协议的应用。(支持四层也支持七层)

Nginx < HAProxy < LVS(DR模式)

< 符号直观体现了三者的性能梯度 ——从应用层的多功能工具(Nginx),到更专注的负载均衡软件(HAProxy),再到内核级的高性能转发工具(LVS DR 模式),处理高并发的能力依次增强。

实际使用中需根据业务规模(并发量、功能需求)选择,而非一味追求 “性能最高”。

2. Load Balance

No Load Balancing

A simple web application environment with no load balancing might look like the following: In this example, the user connects directly to your web server, at your domain.com and there is no load balancing. If your single webserver goes down, the user will no longer be able to access your webserver. Additionally, if many users are trying to access your server simultaneously and it is unable to handle the load, they may have a slow experience or they may not be able to connect at all.

企业级 Web 服务 Nginx 进阶42.png

Layer 4 Load Balancing

The simplest way to load balance network traffic to multiple servers is to use layer 4 (transport layer) load balancing. Load balancing this way will forward user traffic based on IP range and port (i.e. if a request comes in for http://yourdomain.com/anything, the traffic will be forwarded to the backend that handles all the requests for yourdomain.com on port 80). For more details on layer 4, check out the TCP subsection of our Introduction to Networking. Here is a diagram of a simple example of layer 4 load balancing: The user accesses the load balancer, which forwards the user's request to the web-backend group of backend servers. Whichever backend server is selected will respond directly to the user's request. Generally, all of the servers in the web-backend should be serving identical content--otherwise the user might receive inconsistent content. Note that both web servers connect to the same database server.

企业级 Web 服务 Nginx 进阶43.png

Layer 7 Load Balancing

Another, more complex way to load balance network traffic is to use layer 7 (application layer) load balancing. Using layer 7 allows the load balancer to forward requests to different backend servers based on the content of the user's request. This mode of load balancing allows you to run multiple web application servers under the same domain and port. For more details on layer 7, check out the HTTP subsection of our Introduction to Networking. Here is a diagram of a simple example of layer 7 load balancing: In this example, if a user requests yourdomain.com/blog, they are forwarded to the blog backend, which is a set of servers that run a blog application. Other requests are forwarded to web-backend,which might be running another application. Both backends use the same database server, in this example.

企业级 Web 服务 Nginx 进阶44.png

3. HAProxy配置

3.1. 环境准备

序号主机IP主机名备注
1192.168.80.11web1.itcast.cn沿用《Nginx负载均衡》的机器
2192.168.80.12web2.itcast.cn沿用《Nginx负载均衡》的机器
3192.168.80.100haproxy.itcast.cn沿用《Nginx负载均衡》的机器,但是卸载掉 Nginx

准备一台主机,配置 HAProxy 主机名称、IP地址

[root@lb1 ~]# hostnamectl set-hostname haproxy.itcast.cn && bash
[root@haproxy ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:69:10:67 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 192.168.80.100/24 brd 192.168.80.255 scope global noprefixroute ens160
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe69:1067/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
[root@haproxy ~]#

3.2. 安装HAPorxy

# 确保没有安装 Nginx,没有安装 keepalived。
dnf remove nginx keepalived -y

# 安装 haproxy
dnf install haproxy -y

# 验证测试
dnf list installed | grep -E 'ngxin|haproxy'

企业级 Web 服务 Nginx 进阶45.png

4. haproxy.cfg配置(了解)

4.1. 整体参数分类

[root@haproxy ~]#  grep -E -v '#|^$' /etc/haproxy/haproxy.cfg
global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats
    ssl-default-bind-ciphers PROFILE=SYSTEM
    ssl-default-server-ciphers PROFILE=SYSTEM
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000
frontend main
    bind *:5000
    acl url_static       path_beg       -i /static /images /javascript /stylesheets
    acl url_static       path_end       -i .jpg .gif .png .css .js
    use_backend static          if url_static
    default_backend             app
backend static
    balance     roundrobin
    server      static 127.0.0.1:4331 check
backend app
    balance     roundrobin
    server  app1 127.0.0.1:5001 check
    server  app2 127.0.0.1:5002 check
    server  app3 127.0.0.1:5003 check
    server  app4 127.0.0.1:5004 check
[root@haproxy ~]#

HAProxy 的主配置文件位于 /etc/haproxy/haproxy.cfg,主要分为四个部分:

global # 全局参数,进程级配置

defaults # 默认参数,应用于后续的frontend/backend

frontend # 定义接收客户端请求的监听接口

backend # 定义后端服务器集群及负载均衡算法

4.2. ☆ 全局配置 global、dmk

global
        maxconn         20000
        # 最大连接数限制为 20000。

        ulimit-n        16384
        # 设置文件描述符的最大数量为 16384。

        log             127.0.0.1 local0
        # 配置日志系统,日志发送到本地 syslog 的 local0。

        uid             200
        # 运行进程的用户 ID 为 200。

        gid             200
        # 运行进程的组 ID 为 200。

        chroot          /var/empty
        # 更改运行环境的根目录为 /var/empty,提高安全性。

        daemon
        # 设置为后台运行模式。

4.3. ☆ 前端配置解析 frontend

frontend test-proxy
        bind            192.168.200.10:8080
        # 监听地址为 192.168.200.10,端口为 8080。

        mode            http
        # 前端模式为 HTTP。

        log             global
        # 使用全局日志配置。

        option          httplog
        # 启用 HTTP 请求的日志记录。

        option          dontlognull
        # 忽略对空连接(如健康检查)的日志记录。

        maxconn         8000
        # 前端的最大并发连接数限制为 8000。

        timeout client  30s
        # 客户端连接超时时间为 30 秒。

        # layer3: Valid users
        acl allow_host src 192.168.200.150/32
        # 定义访问控制列表(ACL):允许来源 IP 为 192.168.200.150 的用户。

        http-request deny if !allow_host
        # 如果请求不满足 `allow_host` 条件,则拒绝访问。

        # layer7: prevent private network relaying
        acl forbidden_dst url_ip 192.168.0.0/24
        # 定义 ACL:目标地址在 192.168.0.0/24 网段时禁止访问。

        acl forbidden_dst url_ip 172.16.0.0/12
        # 定义 ACL:目标地址在 172.16.0.0/12 网段时禁止访问。

        acl forbidden_dst url_ip 10.0.0.0/8
        # 定义 ACL:目标地址在 10.0.0.0/8 网段时禁止访问。

        http-request deny if forbidden_dst
        # 如果请求满足 `forbidden_dst` 条件,则拒绝访问。

        default_backend test-proxy-srv
        # 设置默认后端为 `test-proxy-srv`。

4.4. ☆ 后端配置解析 backend

backend test-proxy-srv
        mode            http
        # 后端模式为 HTTP。

        timeout connect 5s
        # 与后端服务器建立连接的超时时间为 5 秒。

        timeout server  5s
        # 后端服务器响应的超时时间为 5 秒。

        retries         2
        # 后端服务器连接失败时的重试次数为 2 次。

        # layer7: Only GET method is valid
        acl valid_method        method GET
        # 定义 ACL:仅允许 HTTP 方法为 GET 的请求。

        http-request deny if !valid_method
        # 如果请求的 HTTP 方法不是 GET,则拒绝访问。

        # take IP address from URL's authority
        # and drop scheme+authority from URI
        http-request set-dst url_ip
        # 从 URL 中提取目标 IP 地址并设置为后端的目标地址。

        http-request set-dst-port url_port
        # 从 URL 中提取目标端口并设置为后端的目标端口。

        http-request set-uri %[pathq]
        # 将 URI 设置为仅包含路径和查询字符串,去掉 scheme 和 authority。

        server next-hop 0.0.0.0
        # 配置后端服务器为 0.0.0.0(动态从请求中获取目标地址)。

        # layer7: protect bad reply
        http-response deny if { res.hdr(content-type) audio/mp3 }
        # 如果后端服务器返回的响应头中 `Content-Type` 为 `audio/mp3`,则拒绝响应。

后端配置(backend)的关键参数:

balance:负载均衡算法(如 roundrobin、leastconn、source)

server:定义后端服务器(格式:server 名称 IP:端口 [参数])

check:启用健康检查

inter:健康检查间隔(毫秒)

fall:连续失败几次后标记为不可用

rise:连续成功几次后标记为可用

5. 配置负载均衡

vi /etc/haproxy/haproxy.cfg

... (省略其他内容)

frontend main
    bind *:80        # 改成 80 端口
    acl url_static       path_beg       -i /static /images /javascript /stylesheets
    acl url_static       path_end       -i .jpg .gif .png .css .js

    use_backend static          if url_static
    default_backend             app
    
backend app
    balance     roundrobin                    # 这里是默认的 rr 算法
    server server1 192.168.80.11:80 check    
    
    server server2 192.168.80.12:80 check

6. 验证测试

# 检查配置语法
haproxy -c -f /etc/haproxy/haproxy.cfg

# 开机自启 HAProxy
systemctl restart haproxy
systemctl enable haproxy --now

# 检查状态
systemctl status haproxy
[root@haproxy ~]# haproxy -c -f /etc/haproxy/haproxy.cfg
Configuration file is valid
[root@haproxy ~]# systemctl restart haproxy.service
[root@haproxy ~]# systemctl status haproxy.service
● haproxy.service - HAProxy Load Balancer
     Loaded: loaded (/usr/lib/systemd/system/haproxy.service; disabled; preset:>
     Active: active (running) since Mon 2026-05-25 00:27:58 CST; 7s ago
    Process: 55444 ExecStartPre=/usr/sbin/haproxy -f $CONFIG -f $CFGDIR -c -q $>
   Main PID: 55446 (haproxy)
     Status: "Ready."
      Tasks: 3 (limit: 22926)
     Memory: 8.3M
        CPU: 37ms
     CGroup: /system.slice/haproxy.service
             ├─55446 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/>
             └─55448 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/>

5月 25 00:27:58 haproxy.itcast.cn haproxy[55446]: [ALERT]    (55446) : config :>
5月 25 00:27:58 haproxy.itcast.cn haproxy[55446]: [NOTICE]   (55446) : New work>
5月 25 00:27:58 haproxy.itcast.cn haproxy[55446]: [NOTICE]   (55446) : Loading >
5月 25 00:27:58 haproxy.itcast.cn haproxy[55448]: [WARNING]  (55448) : Server s>
5月 25 00:27:58 haproxy.itcast.cn haproxy[55448]: [ALERT]    (55448) : backend >
5月 25 00:27:58 haproxy.itcast.cn systemd[1]: Started HAProxy Load Balancer.
5月 25 00:27:59 haproxy.itcast.cn haproxy[55448]: [WARNING]  (55448) : Server a>
5月 25 00:27:59 haproxy.itcast.cn haproxy[55448]: [WARNING]  (55448) : Server a>
5月 25 00:27:59 haproxy.itcast.cn haproxy[55448]: [WARNING]  (55448) : Server a>
[root@haproxy ~]#
[root@haproxy ~]# systemctl enable haproxy.service
Created symlink /etc/systemd/system/multi-user.target.wants/haproxy.service → /usr/lib/systemd/system/haproxy.service.

一会儿访问 Web1

企业级 Web 服务 Nginx 进阶46.png

一会儿访问 Web2

企业级 Web 服务 Nginx 进阶47.png

7. 常见错误

请求时,一会正常一会不正常。有一台服务器并没有正常工作 解决办法:一台服务器一台测试,看看具体哪个后端服务宕机

六、扩展: HAProxy 调度算法

balance roundrobin       # 轮询,软负载均衡基本都具备这种算法
balance static-rr        # 根据权重,建议使用        =>  server ...  weight 权重值
balance leastconn        # 最少连接者先处理,建议使用
balance source           # 根据请求源IP,建议使用(类似IP_HASH)
balance uri              # 根据请求的URI
balance url_param        # 根据请求的URl参数
balance hdr(name)        # 根据HTTP请求头来锁定每一次HTTP请求
balance rdp-cookie(name) # 根据cookie(name)来锁定并哈希每一次TCP请求

特殊算法解析:

1. balance uri

描述:根据请求的 URI(Uniform Resource Identifier)来决定负载均衡。对于相同的 URI,会将请求发到同一个服务器。

应用场景:适用于需要将同一个静态资源(如 /images/logo.png)始终从同一台服务器提供的场景,以利用缓存并提高性能。

例子:浏览器请求 http://example.com/images/logo.png 与 http://example.com/images/banner.png 可能分别被定向到两个不同的服务器。

2. balance url_param

描述:依据请求 URL 中的特定参数来决定负载均衡。会查找 URL 中的指定参数并利用其值来锁定服务器。

应用场景:适用于当 URL 参数(如用户 ID)决定了用户数据应该被哪台服务器处理的场合。

例子:请求 http://example.com/page?user=123 和 http://example.com/page?user=456 会根据参数 user 的不同值,可能被发送到不同的服务器。

3. balance hdr(name)

描述:使用 HTTP 请求头的值来进行负载均衡。name 是指定的请求头名称。

应用场景:适用于业务逻辑中某个请求头(如 User-Agent,或自定义的 X-Client-Id)用于分配请求的情况。

例子:请求头中含有 X-Client-Id: ABC123 和 X-Client-Id: DEF456 两者可能会被分配到不同的服务器。

4. balance rdp-cookie(name)

描述:基于名为 name 的 RDP cookie 值的哈希结果来进行负载均衡。这与 HTTP cookie 类似,但用于一些 RDP (Remote Desktop Protocol) 的负载均衡场景。

应用场景:适用于 RDP 连接,帮助同一用户会话返回到同一台服务器。

例子:类似于 HTTP 的会话黏性,确保用户会话的连续性。

七、扩展:业界发行版本

作用:普及一些Nginx发行版本,方便以后进行选择!

1. 淘宝的Tengine

http://tengine.taobao.org/

Tengine(Tabbao engine)是alibaba公司,在nginx的基础上,开发定制,服务自己业务的服务器软件。后来进行了开源。

# tar xvf tengine-3.1.0.tar.gz
# cd tengine-3.1.0
# ./configure --prefix=/usr/local/tengine
# make && make install

2. OpenResty

openresty 在nginx的基础上,结合lua脚本实现高并发等web平台。

WAF nginx+lua+redis 实现应用型防火墙

章亦春 http://openresty.org/cn/

美团官方用的就是OpentRestyhttps://www.meituan.com/

安装步骤:

# tar xvf openresty-1.25.3.2.tar.gz
# cd openresty-1.25.3.2
# ./configure --prefix=/usr/local/openresty
# make && make install