加群联系作者vx:xiaoda0423
仓库地址:webvueblog.github.io/JavaPlusDoc...
🚀 一、前后端缓存策略协同
🔧 1. 前端:合理利用浏览器缓存
-
强缓存(from disk cache / memory cache)
-
服务端响应:
yamlCache-Control: public, max-age=86400 Expires: Wed, 16 Apr 2025 12:00:00 GMT
-
前端表现:
- 浏览器命中强缓存,不发请求,直接用本地缓存
- 适合不常改动的静态资源:如图片、字体、JS/CSS 等
-
-
协商缓存(304)
-
服务端响应:
yamlLast-Modified: Wed, 10 Apr 2025 06:00:00 GMT ETag: "abc123xyz"
-
客户端下一次发起请求带上:
makefileIf-Modified-Since: ... If-None-Match: ...
-
如果资源没变,返回 304,节省带宽;否则返回新的 200
-
-
强制刷新(Ctrl+F5)
-
浏览器自动加上请求头:
yamlCache-Control: no-cache Pragma: no-cache
-
🧠 2. 后端:根据资源类型设置缓存响应头
建议结合 Nginx、Spring Boot 或其他后端框架统一配置静态资源策略。
✅ 示例策略(Nginx):
ini
location ~* .(js|css|png|jpg|jpeg|gif|woff|woff2|svg|ico)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000, immutable";
}
location /api/ {
expires off;
add_header Cache-Control "no-store";
}
✅ 示例策略(Spring Boot):
typescript
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/")
.setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS).cachePublic());
}
}
🎯 二、配合思路
资源类型 | 建议缓存策略 | 原因/说明 |
---|---|---|
JS/CSS | Cache-Control: max-age=31536000, immutable |
不常更新、版本号改名 |
图片/字体 | Cache-Control: max-age=31536000, immutable |
不变就一直缓存 |
HTML | Cache-Control: no-cache |
每次都需要检查是否有更新 |
API 请求 | Cache-Control: no-store |
避免缓存敏感数据,实时性强 |
JSON 配置文件 | 可选协商缓存 (ETag + Last-Modified) | 若更新频率低可协商缓存 |
上传文件 | 通常不缓存 | 私密/敏感性资源 |
🎨 三、结合构建工具版本号策略(前端重点)
💡 原理:
每次构建时,资源文件自动添加 hash 值(如 app.7ad32f.js
),强缓存时间可以设置很长(如一年),资源更新后文件名变了,用户自然请求最新资源。
- Webpack/Vite/Rollup 常用方式:
css
output: {
filename: '[name].[contenthash].js'
}
- HTML 引用时自动更新引用路径,如:
xml
<script src="/static/js/app.7ad32f.js"></script>
🛠 四、注意点
-
ETag 在集群部署时建议关闭
- 每个节点生成的 ETag 可能不同,导致命中失败 →
nginx.conf
:etag off;
- 每个节点生成的 ETag 可能不同,导致命中失败 →
-
尽量不要前端禁用缓存(Disable Cache)
- 除了调试开发,正式环境打开会极大增加流量
-
图片字体类资源 CDN 分发 + 永久缓存
-
甚至可以设置:
iniCache-Control: max-age=315360000, immutable
-
-
动态数据慎用缓存头
- 比如用户信息、购物车、支付状态,不建议缓存
前端合理配置构建和版本策略,后端精细控制缓存响应头。
层级 | 优化手段 |
---|---|
前端 | hash 文件名、immutable 标记、避免 no-cache 滥用 |
后端 | 静态资源加长缓存、动态资源配合校验、关闭 ETag(如必要) |
网络 | 启用 CDN 缓存、压缩 Gzip/Brotli、减少 RTT |
业务 | 尽量数据解耦(静态 vs 动态),结构分离、更新原子性 |
-
准备 3 个 Nginx 实例:模拟多层代理(Client → Proxy1 → Proxy2 → Backend)
-
配置测试页面:
- 后端 Nginx 返回
$remote_addr
,$http_x_forwarded_for
,$http_x_real_ip
来验证 IP 透传。 - 同时返回
$request_method
,$request_uri
来验证proxy_pass
和rewrite
效果。 - 添加资源带上
ETag
,Last-Modified
,Cache-Control
头部测试缓存策略。
- 后端 Nginx 返回
-
Curl 测试命令模板:
arduinocurl -I -H "Cache-Control: no-cache" http://localhost/static.js curl -I -H "If-None-Match: "etag123"" http://localhost/static.js curl -I -H "a_b: 123" http://localhost:81
-
关键配置测试点:
proxy_pass
+ URI 规则的差异行为rewrite + break
对proxy_pass
行为影响proxy_set_header
的 header 继承与覆盖机制underscores_in_headers
开关对 header 变量命名的影响- 缓存命中(304 vs 200 vs from disk cache)
✅ 一、蓝绿部署(Blue-Green Deployment)
🔍 核心思路:
同时部署两个版本:
blue
:当前稳定线上版本green
:即将上线的新版本
通过 Nginx 实现快速流量切换,避免停机。
🔧 Nginx 配置方法(蓝绿环境切换):
arduino
upstream app_backend {
server 10.0.0.1:8080; # blue
# server 10.0.0.2:8080; # green(上线时把这行打开,把上面注释掉)
}
server {
listen 80;
location / {
proxy_pass http://app_backend;
}
}
🔁 切换版本时 :只需修改
upstream
的目标 IP 并 reload Nginx,即可完成无缝蓝绿切换。
✨ 实操建议:
- 配合 Jenkins/脚本做一键切流
- 结合 health check,避免新版本服务不可用
✅ 二、灰度发布(Canary Release)
🔍 核心思路:
只让部分用户使用新版本,根据规则(如 IP、cookie、header、比例等)灰度流量。
🎯 场景一:按 IP 灰度发布
perl
map $remote_addr $gray_user {
default 0;
192.168.1.100 1; # 指定用户 IP 灰度
}
upstream app_v1 {
server 10.0.0.1:8080; # 旧版本
}
upstream app_v2 {
server 10.0.0.2:8080; # 新版本
}
server {
listen 80;
location / {
if ($gray_user = 1) {
proxy_pass http://app_v2;
}
proxy_pass http://app_v1;
}
}
🎯 场景二:按 Cookie 灰度发布
perl
map $http_cookie $gray_cookie {
default 0;
"~*gray_user=true" 1;
}
location / {
if ($gray_cookie = 1) {
proxy_pass http://app_v2;
}
proxy_pass http://app_v1;
}
🎯 场景三:按比例灰度发布(权重轮询)
ini
upstream canary {
server 10.0.0.1:8080 weight=9; # v1 - 90%
server 10.0.0.2:8080 weight=1; # v2 - 10%
}
server {
listen 80;
location / {
proxy_pass http://canary;
}
}
⚠️ 注意:这种方式对"同一个用户固定命中新旧版本"没有保证。
🔧 Nginx 配合蓝绿/灰度部署的实操小技巧:
功能点 | 技术方案 |
---|---|
精准用户灰度 | $remote_addr / $http_cookie / $http_user_agent |
动态权重切流 | 使用 nginx + consul/etcd + lua/openresty |
实时切换 upstream | 配合 nginx reload or dynamic upstream 模块 |
监控切流效果 | 配合 access_log + log_format 打日志分析 |
健康检查 | proxy_next_upstream + max_fails + fail_timeout |
✅ 项目结构(蓝绿灰度 Nginx 示例)
bash
nginx-canary-demo/
├── docker-compose.yml
├── nginx/
│ ├── nginx.conf
│ └── conf.d/
│ └── default.conf
├── app-v1/ # 模拟蓝色版本
│ └── index.html
├── app-v2/ # 模拟绿色版本
│ └── index.html
└── test/
└── curl_test.sh
📦 docker-compose.yml
bash
version: '3.8'
services:
nginx:
image: nginx:latest
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/conf.d:/etc/nginx/conf.d
- ./app-v1:/usr/share/nginx/html/v1
- ./app-v2:/usr/share/nginx/html/v2
ports:
- "8080:80"
app-v1:
image: httpd:alpine
volumes:
- ./app-v1:/usr/local/apache2/htdocs/
ports:
- "8081:80"
app-v2:
image: httpd:alpine
volumes:
- ./app-v2:/usr/local/apache2/htdocs/
ports:
- "8082:80"
🧠 nginx/conf.d/default.conf
perl
# 蓝绿灰度配置
map $http_cookie $is_gray_user {
default 0;
"~*gray_user=true" 1;
}
upstream blue {
server app-v1:80;
}
upstream green {
server app-v2:80;
}
server {
listen 80;
server_name localhost;
location / {
if ($is_gray_user = 1) {
proxy_pass http://green;
}
proxy_pass http://blue;
}
}
🔧 nginx/nginx.conf
ini
worker_processes 1;
events { worker_connections 1024; }
http {
include mime.types;
default_type text/html;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}
📄 app-v1/index.html
xml
<!DOCTYPE html>
<html>
<head><title>Blue Version</title></head>
<body style="background-color:lightblue;">
<h1>Blue Version: v1</h1>
</body>
</html>
📄 app-v2/index.html
xml
<!DOCTYPE html>
<html>
<head><title>Green Version</title></head>
<body style="background-color:lightgreen;">
<h1>Green Version: v2 (灰度用户专属)</h1>
</body>
</html>
🧪 test/curl_test.sh
bash
#!/bin/bash
echo "== 普通用户访问 =="
curl -s http://localhost:8080 | grep h1
echo "== 灰度用户访问 =="
curl -s -H "Cookie: gray_user=true" http://localhost:8080 | grep h1
🚀 使用方法
- 启动项目:
css
docker-compose up --build
-
访问测试:
- 普通访问: http://localhost:8080
- 灰度访问:
curl -H "Cookie: gray_user=true" http://localhost:8080
-
运行测试脚本:
bash
chmod +x test/curl_test.sh
./test/curl_test.sh
🧩 后续进阶建议
功能 | 方法 |
---|---|
动态流量比例调整 | Nginx + Lua + Redis 控制比例 |
权重灰度(10% 进入 green) | upstream weight + sticky session |
请求路径/UA/Referer 灰度 | 用 $http_user_agent 或 $request_uri 做 map |
🌈 场景回顾:蓝绿环境 + 灰度切流
- Blue(当前稳定)
- Green(新版本)
- 默认流量都走 Blue
- Jenkins 按钮发布时,先检测 Green 健康,再流量切换
- 切流可灰度逐步调整、也可一键全量
🛠️ 1. Nginx 目标配置(动态切换 upstream)
我们通过软链接 + reload 实现:
bash
bash
复制编辑
/etc/nginx/conf.d/default.conf -> points to: conf.d/blue.conf or conf.d/green.conf
例如:
conf.d/upstream-blue.conf
css
upstream backend {
server app-v1:80;
}
conf.d/upstream-green.conf
css
upstream backend {
server app-v2:80;
}
conf.d/location.conf
arduino
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
🧪 2. 健康检查脚本(health_check.sh
)
bash
#!/bin/bash
TARGET_URL=$1
RETRY=5
for i in $(seq 1 $RETRY); do
echo "Health check [$i/$RETRY]: $TARGET_URL"
code=$(curl -s -o /dev/null -w "%{http_code}" "$TARGET_URL")
if [ "$code" == "200" ]; then
echo "✅ Health check success."
exit 0
fi
sleep 2
done
echo "❌ Health check failed."
exit 1
🚀 3. 一键切流脚本(switch_traffic.sh
)
bash
#!/bin/bash
TARGET=$1 # blue or green
NGINX_DIR="/etc/nginx/conf.d"
LINK="$NGINX_DIR/default.conf"
UPSTREAM="$NGINX_DIR/upstream-${TARGET}.conf"
if [ "$TARGET" != "blue" ] && [ "$TARGET" != "green" ]; then
echo "Usage: $0 [blue|green]"
exit 1
fi
# 健康检查
bash ./health_check.sh "http://127.0.0.1:808${TARGET/blue/1}${TARGET/green/2}" || exit 1
# 切换 upstream
rm -f $LINK
ln -s $UPSTREAM $LINK
# Reload Nginx
nginx -s reload
echo "✅ 切流到 $TARGET 成功"
🧱 4. Jenkins 流程(自由风格任务 / Pipeline)
方式一:自由风格任务 + 参数
- 添加构建参数:
TARGET_ENV
(值为blue
或green
) - 构建步骤:
bash
cd /your/nginx-deploy-dir
git pull
chmod +x switch_traffic.sh
./switch_traffic.sh $TARGET_ENV
方式二:Pipeline 示例
python
pipeline {
agent any
parameters {
choice(name: 'TARGET', choices: ['blue', 'green'], description: '选择要切流的版本')
}
stages {
stage('切流') {
steps {
sh '''
cd /your/nginx-deploy-dir
git pull
./switch_traffic.sh $TARGET
'''
}
}
}
}
🔒 稳定性保证(建议搭配)
功能 | 技术点 |
---|---|
健康检查 | curl + retry |
灰度切换(10%) | Nginx map + $request_id hash 灰度 |
回滚 | 切换软链接回 blue 即可 |
实时监控 | Prometheus + Grafana |
异常自动报警 | Jenkins 配合 DingTalk/飞书 |
Nginx 的主配置文件(nginx.conf)
🔧 worker_processes 1;
- 启动 1 个 worker 进程(处理请求的核心进程)
- 通常设为
auto
(自动根据 CPU 核心数来分配)
⚙️ events { worker_connections 1024; }
这是 事件模块,控制每个 worker 能同时处理的连接数:
worker_connections 1024
:一个 worker 最多能处理 1024 个并发连接- 理论最大并发:
worker_processes × worker_connections
(但受限于系统 ulimit)
🌐 http { ... }
Nginx 的 HTTP 服务核心配置块,包含所有 web server 配置。
逐条解释:
📎 include mime.types;
- 引入
mime.types
文件,告诉 Nginx 各种文件扩展名对应的Content-Type
(如.html
是text/html
)
📎 default_type text/html;
- 如果找不到合适的 mime type,就默认使用
text/html
🚀 sendfile on;
- 开启零拷贝(zero copy),优化文件传输效率
- 用于静态资源场景(图片、视频、压缩包等)
🔁 keepalive_timeout 65;
- TCP keep-alive 时间,单位:秒
- 如果 65 秒内没有请求,则断开连接,节省资源
- 默认值是
75
,这里调成65
说明略早释放
📁 include /etc/nginx/conf.d/*.conf;
- 引入所有
/etc/nginx/conf.d/
目录下的.conf
文件 - 所有的
server {}
或location {}
块通常写在这里
例子:
bash
/etc/nginx/
├── nginx.conf # 主配置
└── conf.d/
├── app1.conf # 站点1
├── app2.conf # 站点2
📁 项目结构建议
bash
deploy/
├── nginx/
│ ├── blue.conf # 蓝环境配置
│ ├── green.conf # 绿环境配置
│ └── main.conf # 入口 nginx 配置 (引用 upstream)
├── scripts/
│ └── switch_env.sh # 切流脚本(蓝 -> 绿 / 绿 -> 蓝)
🧩 main.conf
(Nginx 主配置引用 upstream)
ini
# main.conf (加载到 nginx.conf 或 conf.d/default.conf)
upstream backend {
include /etc/nginx/upstream/active.conf;
}
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location = /healthz {
return 200 'ok';
}
}
🟦 blue.conf
ini
# blue.conf
server 10.0.0.11:8080 max_fails=3 fail_timeout=30s;
🟩 green.conf
ini
# green.conf
server 10.0.0.12:8080 max_fails=3 fail_timeout=30s;
🔗 active.conf
(软链接)
bash
# 初始环境为 blue
ln -s /etc/nginx/upstream/blue.conf /etc/nginx/upstream/active.conf
🛠️ switch_env.sh
(脚本实现一键切流)
bash
#!/bin/bash
UPSTREAM_DIR="/etc/nginx/upstream"
CURRENT=$(readlink "$UPSTREAM_DIR/active.conf")
if [[ $CURRENT == *"blue.conf" ]]; then
NEW_TARGET="green.conf"
else
NEW_TARGET="blue.conf"
fi
echo "[INFO] 切换到环境: $NEW_TARGET"
# 更新软链接
ln -sf "$UPSTREAM_DIR/$NEW_TARGET" "$UPSTREAM_DIR/active.conf"
# 检查健康
echo "[INFO] 进行健康检查..."
CHECK_URL="http://127.0.0.1/healthz"
sleep 1
HEALTH=$(curl -s --max-time 3 "$CHECK_URL")
if [[ "$HEALTH" == "ok" ]]; then
echo "[INFO] 健康检查通过,重载 Nginx..."
nginx -s reload
echo "[OK] 切流成功!当前环境:$NEW_TARGET"
else
echo "[ERROR] 健康检查失败,回滚..."
# 回滚
ln -sf "$CURRENT" "$UPSTREAM_DIR/active.conf"
nginx -s reload
echo "[ROLLBACK] 已回滚至 $CURRENT"
exit 1
fi
✅ 使用方式
bash
# Jenkins中执行
bash /path/to/scripts/switch_env.sh
💡 可选增强点
功能 | 建议方式 |
---|---|
自动灰度比例切换 | Nginx weight 参数 + hash |
多版本健康检查 | /healthz 带版本参数 |
压力测试 | wrk / ab / hey 工具 |
可视化状态切换 | 搭配 Nginx status + Lua |