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