Contact the author via WeChat: xiaoda0423
Repository address: https://webvueblog.github.io/JavaPlusDoc/
https://1024bat.cn/
๐ 1. Frontend and Backend Cache Strategy Coordination
๐ง 1. Frontend: Effectively Utilize Browser Cache
-
Strong Cache (from disk cache / memory cache)
- The browser hits the strong cache, does not send a request, and directly uses the local cache
- Suitable for static resources that do not change often: such as images, fonts, JS/CSS, etc.
-
Server response:
Cache-Control: public, max-age=86400 Expires: Wed, 16 Apr 2025 12:00:00 GMT
-
Frontend performance:
-
Negotiated Cache (304)
-
Server response:
Last-Modified: Wed, 10 Apr 2025 06:00:00 GMT ETag: "abc123xyz"
-
The client sends the next request with:
If-Modified-Since: ... If-None-Match: ...
-
If the resource has not changed, return 304 to save bandwidth; otherwise, return a new 200
-
Force Refresh (Ctrl+F5)
-
The browser automatically adds the request header:
Cache-Control: no-cache Pragma: no-cache
๐ง 2. Backend: Set Cache Response Headers Based on Resource Type
It is recommended to configure static resource strategies uniformly with Nginx, Spring Boot, or other backend frameworks.
โ Example Strategy (Nginx):
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";
}
โ Example Strategy (Spring Boot):
@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());
}
}
๐ฏ 2. Coordination Ideas
Resource Type | Recommended Cache Strategy | Reason/Explanation |
---|---|---|
JS/CSS | <span>Cache-Control: max-age=31536000, immutable</span> |
Rarely updated, version number renaming |
Images/Fonts | <span>Cache-Control: max-age=31536000, immutable</span> |
Cache as long as it does not change |
HTML | <span>Cache-Control: no-cache</span> |
Needs to check for updates every time |
API Requests | <span>Cache-Control: no-store</span> |
Avoid caching sensitive data, high real-time requirements |
JSON Configuration Files | Optional negotiated cache (ETag + Last-Modified) | Can negotiate cache if update frequency is low |
Uploaded Files | Usually not cached | Private/sensitive resources |
๐จ 3. Combine Build Tool Versioning Strategy (Frontend Focus)
๐ก Principle:
During each build, resource files automatically add a hash value (e.g., <span>app.7ad32f.js</span>
), strong cache time can be set long (e.g., one year),when resources are updated, the file name changes, and users naturally request the latest resources.
- Common methods for Webpack/Vite/Rollup:
output: {
filename: '[name].[contenthash].js'
}
- HTML references automatically update the reference path, such as:
<script src="/static/js/app.7ad32f.js"></script>
๐ 4. Points to Note
-
ETag is recommended to be turned off in cluster deployments
- The ETag generated by each node may be different, leading to cache misses โ
<span>nginx.conf</span>
:<span>etag off;</span>
Avoid disabling cache on the frontend (Disable Cache)
- Except for debugging and development, enabling it in production will greatly increase traffic
CDN distribution for image and font resources + permanent caching
-
Can even set:
Cache-Control: max-age=315360000, immutable
Be cautious with cache headers for dynamic data
- For example, user information, shopping cart, payment status, caching is not recommended
Reasonably configure build and version strategies on the frontend, and finely control cache response headers on the backend.
Level | Optimization Measures |
---|---|
Frontend | hash file names, immutable tags, avoid misuse of no-cache |
Backend | Extend cache for static resources, verify dynamic resources, turn off ETag (if necessary) |
Network | Enable CDN caching, compress Gzip/Brotli, reduce RTT |
Business | Aim for data decoupling (static vs dynamic), structural separation, atomic updates |
-
Prepare 3 Nginx instances: Simulate multi-layer proxy (Client โ Proxy1 โ Proxy2 โ Backend)
-
Configure test page:
- Backend Nginx returns
<span>$remote_addr</span><span>, </span><code><span>$http_x_forwarded_for</span><span>, </span><code><span>$http_x_real_ip</span><span> to verify IP forwarding.</span>
- Also returns
<span>$request_method</span><span>, </span><code><span>$request_uri</span><span> to verify </span><code><span>proxy_pass</span><span> and </span><code><span>rewrite</span><span> effects.</span>
- Add resources with
<span>ETag</span><span>, </span><code><span>Last-Modified</span><span>, </span><code><span>Cache-Control</span><span> headers to test caching strategies.</span>
Curl test command template:
curl -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
Key configuration test points:
<span>proxy_pass</span><span> + URI rule differences</span>
<span>rewrite + break</span><span> impact on </span><code><span>proxy_pass</span>
<span>proxy_set_header</span><span> header inheritance and overriding mechanism</span>
<span>underscores_in_headers</span><span> switch impact on header variable naming</span>
- Cache hits (304 vs 200 vs from disk cache)
โ 1. Blue-Green Deployment
๐ Core Idea:
Deploy two versions simultaneously:
<span>blue</span><span>: Current stable online version</span>
<span>green</span><span>: Upcoming new version</span>
Achieve rapid traffic switching through Nginx to avoid downtime.
๐ง Nginx Configuration Method (Blue-Green Environment Switching):
upstream app_backend {
server 10.0.0.1:8080; # blue
# server 10.0.0.2:8080; # green (uncomment this line to go live, comment the above)
}
server {
listen 80;
location / {
proxy_pass http://app_backend;
}
}
๐ When switching versions: Simply modify the target IP of
<span>upstream</span><span> and reload Nginx to complete seamless blue-green switching.</span>
โจ Practical Suggestions:
- Use Jenkins/scripts for one-click traffic switching
- Combine with health checks to avoid new version service unavailability
โ 2. Canary Release
๐ Core Idea:
Only allow a portion of users to use the new version, gradually releasing traffic based on rules (such as IP, cookie, header, ratio, etc.).
๐ฏ Scenario 1: IP-based Canary Release
map $remote_addr $gray_user {
default 0;
192.168.1.100 1; # Specify user IP for canary
}
upstream app_v1 {
server 10.0.0.1:8080; # Old version
}
upstream app_v2 {
server 10.0.0.2:8080; # New version
}
server {
listen 80;
location / {
if ($gray_user = 1) {
proxy_pass http://app_v2;
}
proxy_pass http://app_v1;
}
}
๐ฏ Scenario 2: Cookie-based Canary Release
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;
}
๐ฏ Scenario 3: Ratio-based Canary Release (Weighted Round Robin)
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;
}
}
โ ๏ธ Note: This method does not guarantee that “the same user will consistently hit the old or new version”.
๐ง Practical Tips for Nginx with Blue-Green/Canary Deployment:
Function Point | Technical Solution |
---|---|
Precise User Canary | <span>$remote_addr</span><span> / </span><code><span>$http_cookie</span><span> / </span><code><span>$http_user_agent</span> |
Dynamic Weight Traffic Switching | Use nginx + consul/etcd + lua/openresty |
Real-time Upstream Switching | Combine with <span>nginx reload</span><span> or </span><code><span>dynamic upstream</span> module |
Monitor Traffic Switching Effects | Combine with <span>access_log</span><span> + log_format for log analysis</span> |
Health Check | <span>proxy_next_upstream</span><span> + </span><code><span>max_fails</span><span> + </span><code><span>fail_timeout</span> |
โ Project Structure (Blue-Green Canary Nginx Example)
nginx-canary-demo/
โโโ docker-compose.yml
โโโ nginx/
โ โโโ nginx.conf
โ โโโ conf.d/
โ โโโ default.conf
โโโ app-v1/ # Simulated blue version
โ โโโ index.html
โโโ app-v2/ # Simulated green version
โ โโโ index.html
โโโ test/
โโโ curl_test.sh
๐ฆ docker-compose.yml
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
# Blue-Green Canary Configuration
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
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
<!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
<!DOCTYPE html>
<html>
<head><title>Green Version</title></head>
<body style="background-color:lightgreen;">
<h1>Green Version: v2 (Canary User Exclusive)</h1>
</body>
</html>
๐งช test/curl_test.sh
#!/bin/bash
echo "== Regular User Access =="
curl -s http://localhost:8080 | grep h1
echo "== Canary User Access =="
curl -s -H "Cookie: gray_user=true" http://localhost:8080 | grep h1
๐ Usage Instructions
- Start the project:
docker-compose up --build
-
Access test:
- Regular access: http://localhost:8080
- Canary access:
<span>curl -H "Cookie: gray_user=true" http://localhost:8080</span>
Run the test script:
chmod +x test/curl_test.sh
./test/curl_test.sh
๐งฉ Further Advanced Suggestions
Function | Method |
---|---|
Dynamic Traffic Ratio Adjustment | Nginx + Lua + Redis to control ratios |
Weighted Canary (10% to green) | <span>upstream weight</span> + sticky session |
Path/UA/Referer-based Canary | Use <span>$http_user_agent</span><span> or </span><code><span>$request_uri</span><span> to map</span> |
๐ Scenario Review: Blue-Green Environment + Canary Traffic Switching
- Blue (Current Stable)
- Green (New Version)
- Default traffic goes to Blue
- When Jenkins publishes, first check Green’s health, then switch traffic
- Traffic switching can be gradually adjusted or done in one click
๐ ๏ธ 1. Nginx Target Configuration (Dynamic Upstream Switching)
We achieve this through symbolic links + reload:
/etc/nginx/conf.d/default.conf -> points to: conf.d/blue.conf or conf.d/green.conf
For example:
<span>conf.d/upstream-blue.conf</span>
upstream backend {
server app-v1:80;
}
<span>conf.d/upstream-green.conf</span>
upstream backend {
server app-v2:80;
}
<span>conf.d/location.conf</span>
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
๐งช 2. Health Check Script (<span>health_check.sh</span>
)
#!/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. One-Click Traffic Switching Script (<span>switch_traffic.sh</span>
)
#!/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
# Health check
bash ./health_check.sh "http://127.0.0.1:808${TARGET/blue/1}${TARGET/green/2}" || exit 1
# Switch upstream
rm -f $LINK
ln -s $UPSTREAM$LINK
# Reload Nginx
nginx -s reload
echo"โ
Successfully switched to $TARGET"
๐งฑ 4. Jenkins Process (Freestyle Job / Pipeline)
Method 1:Freestyle Job + Parameters
- Add build parameters:
<span>TARGET_ENV</span><span> (value is </span><code><span>blue</span><span> or </span><code><span>green</span><span>)</span>
- Build steps:
cd /your/nginx-deploy-dir
git pull
chmod +x switch_traffic.sh
./switch_traffic.sh $TARGET_ENV
Method 2:Pipeline Example
pipeline {
agent any
parameters {
choice(name: 'TARGET', choices: ['blue', 'green'], description: 'Select the version to switch traffic to')
}
stages {
stage('Switch Traffic') {
steps {
sh '''
cd /your/nginx-deploy-dir
git pull
./switch_traffic.sh $TARGET
'''
}
}
}
}
๐ Stability Assurance (Recommended to Pair)
Function | Technical Points |
---|---|
Health Check | curl + retry |
Canary Switching (10%) | Nginx map + $request_id hash canary |
Rollback | Switch soft link back to blue |
Real-time Monitoring | Prometheus + Grafana |
Automatic Alarm for Exceptions | Jenkins combined with DingTalk/FeiShu |
The main configuration file for Nginx (nginx.conf)
๐ง <span>worker_processes 1;</span>
- Start 1 worker process (the core process handling requests)
- Usually set to
<span>auto</span><span> (automatically allocated based on CPU core count)</span>
โ๏ธ <span>events { worker_connections 1024; }</span>
This is the event module that controls the number of connections each worker can handle simultaneously:
<span>worker_connections 1024</span>
: A worker can handle a maximum of 1024 concurrent connections- Theoretical maximum concurrency:
<span>worker_processes ร worker_connections</span>
(but limited by system ulimit)
๐ <span>http { ... }</span>
The core configuration block for Nginx HTTP service, containing all web server configurations.
Explanation of each line:
๐ <span>include mime.types;</span>
- Import the
<span>mime.types</span><code><span> file, telling Nginx the corresponding </span><code><span>Content-Type</span><span> for various file extensions (e.g., </span><code><span>.html</span><span> is </span><code><span>text/html</span><span>))</span>
๐ <span>default_type text/html;</span>
- If no suitable mime type is found, default to
<span>text/html</span>
๐ <span>sendfile on;</span>
- Enable zero copy, optimizing file transfer efficiency
- Used for static resource scenarios (images, videos, compressed files, etc.)
๐ <span>keepalive_timeout 65;</span>
- TCP keep-alive time, in seconds
- If no request is made within 65 seconds, the connection is closed to save resources
- The default value is
<span>75</span>
, setting it to<span>65</span>
indicates an earlier release
๐ <span>include /etc/nginx/conf.d/*.conf;</span>
- Import all
<span>/etc/nginx/conf.d/</span><span> directory's </span><code><span>.conf</span><span> files</span>
- All
<span>server {}</span><span> or </span><code><span>location {}</span><span> blocks are usually written here</span>
Example:
/etc/nginx/
โโโ nginx.conf # Main configuration
โโโ conf.d/
โโโ app1.conf # Site 1
โโโ app2.conf # Site 2
๐ Suggested Project Structure
deploy/
โโโ nginx/
โ โโโ blue.conf # Blue environment configuration
โ โโโ green.conf # Green environment configuration
โ โโโ main.conf # Entry nginx configuration (references upstream)
โโโ scripts/
โ โโโ switch_env.sh # Traffic switching script (blue -> green / green -> blue)
๐งฉ <span>main.conf</span>
(Nginx main configuration referencing upstream)
# main.conf (loaded into nginx.conf or 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';
}
}
๐ฆ <span>blue.conf</span>
# blue.conf
server 10.0.0.11:8080 max_fails=3 fail_timeout=30s;
๐ฉ <span>green.conf</span>
# green.conf
server 10.0.0.12:8080 max_fails=3 fail_timeout=30s;
๐ <span>active.conf</span>
(symbolic link)
# Initial environment is blue
ln -s /etc/nginx/upstream/blue.conf /etc/nginx/upstream/active.conf
๐ ๏ธ <span>switch_env.sh</span>
(script for one-click traffic switching)
#!/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] Switching to environment: $NEW_TARGET"
# Update symbolic link
ln -sf "$UPSTREAM_DIR/$NEW_TARGET""$UPSTREAM_DIR/active.conf"
# Health check
echo"[INFO] Performing health check..."
CHECK_URL="http://127.0.0.1/healthz"
sleep 1
HEALTH=$(curl -s --max-time 3 "$CHECK_URL")
if [[ "$HEALTH" == "ok" ]]; then
echo"[INFO] Health check passed, reloading Nginx..."
nginx -s reload
echo"[OK] Traffic switch successful! Current environment: $NEW_TARGET"
else
echo"[ERROR] Health check failed, rolling back..."
# Rollback
ln -sf "$CURRENT""$UPSTREAM_DIR/active.conf"
nginx -s reload
echo"[ROLLBACK] Rolled back to $CURRENT"
exit 1
fi
โ Usage Instructions
# Execute in Jenkins
bash /path/to/scripts/switch_env.sh
๐ก Optional Enhancements
Function | Recommended Method |
---|---|
Automatic Canary Ratio Switching | Nginx <span>weight</span> parameter + hash |
Multi-Version Health Checks | <span>/healthz</span> with version parameters |
Load Testing | <span>wrk</span> / <span>ab</span> / <span>hey</span> tools |
Visual State Switching | Combine with <span>Nginx status + Lua</span> |