Nginx 错误页
Nginx 的 error_page 指令允许你自定义错误响应页面,提升用户体验。
基本语法
error_page code ... [=[response]] uri;常见配置示例
基本错误页面配置
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;指定完整路径
error_page 404 = /error_pages/404.html;更改响应状态码
error_page 404 =200 /not_found.html; # 返回404内容但状态码为200
error_page 404 = /not_found.html; # 保持原始状态码404使用命名位置
error_page 404 @not_found;
location @not_found {
return 301 /new-location;
}直接返回文本
error_page 403 /403.html;
location = /403.html {
internal;
return 403 'Forbidden: You don\'t have permission to access this page';
}多错误码指向同一页面
error_page 400 401 402 403 404 /4xx.html;
error_page 500 501 502 503 504 /5xx.html;变量动态生成错误页
error_page 404 @custom_error;
location @custom_error {
add_header Content-Type text/html;
return 404 "<html><body><h1>404 Not Found</h1><p>Requested URI: $uri</p></body></html>";
}完整配置模板
# 全局块
user www;
worker_processes auto; # 工作进程数(通常设为CPU核心数)
error_log /var/log/nginx/error.log warn; # 错误日志路径及级别
pid /var/run/nginx.pid; # PID文件路径
worker_rlimit_nofile 65535; # 单个进程最大文件打开数
# 事件块
events {
worker_connections 2048; # 每个Worker的最大连接数
multi_accept on; # 是否一次性接受所有新连接
use epoll; # 事件驱动模型(Linux推荐epoll)
}
http {
# 隐藏版本信息
server_tokens off;
# 共享内存区域,用于多工作进程间状态同步
upstream backend {
zone backend_zone 64k;
least_conn; # 最少连接算法
ip_hash; # 会话保持
server 192.168.1.101:8080 weight=3 max_fails=3 fail_timeout=30s;
server 192.168.1.102:8080 weight=2 max_fails=3 fail_timeout=30s;
server backup.example.com:8080 backup; # 备份节点
keepalive 32; # 连接池大小
}
# 增强日志格式
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct="$upstream_connect_time" '
'uht="$upstream_header_time" urt="$upstream_response_time"';
server {
listen 80;
server_name example.com;
access_log /var/log/nginx/access.log main;
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 3h;
add_header Cache-Control "public";
}
# API速率限制
location /api/ {
limit_req zone=api_limit burst=200 nodelay;
proxy_pass http://backend;
proxy_connect_timeout 5s; # 连接超时
proxy_read_timeout 30s; # 响应读取超时
proxy_set_header Host $host; # 传递原始请求头
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 错误处理
proxy_next_upstream error timeout http_500 http_502 http_504;
}
# 状态监控
location /nginx_status {
stub_status;
allow 192.168.1.0/24;
deny all;
}
}
# 请求限制区域定义
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
}Nginx 统一配置文件
在Nginx安装目录的conf中创建conf.d目录,所有的server块配置都放在conf.d目录下,文件以.conf结尾
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
include conf.d/www.conf; #虚拟网站配置信息统一放在了当前的conf.d目录下
}Nginx 状态信息
确认安装模块
状态模块--with-http_stub_status_module在编译时指定。
[root@localhost ]# nginx -V
nginx version: nginx/1.26.3
built by gcc 12.3.1 (openEuler 12.3.1-30.oe2403) (GCC)
built with OpenSSL 3.0.12 24 Oct 2023
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --user=www --group=www --with-http_stub_status_module --with-http_ssl_module状态模块配置
server{
listen 80;
server_name status.com;
location / {
stub_status on; #开启状态信息功能
access_log off; #不记录访问日志
}
}结果解析
Active connections: 1
server accepts handled requests
47 47 45
Reading: 0 Writing: 1 Waiting: 0- 活动连接(Active connections):表示当前 Nginx 正在处理的 活动连接数 为 1 个(包括正在读取、写入和等待的连接)
- 连接统计 (server accepts handled requests):
- accepts: 47 - 表示 Nginx 自启动以来 接受的客户端连接总数(TCP 连接)。
- handled: 47 - 表示 Nginx 成功处理的连接数(通常等于
accepts,除非达到worker_connections限制)。 - requests: 45 - 表示 Nginx 处理的 HTTP 请求总数(一个连接可以发送多个请求,如 HTTP Keep-Alive)。
- 当前连接状态 (Reading, Writing, Waiting)
- Reading (0): 当前有 0 个连接 正在读取客户端请求(Nginx 正在接收请求头或请求体)。
- Writing (1): 当前有 1 个连接 正在向客户端发送响应(Nginx 正在返回数据)。
- Waiting (0): 当前有 0 个连接 处于空闲状态(Keep-Alive 连接,等待客户端发送新请求)
数据库读写分离
将读请求分发到多个从库,写请求定向到主库
stream {
upstream mysql_read {
server read1.example.com:3306;
server read2.example.com:3306;
}
upstream mysql_write {
server write.example.com:3306;
}
server {
listen 3306;
proxy_pass mysql_read;
}
}- 使用Nginx的stream模块实现TCP层负载均衡
- 结合中间件(如MySQL Router)实现更智能的路由
Nginx 域名配置
本机业务
server {
listen 8080;
server_name www.example.com;
location / {
root html;
index index.html;
try_files $uri $uri/ /index.html;
}
}反向代理
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://192.168.1.10;
}
}负载均衡
upstream example.com {
server 192.168.10.2:8080;
...
}
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://192.168.1.10;
proxy_set_header host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}二级目录
服务端
server {
listen 80;
server_name www.example.com;
location /article {
root /data/wwwroot/www;
index index.html;
}
}负载均衡配置
server {
listen 80;
server_name www.example.com;
location /article {
proxy_pass http://192.168.1.10;
proxy_set_header host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}静态资源
server {
location /page/ {
alias /home/user/web/page/dist/;
try_files $uri $uri/ /page/index.html;
}
}当浏览器访问 https://example.com/page 时,nginx 会代理到 /home/user/web/page/dist/目录,此时,$uri 就表示 /page。
try_files 会先检查 alias 目录下 page文件是否存在,存在则返回该文件;
然后会检查 page/目录是否存在,存在则返回 page/ 目录下的 index.xml(page 不带斜杠表示文件,page/ 带斜杠表示目录);
最后如果都找不到,则返回 /page/index.html ,此时 /page/表示相对目录,和上面的 location /page/表示一个意思,即 alias 表示的路径,所以 /page/index.html 完整的路径表示 /home/user/web/page/dist/index.html
alias 和 root 的区别?
- alias 是一个目录别名的定义,可以直接替换,比如 /page/ 就表示 /home/user/web/page/dist/
- root 是最上层目录的定义,访问 /page/ 则表示 访问 root 后面的目录 + /page/,即 /home/user/web/page/dist/page/
反向代理
单节点的反向代理配置,将 HTTP 请求转发的后端服务器,但是只能代理到单节点,无法在集群中使用。
server {
# 二级目录
location /testapi/ {
proxy_pass http://178.168.1.10:9120/;
index /; # index.html index.htm;
proxy_set_header Host $host;
# 表示与这个nginx 直接通信的IP, 如果这个是第一层代理,这将是最真实的客户端IP
proxy_set_header X-Real-IP $remote_addr;
# 表示与这个nginx 直接通信的Port, 如果这个是第一层代理,这将是最真实的客户Port
proxy_set_header X-Real-Port $remote_port;
# NGINX 在转发请求时会将客户端的 IP 地址添加到 X-Forwarded-For 头部
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 8M;
client_body_buffer_size 128k;
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}负载均衡
负载均衡配置 用于将 HTTP 请求分布到多个节点的 后端服务器;负载均衡功能支持自动下线,当某一台节点服务端返回 500,则会自动下线该节点不再访问。负载均衡的配置可以单独写成 conf 文件。
upstream openserver-api {
# ip_hash; 根据访问ip的hash结果分配
# least_conn;请求分配到连接数最少的服务
# fair; 请求分配到后端响应的时间最短
server 127.0.0.1:8900 weight=100 max_fails=10 fail_timeout=15s;
server 127.0.0.1:8901 weight=100 max_fails=10 fail_timeout=15s;
}
server {
location /test-api/{
proxy_pass http://openserver-api/;
index /; # index.html index.htm;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 8M;
client_body_buffer_size 128k;
}
}- max_fails:出现N次失败,负载均衡停止转发流量
- fail_timeout:在N秒内失败
Nginx 代理MySQL
确保 Nginx 编译时包含了 --with-stream 模块
stream {
server {
listen 3306;
proxy_pass mysql_backend;
proxy_connect_timeout 1s;
proxy_timeout 3s;
}
upstream mysql_backend {
server mysql_server1:3306;
server mysql_server2:3306 backup;
}
}Nginx 代理Redis
stream {
server {
listen 6379;
proxy_pass redis_backend;
}
upstream redis_backend {
server redis1:6379;
server redis2:6379;
}
}Nginx CORS 跨域
基础 CORS
location /api/ {
# 允许所有域名跨域访问(生产环境不推荐)
add_header 'Access-Control-Allow-Origin' '*';
# 允许的请求方法
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
# 允许的请求头
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Accept,Origin';
# 预检请求缓存时间
add_header 'Access-Control-Max-Age' 1728000;
# 允许携带凭据(如cookies)
add_header 'Access-Control-Allow-Credentials' 'true';
}预检请求(OPTIONS)处理
location /api/ {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://client.example.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
# 正常请求处理...
}多域名动态允许
# 使用map定义允许的域名列表
map $http_origin $allowed_origin {
default "";
"~^https://(www\.)?example\.com$" $http_origin;
"~^https://app\.example\.org$" $http_origin;
"~^https://staging\.example\.net$" $http_origin;
}
server {
location /api/ {
if ($cors_origin) {
add_header 'Access-Control-Allow-Origin' $allowed_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
# 处理OPTIONS请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,X-Requested-With';
add_header 'Access-Control-Max-Age' 1728000;
return 204;
}
}
}安全增强
server {
location /api/ {
...
# 安全增强
server {
# 基础安全头
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "DENY";
add_header X-XSS-Protection "1; mode=block";
# 增强安全头
add_header Content-Security-Policy "default-src 'self' https:; frame-ancestors 'none'";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Referrer-Policy "strict-origin-when-cross-origin";
# 隐私保护
add_header Permissions-Policy "geolocation=(), microphone=()";
add_header Clear-Site-Data "\"cache\", \"cookies\", \"storage\"";
}
...
}
}| HTTP 头 | 值 | 作用 |
|---|---|---|
X-Content-Type-Options | nosniff | 禁止浏览器自动推断 MIME 类型,防止 MIME 混淆攻击 |
X-Frame-Options | DENY | 禁止页面被嵌入 <iframe>,防止点击劫持 |
X-XSS-Protection | 1; mode=block | 启用 XSS 过滤,检测到攻击时阻止页面加载 |
Content-Security-Policy | default-src 'self' | 限制资源加载来源,防止 XSS/数据注入 |
Strict-Transport-Security | max-age=63072000; includeSubDomains; preload | 强制 HTTPS,防止 SSL 剥离攻击 |
X-Permitted-Cross-Domain-Policies | none | 禁止跨域策略文件(如 Flash/PDF 的 crossdomain.xml) |
Referrer-Policy | no-referrer-when-downgrade | 控制 Referer 头,防止 URL 泄露 |
Feature-Policy | microphone 'none'; camera 'none' | 禁用浏览器敏感 API(如摄像头、麦克风) |
X-DNS-Prefetch-Control | off | 禁止 DNS 预解析,防止隐私泄露 |
Cross-Origin-Resource-Policy | same-origin | 限制跨域资源加载 |
Cross-Origin-Opener-Policy | same-origin | 防止跨窗口攻击(如 Spectre) |
Cross-Origin-Embedder-Policy | require-corp | 强制跨域资源使用 CORS 或 CORP |
Permissions-Policy | geolocation=(), microphone=() | 替代 Feature-Policy,控制浏览器 API 权限 |
Clear-Site-Data | "cache", "cookies", "storage" | 强制清除客户端缓存、Cookie 和存储数据 |
隐藏版本号
在浏览器响应头里有 Server 项,这里返回的是当前服务 web 服务器的名称,如 Nginx、Kong 等。
但是这里不应该把服务器的版本号返回出来,万一版本有漏洞,会被针对攻击。
# 1、关闭 http{} 的 server_tokens
server_tokens off;
#2、修改 ../nginx/conf/fastcgi_params
fastcgi_params SERVER_SOFTWARE
nginx/$nginx_version
# 改为
fastcgi_params SERVER_SOFTWARE nginxfastcgi_params 这个文件里的存放的都是 Nginx 环境变量。
日志 JSON 格式化
将 Nginx 的日志格式化为 JSON,可以修改 log_format 指令,将日志字段转化为 JSON 格式。
JSON 格式的日志,更适合日志聚合和后续处理,比如 ELK, Flume 等工具。
JSON 格式化配置:
http{
log_format json '{
"remote_addr": "$remote_addr",
"connection": "$connection",
"connection_requests": "$connection_requests",
"remote_user": "$remote_user",
"time_local": "$time_local",
"request_length": "$request_length",
"request": "$request",
"status": "$status",
"request_time": "$request_time",
"upstream_response_time": "$upstream_response_time",
"body_bytes_sent": "$body_bytes_sent",
"content_length": "$content_length",
"http_x_forwarded_for": "$http_x_forwarded_for",
"upstream_addr": "$upstream_addr",
"http_referer": "$http_referer",
"http_user_agent": "$http_user_agent"
}';
# 日志格式可以引用main ,也可以引用 json
access_log /var/log/nginx/access.log json;
}确保将此配置添加到 http 块中,并设置 access_log 指令以使用这个 JSON 格式:
配置各种响应头
配置响应头是为了告诉浏览器某些操作,**比如禁止缓存、禁止iframe嵌套等,**Nginx 作为 Web 服务器,支持设置响应头。加在 server 里可以全局统一
location / {
# 禁止浏览器缓存
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires 0;
#该页面不允许在frame中展示,另外还有 SAMEORIGIN(表示该页面可以在相同域名页面的frame中展示),
# ALLOW-FROM url(页面可以在指定来源的frame中展示)
# 这个头加之前需要和前端同步
add_header X-Frame-Options:DENY
#启用XSS保护;
add_header X-Xss-Protection: 1;
add_header X-Xss-Protection: mod=block;
# 严格按照 Content-Type指定的类型加载,直接猜测
add_header X-Content-Type-Options "nosniff";
#指定哪些域名可以访问当前资源
add_header Access-Control-Allow-Origin "*";
#防止浏览器在下载文件时自动执行内容(如 JS 文件)
add_header X-Download-Options "noopen";
# 默认只允许加载与页面相同源的资源,帮助防止跨站脚本攻击(XSS)
add_header Content-Security-Policy "default-src 'self';" always;
# 启用 HSTS,强制所有连接使用 HTTPS,禁止304 跳转
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}IP限流
我们系统上线后可能会遭遇外部刷接口、暴力测试等行为,尤其是权益类的服务,羊毛党的黄牛特别多。我之前有做过权益兑换系统,这个服务经常会被暴力刷接口,我们可以通过 Nginx 限流机制,熔断刷子流量,从而提升服务可用性。
在 Nginx 中,可以使用 限流(Rate Limiting)功能来控制进入服务器的请求数量。Nginx 提供了两个主要的限流模块:
- limit_req:限制请求的速率(单位时间内请求的次数)。
- limit_conn:限制并发连接数(每个 IP 地址允许的最大并发连接数)。
limit_req - 限制请求速率
limit_req 模块可以限制特定 IP 地址的请求频率。例如,限制每秒钟一个 IP 地址只能发出一定数量的请求。
http {
# 定义一个限流区域
limit_req_zone$binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;
server {
listen 80;
server_name example.com;
location / {
# 使用上面定义的限流区域,限制请求频率
limit_req zone=req_limit_per_ip burst=20 nodelay;
# 设置请求超限时返回的页面
error_page 503 /custom_503.html;
# 处理正常请求
root /usr/share/nginx/html;
index index.html;
}
}
}解释:
- limit_req_zone:定义一个名为
req_limit_per_ip的限流区域。$binary_remote_addr是客户端的 IP 地址,以二进制格式存储,可以减少内存消耗。rate=10r/s限制每秒最多 10 次请求。zone=req_limit_per_ip:10m表示存储在内存中,并且该区域的大小是 10MB,可以存储多个 IP 地址的限流信息。 - limit_req:在具体的
location配置中启用限流,使用定义好的req_limit_per_ip区域。burst=20允许一定的请求突发,即在瞬间请求量超过正常限速时,最多可以允许 20 个请求超出限速。nodelay表示一旦超出请求限制,就立即拒绝请求,而不是延迟处理。
limit_conn - 限制连接数
limit_conn 模块限制每个客户端(每个客户端都有 IP 地址)的并发连接数。这对于防止单个客户端占用过多服务器资源非常有效。
http {
# 定义每个客户端(IP 地址)的最大连接数为 1
limit_conn_zone$binary_remote_addr zone=conn_limit_per_ip:10m;
server {
listen80;
server_name example.com;
location / {
# 限制每个 IP 的最大连接数
limit_conn conn_limit_per_ip 1;
# 处理正常请求
root /usr/share/nginx/html;
index index.html;
}
}
}解释:
- limit_conn_zone:定义了一个名为
conn_limit_per_ip的区域,用于存储每个 IP 地址的连接信息,zone=conn_limit_per_ip:10m指定了 10MB 的存储空间。 - limit_conn:在
location配置中启用连接限制,限制每个 IP 地址只能有一个并发连接。
灰度发布
在软件部署高可用架构体系中,灰度发布是逐步将新版本的应用程序或功能推送到一部分用户,而不是一次性让所有用户都使用新的版本。Nginx 作为主流的高性能反向代理服务器,凭借其强大的流量控制和路由能力,成为灰度发布设计中不可或缺的核心组件。在 Nginx 中配置灰度发布,通常是通过基于 IP、请求头、cookie、URL 参数 等的负载均衡策略来实现的。这可以确保新的版本只对一部分用户可见,直到测试完成并验证没有问题后,才会将所有流量切换到新版本。本文将讲解如何基于 Nginx 实现的几个灰度发布方案。
假设我们有两个 Tomcat 节点,一个是生产环境,一个是部署了新代码但还不能公开的环境。可以通过 Nginx 配置负载均衡和访问控制来实现灰度发布。
灰度发布方案
方案 1:基于请求头进行灰度发布
可以使用自定义的请求头(例如 X-GrayRelease)来控制流量的分配。这个请求头可以在测试人员访问时加上(如通过浏览器插件或代码),来决定请求发送到哪个节点。
http {
upstream tomcat_prod {
server tomcat-prod1.example.com:8080;
}
upstream tomcat_canary {
server tomcat-canary1.example.com:8080;
}
server {
listen80;
server_name example.com;
location / {
# 检查是否存在 X-GrayRelease 请求头
if ($http_x_grayrelease = "true") {
# 如果请求头为 "true",则流量路由到测试环境
proxy_pass http://tomcat_canary;
}
# 否则,流量路由到生产环境
proxy_pass http://tomcat_prod;
}
}
}说明:
- 当请求中带有
X-GrayRelease: true请求头时,流量会被转发到tomcat_canary(修改后的版本)。 - 没有请求头或者请求头为其它值时,流量会默认转发到生产环境
tomcat_prod
方案 2:基于 Cookie 进行灰度发布
另一种常见的方式是通过 Cookie 来控制访问。测试人员访问时,Nginx 会检查用户的 Cookie 是否有特定值,从而决定流量的路由。
http {
upstream tomcat_prod {
server tomcat-prod1.example.com:8080;
server tomcat-prod2.example.com:8080;
}
upstream tomcat_canary {
server tomcat-canary1.example.com:8080;
server tomcat-canary2.example.com:8080;
}
server {
listen80;
server_name example.com;
location / {
# 检查请求中是否有灰度发布的 Cookie
if ($cookie_grayrelease = "true") {
# 如果 Cookie 为 "true",路由到测试环境
proxy_pass http://tomcat_canary;
}
# 默认路由到生产环境
proxy_pass http://tomcat_prod;
}
}
}说明:
- 如果请求中带有
grayrelease=true的 Cookie,流量将路由到tomcat_canary(灰度版本)。 - 没有该 Cookie 或 Cookie 值不为
true时,流量会默认路由到生产环境tomcat_prod。
方案 3:基于 IP 地址进行灰度发布
如果我们想为特定 IP 地址的用户提供灰度版本(例如,测试人员的 IP 地址,最好是固定IP,通过 VPN 技术实现),可以基于 IP 地址进行路由。
http {
upstream tomcat_prod {
server tomcat-prod1.example.com:8080;
}
upstream tomcat_canary {
server tomcat-canary1.example.com:8080;
}
server {
listen80;
server_name example.com;
location / {
# 基于 IP 地址路由
if ($remote_addr = "192.168.1.100") {
# 只有测试人员的 IP 地址才能访问测试环境
proxy_pass http://tomcat_canary;
}
# 默认路由到生产环境
proxy_pass http://tomcat_prod;
}
}
}说明:
- 如果请求来源于 IP 地址
192.168.1.100(测试人员的 IP),流量将被路由到tomcat_canary(灰度版本)。 - 其他所有用户的流量都将路由到生产环境
tomcat_prod。
部署与流程
在实际部署过程中,我们可以按照以下步骤进行灰度发布:
部署新版本到测试环境
首先,将修改后的代码部署到
tomcat-canary节点(灰度环境),确保其可以访问但不对所有用户开放。Nginx 配置路由策略
根据你的灰度发布策略(请求头、Cookie、IP 等),在 Nginx 中配置流量的分配。你可以选择逐步增加灰度发布的比例,例如先让 10% 的流量访问
tomcat-canary,然后逐步增加,直到 100% 流量都切换到新版本。测试和验证
测试人员或 QA 团队可以通过特定的请求头、Cookie 或 IP 地址访问灰度版本(
tomcat-canary),进行验证和测试。正式发布
一旦灰度版本通过测试,可以逐步将所有流量切换到新的版本。可以直接修改 Nginx 配置,将所有流量都路由到
tomcat-canary或tomcat-prod,并最终清除灰度发布的控制条件。
http {
upstream tomcat_prod {
server tomcat-prod1.example.com:8080 weight=90; # 生产环境,权重为 90
server tomcat-canary1.example.com:8080 weight=10; # 灰度版本,权重为 10
}
server {
listen80;
server_name example.com;
location / {
# 根据权重分配流量
proxy_pass http://tomcat_prod; # 默认路由到生产环境
}
}
}