阶段2(下):运维专题 Docker/Nginx/Linux/CI-CD/Git 的课程、企业场景、面试题和可运行示例
This commit is contained in:
1 parent
5eb67c5d08
commit
b8010a74f3
42 files changed
+3533
-55
No files matched your search
@@ -0,0 +1,113 @@
|
||||
---
|
||||
id: devops.nginx.https-stream-limit
|
||||
title: HTTPS、SSE / WebSocket、限流和灰度
|
||||
type: lesson
|
||||
domain: devops
|
||||
stack: [nginx]
|
||||
tags: [HTTPS, TLS, SSE, WebSocket, limit_req, 灰度发布]
|
||||
level: intermediate
|
||||
prerequisites: [devops.nginx.proxy-static]
|
||||
est_hours: 3
|
||||
related: [devops.nginx.scenario.ai-gateway-sse-canary, devops.nginx.interview]
|
||||
week: [7, 14]
|
||||
order: 2
|
||||
---
|
||||
|
||||
# HTTPS、SSE / WebSocket、限流和灰度
|
||||
|
||||
## 解释说明
|
||||
|
||||
**HTTPS**
|
||||
|
||||
- 证书可以用 Let's Encrypt(免费,certbot 或 acme.sh 自动续期)或云厂商证书。
|
||||
- 配置 `ssl_certificate`、`ssl_certificate_key`,只开启 TLS 1.2 / 1.3;80 端口 301 跳转到 443。
|
||||
- TLS 在 Nginx 终止,Nginx 到内网后端用 HTTP(`X-Forwarded-Proto: https` 告诉后端原始协议)。
|
||||
|
||||
**SSE(大模型流式输出)**
|
||||
|
||||
- SSE 是普通 HTTP 响应(`Content-Type: text/event-stream`),服务端不断写入 `data: ...\n\n`。
|
||||
- Nginx 默认开启 `proxy_buffering`,会把后端响应先攒进缓冲区,导致用户看到的“打字机效果”变成一大段一起出现。**关闭缓冲**:`proxy_buffering off;`,或者后端返回响应头 `X-Accel-Buffering: no`。
|
||||
- 生成时间长,`proxy_read_timeout` 要调大(它是两次读之间的间隔,不是总时长);也可以让后端定期发心跳注释 `: ping`。
|
||||
- 如果开启了 gzip,确认流式响应不被压缩缓冲(`text/event-stream` 不在 `gzip_types` 中即可)。
|
||||
|
||||
**WebSocket**:需要协议升级头:
|
||||
|
||||
```nginx
|
||||
map $http_upgrade $connection_upgrade { default upgrade; "" close; }
|
||||
location /ws/ {
|
||||
proxy_pass http://ws_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_read_timeout 3600s;
|
||||
}
|
||||
```
|
||||
|
||||
**限流**:`limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;` 定义按 IP 的漏桶;`limit_req zone=api burst=20 nodelay;` 允许突发 20 个且不排队延迟;超出返回 `limit_req_status`(默认 503,建议改成 429)。`limit_conn` 限制并发连接数。
|
||||
|
||||
**灰度发布**:
|
||||
|
||||
- 按比例:`split_clients "${remote_addr}" $variant { 10% canary; * stable; }`;
|
||||
- 按用户:`map $cookie_canary $backend { default stable; "1" canary; }`,内部员工或白名单用户先体验;
|
||||
- 按权重:`upstream` 里新旧实例设置不同 `weight`。
|
||||
|
||||
## 案例
|
||||
|
||||
AI 问答页面上线后用户反馈“回答要等很久才一下子全部出来”:浏览器直连后端是逐字输出,经过 Nginx 就变成整段。原因是 `proxy_buffering` 默认开启。关闭后恢复逐字输出;同时把 `proxy_read_timeout` 从 60 秒调到 300 秒,避免长回答被中途断开(504)。
|
||||
|
||||
## 代码示例
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;
|
||||
|
||||
map $cookie_canary $api_backend {
|
||||
default api_stable;
|
||||
"1" api_canary;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on; # nginx 1.25.1+ 的写法;旧版本写在 listen 后面
|
||||
server_name example.com;
|
||||
ssl_certificate /etc/nginx/certs/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
|
||||
location /api/ {
|
||||
limit_req zone=api_limit burst=5 nodelay;
|
||||
limit_req_status 429;
|
||||
proxy_pass http://$api_backend;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /ai/stream {
|
||||
proxy_pass http://api_stable;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_buffering off; # 流式输出必须关闭缓冲
|
||||
proxy_cache off;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[examples/gateway](examples/gateway/) 的测试里验证了:关闭缓冲时第一条 SSE 事件在约 0.3 秒内到达,而整个响应约 0.9 秒结束;打开缓冲时第一条事件要等整个响应结束才到达。
|
||||
|
||||
## 易错点
|
||||
|
||||
- **SSE 没关缓冲**:流式变整段。
|
||||
- **`proxy_read_timeout` 太短**:长回答被 504 中断。
|
||||
- **WebSocket 没加 Upgrade / Connection 头**:握手失败,前端报 400 或连接立即关闭。
|
||||
- **限流按 `$remote_addr` 但前面还有一层负载均衡**:所有请求的地址都是负载均衡器,一起被限流。要用 `real_ip` 模块从可信代理的头里取真实 IP。
|
||||
- **证书过期**:自动续期任务失败没人发现。加监控告警。
|
||||
- **灰度只切了后端没切前端资源**(或反过来):前后端版本不匹配。灰度规则要一致,接口要向后兼容。
|
||||
|
||||
## 面试常问
|
||||
|
||||
见 [Nginx 面试题](interview.md):SSE 代理要注意什么、WebSocket 代理配置、限流原理、灰度发布怎么做、502 和 504 的区别。
|
||||
Reference in new issue
Block a user