本节目录
gRPC
grpc 是由 Google 开发的一种高性能、开源的远程过程调用(rpc)框架,它定义了一套 rpc 语义与编码规范,并使用 HTTP/2 作为传输协议,其基于 HTTP/2 作为传输层协议,支持多路复用、头部压缩、双向流等特性。所以严格来说,grpc 并不是一个底层网络协议,而是一个构建在 HTTP/2 之上的应用层 rpc 协议。
grpc 协议的用途现今十分广泛,微服务、移动端 app、IoT设备、多编程语言集成项目等,其中都有 gpc 的影子。
nginx 从 nginx-1.13.10 版本起,正式官方支持 grpc 反向代理:
由于 grpc 基于 HTTP/2 的,所以需要在编译时安装
--with-http_ssl_module和--with-http_v2_module模块。(基于 HTTP/3(quic)在 grpc 生态中还处于实验或非主流阶段)
nginx
location /service {
grpc_pass grpc://127.0.0.1:50051; # 指定 grpc 后端地址,可以是 ip、域名、套接字、负载均衡组
# grpc_pass grpcs://127.0.0.1:50051; # 如果后端是 grpc 加密的,使用此项(location 中 grpc_pass 只能存在一个)
grpc_bind 192.168.1.100; # 设置连接后端时使用的本地 ip 地址(多网卡场景)
grpc_connect_timeout 5s; # 与后端建立连接的超时时间(默认 60s)
grpc_send_timeout 10s; # 向后端发送请求的超时(默认 60s)
grpc_read_timeout 1h; # 从后端读取响应的超时(默认 60s)
grpc_next_upstream error timeout http_500; # 定义在错误、超时、状态码 500 的情况下将请求重发给下一个后端
grpc_next_upstream_tries 3; # 最多尝试三次
grpc_next_upstream_timeout 15s; # 三次尝试总时间不超过 15s
grpc_set_header Authorization "Bearer $grpc_auth_token"; # 传输自定义 header,可用于传输 grpc 元数据
grpc_set_header X-Request-ID $request_id;
grpc_hide_header Server; # 拒绝某些后端响应的 herder,提升安全
grpc_hide_header X-Powered-By;
grpc_pass_header X-Custom-Backend-Status; # 允许 nginx 传递部分非标准 header 到后端
grpc_ignore_headers X-Accel-Redirect # 忽略后端返回的某些 herder
grpc_ssl_certificate /etc/nginx/client.pem; # nginx 作为 grpc 客户端去连接后端,需进行 mtls 认证
grpc_ssl_certificate_key /etc/nginx/client.key;
grpc_ssl_verify on; # on 需要验证后端服务器证书(默认 off)
grpc_ssl_name grpc.ex.com; # 验证后端服务器证书的主机名,后端存在多域多证书时必须写上
grpc_ssl_trusted_certificate /etc/nginx/ca.pem;
grpc_ssl_protocols TLSv1.2 TLSv1.3; # 指定 tls 版本
grpc_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256; # 指定加密算法
grpc_ssl_session_reuse on; # 开启 ssl 会话重用,可显著降低多次 tcp 握手的开销
grpc_buffering on; # 启用响应缓冲
grpc_buffer_size 4k; # 读取后端响应第一部分的缓冲区大小
grpc_socket_keepalive on; # 向后端 grpc 开启长连接,防止没有数据传输导致 tcp 被中断
grpc_intercept_errors on; # 拦截后端返回的错误码,交由 nginx 处理
error_page 502 /grpc_error.html;
}
注意:
- grpc 基于 HTTP/2 工作,请务必确保此 server 的
listen 443 http2中包含 http2 字样;- 路径必须与
.proto中定义的 service 和 method 完全匹配,否则将返回 404 或 UNIMPLEMENTED;- 对于流式应用,
grpc_buffering必须设置为off,否则用户端会存在明显的卡顿感;- 如果同时配置了
grpc_read_timeout和grpc_socket_keepalive on,请确保grpc_read_timeout的时间大于 grpc 自身的 keepalive 时间,否则 nginx 会切断看似闲置的长连接;- 若 grpc 元数据很大(如包含了很大的 token),则需要调整 http 级别的
large_client_header_buffers;- 如果后端 grpc 使用了 SNI(多域名托管在同一 ip),那么
grpc_ssl_name必须强制配置,如果后端的 SNI 和配置的域名不同,则 nginx 会拒绝;- 若开启了
grpc_intercept_errors on,那请确保你的 error_page 返回的也是符合 grpc 规范的响应,一般对于业务逻辑错误的,都建议关闭此项,让后端 grpc 的直接将错误透传给客户端,由客户端自行处理。
FastCGI
fastcgi 是一种用于 web 服务器与外部程序(如 php、python、go 等)通信的二进制协议。它的出现是为了解决传统 cgi 性能低下的问题(传统 cgi 会频繁的创建和销毁进程,进而消耗了巨大的 CPU 和内存资源)。
针对上述问题,fastcgi 引入了常驻进程的概念,当 web 服务启动时,fastcgi 进程管理器(如 php-fpm)就会预先启动一批进程,等待请求到来时,通过 socket 将数据传给已有的进程,但在处理完后进程并不退出,而是继续等待下一个请求。
fastcgi 现在几乎是 php 的专属产品了,另外 perl、超老旧的 python 等产品可能还在用(忽略不记),其他语言(如 java、go、c# 等)都自带高性能 web 服务器的,完全不需要中间再夹一个 fastcgi,所以其应用场景现在很窄了。[ 如果不是 php 还需要它,fastcgi 也早就入土了,和下面的 scgi 一样 ]
nginx 对 fastcgi 的支持几乎是与生俱来的;
nginx
http {
...
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=phpCache:100m inactive=60m; # 设置 fastcgi 缓存
...
}
location ~ \.php$ {
root /var/www/html;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_index index.php; # 当 uri 以 / 结尾时,等于是访问首页
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # 向fastcgi 进程传递变量
fastcgi_connect_timeout 10s; # 连接 fastcgi 服务器超过 10s ,则超时(默认 60s)
fastcgi_send_timeout 30s; # 向 fastcgi 发送请求超过 30s,则超时(默认 60s)
fastcgi_read_timeout 1m; # fastcgi 响应间隔超过 1 分钟则超时(默认 60s)
fastcgi_buffering on; # 开启响应式缓冲,流式输出适合 off
fastcgi_buffer_size 16k; # 设置用于读取 herder 的缓冲区大小
fastcgi_buffers 4 16k; # 为每个连接分配缓冲区和大小
fastcgi_request_buffering off; # 允许大文件可以边上传边处理
fastcgi_next_upstream error timeout http_500; # 功能和上面的 grpc 的此配置项功能一样
fastcgi_next_upstream_tries 3;
fastcgi_hide_header X-Powered-By; # 隐藏后端返回的敏感信息头
fastcgi_hide_header Server;
fastcgi_ignore_client_abort on; # 客户端断开连接后,继续处理异步任务(默认 off)
fastcgi_cache_key "$scheme$request_method$host$request_uri"; # 设置每条缓存存储的唯一标识
fastcgi_cache phpCache; # 启用缓存
fastcgi_cache_valid 200 302 10m; # 指定不同状态码的缓存时间
fastcgi_cache_valid 404 1m;
map $request_method $skip_cache {
default 0;
POST 1;
}
fastcgi_cache_bypass $skip_cache; # 对于某些请求需要跳过缓存
fastcgi_intercept_errors on; # 将 后端返回的 404 错误交给 nginx 来处理
fastcgi_keep_conn on; # 开启长连接减少握手
}
注意事项:(针对 php-fpm 的)
fastcgi_read_timeout不要设置太长,除非你的后端是处理超大任务,最后确保 read_timeout 应该略大于 php-fpm 中max_execution_time的值;fastcgi_keep_conn如果开启,需要注意 fastcgi 后端可能需要没有任何限制短连接的配置,配合负载均衡模块中的keepalive指令效果会更好,而且需要确保 php-fpm 的配置文件(www.conf)中也支持长连接,否则此项无效;fastcgi_request_buffering如果不是处理超大文件或实现上传进度条之类的,请保持 on;- 如果请求 herder 很大(如超大 cookie),
fastcgi_buffer_size与fastcgi_buffers需要响应调大,而且要确保php-fpm 配置文件中的max_input_time和post_max_size与之相匹配;fastcgi_ignore_client_abort请谨慎开启,若无脑开启,当发生恶意攻击(大量请求并立即断开)时,后端进程可能会被占满且不会因为客户端断开而释放,导致服务器宕机。如果需要,必须配合限流(limit_req / limit_conn)使用。
uWSGI
在 2010--2020 年间,uwsgi 是 python web 部署的黄金标准,但截至目前,uwsgi 的使用量正在明显减少,尤其在新项目中已不再是主流选择,但它仍在大量遗留系统、传统企业应用和部分 django 项目中稳定运行(新项目中已逐渐被 gunicorn + uvicorn 取代)。现在的 uwsgi 已进入了维护模式了,它完成了自己的历史使命,不再是未来推荐的 sgi 标准了。
uwsgi 既是一个服务器,又定义了 uwsgi 协议,其运行速度还可以,但是配置起来很容易出错,文档也很杂乱;
nginx
location / {
uwsgi_pass unix:/tmp/uwsgi.sock;
include uwsgi_params; # 包含标准 uWSGI 参数映射文件(由 nginx 提供,写上就行)
uwsgi_param UWSGI_CHDIR /var/www/myapp; # 设置工作目录(uwsgi_param 可以自定义参数)
uwsgi_param UWSGI_SCRIPT app:application; # 指定入口(旧式)
uwsgi_param DJANGO_SETTINGS_MODULE myapp.settings;
uwsgi_param Host $host;
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $scheme;
uwsgi_connect_timeout 10s;
uwsgi_send_timeout 60s;
uwsgi_read_timeout 300s;
...
}
uwsgi 的整体配置和上述的 fastcgi 等差不多,只是换个前缀即可。
对于新项目,建议转向 gunicorn + proxy_pass 或 uvicorn(asgi) 架构!!
SCGI
截至 2025 年,scgi 在实际生产环境中几乎已经没人使用了,它是一个理论简洁、实践上被时代淘汰的协议。虽然 nginx 中仍然保留了 scgi 模块,但却极少在示例或最佳实践中提及。
nginx
server {
listen 80;
server_name localhost;
location / {
scgi_pass 127.0.0.1:8080;
include scgi_params;
scgi_param REQUEST_METHOD $request_method; # 自定义变量
scgi_param QUERY_STRING $query_string;
}
}
注意:
- scgi 在生产环境中已基本淘汰,请不要在新项目中再次使用它,即使项目很简单也不推荐(除非你是学习 [bushi, 这鬼东西现在谁还学它啊, 不理解但尊重 ])
- 如果你在维护一个老系统且它还用了 scgi,虽然可继续运行,但建议迁移到现代架构上来;
- 如果你在学习 web 协议,那么 了解 其原理即可,重点掌握 HTTP、fastcgi、asgi 等。
nginx 所有支持的协议总览(除开 HTTP):
| 协议 | 传输层 | 语言绑定 | 现状 |
|---|---|---|---|
| grpc | HTTP/2 | java、go、c++、python 等主流语言都支持 | 必选 |
| fastcgi | TCP、Unix | php | 差点入土 |
| uwsgi | TCP、Unix | python | 土埋半截 |
| scgi | TCP | 几乎没有 | 已经入土 |