nginx 不能解析 sql,但可通过 http 方法、url 路径或 tcp 端口实现读写分离:基于 $request_method 的 map 配置最常用;路径匹配适用于接口约定明确场景;stream 模块支持四层数据库端口分流,需应用主动连接对应端口。

Nginx 本身不解析 SQL,也不能直接对数据库请求做读写判断,但它可以在应用层(HTTP)或传输层(TCP)通过明确的规则,把不同语义的流量分发到不同后端,从而实现读写分离的效果。关键在于:由谁来区分读写,决定了 Nginx 的配置方式和适用场景。
基于 HTTP 请求方法的读写分离(适用于 Web 应用)
这是最常用、最清晰的方式。Nginx 利用 $request_method 变量识别请求类型,将写操作(如 POST、PUT、DELETE)转发给写集群,其余读操作(如 GET、HEAD)转发给读集群。
- 使用
if指令配合proxy_pass是基础做法,但要注意:-
if在 location 中有执行顺序限制,不能嵌套,且可能影响性能 - 更推荐用
map指令提前定义后端变量,再在proxy_pass中引用,更高效、更安全
-
示例配置片段:
map $request_method $backend {
default backend_read;
POST backend_write;
PUT backend_write;
DELETE backend_write;
}
upstream backend_read {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
upstream backend_write {
server 192.168.1.20:8080;
}
server {
listen 80;
location / {
proxy_pass http://$backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
- 注意
proxy_pass后必须带/,否则路径拼接会出错 - 所有写请求统一走
backend_write,读请求轮询backend_read中的节点
基于 URL 路径的读写分离(适用于接口级拆分)
当业务接口约定明确时(例如 /api/v1/user/create 是写,/api/v1/user/list 是读),可直接用 location 匹配路径做分流。
- 优点:规则直观,无需解析请求体或方法
- 缺点:需前后端协同约定路径规范,灵活性略低
示例:
location ^~ /api/v1/user/create {
proxy_pass http://backend_write/;
}
location ^~ /api/v1/user/update {
proxy_pass http://backend_write/;
}
location /api/ {
proxy_pass http://backend_read/;
}
-
^~表示前缀匹配且优先级高于正则,适合接口路由 - 未匹配的
/api/请求默认走读集群,避免遗漏
基于四层 TCP 代理的数据库读写分离(适用于 MySQL/Redis 等)
Nginx 的 stream 模块可监听不同端口,把连接按端口转发到不同上游组,但前提是应用主动连接对应端口。
- 写请求连
3306→ 转发到主库(mysql_write) - 读请求连
3307→ 转发到从库集群(mysql_read)
示例(需在 nginx.conf 顶层配置,非 http 块内):
stream {
upstream mysql_write {
server 10.0.0.100:3306;
}
upstream mysql_read {
server 10.0.0.101:3306;
server 10.0.0.102:3306;
}
server {
listen 3306;
proxy_pass mysql_write;
}
server {
listen 3307;
proxy_pass mysql_read;
}
}
- 必须启用
stream模块(编译时加--with-stream,配置中加载stream { ... }) - Nginx 不解析 MySQL 协议,只做连接级转发,真正的读写逻辑由应用或中间件控制
需要避开的常见误区
- ❌ 认为 Nginx 能自动识别 SQL 并分流:它没有 SQL 解析能力,无法判断
SELECT还是UPDATE - ❌ 用
weight参数试图让 Nginx “智能”分配读写流量:weight 控制的是节点权重,不是语义路由 - ❌ 在
http块里配置stream相关指令:stream 必须在顶层,与 http 平级 - ❌ 忽略健康检查和连接超时:尤其在数据库代理场景,应配置
proxy_timeout和health_check(需商业版或第三方模块)
真正可靠的读写分离,核心逻辑应在应用层(如 Spring 的 AbstractRoutingDataSource)、数据库中间件(如 ProxySQL、MaxScale)或客户端驱动(如 MySQL Connector/J 的 replication 模式)中完成。Nginx 的角色是稳定接入、协议无关转发和连接管理,不是决策中心。











