nginx这玩意儿,平时大家用它做反向代理、负载均衡、静态资源缓存,玩得挺溜。但你有没有想过,让它直接去访问数据库?听起来有点反常规,毕竟 PHP、Python 这些后端语言才是数据库的“亲儿子”。可现实是,在高并发场景下,比如电商秒杀、实时排行榜、API 网关限流,nginx 直连数据库能省掉一层中间件的转发开销,响应时间直接砍半。这招不是银弹,但用对了地方,性能提升肉眼可见。

先说说 nginx 怎么跟数据库“说话”。它本身不支持数据库协议,但通过第三方模块,比如 (OpenResty 的核心),就能用 Lua 脚本写 SQL 查询。配置也不复杂:在 块里加个 指向存放 SQL 逻辑的目录,然后在 中写 ,里面直接调 。比如要查用户信息,以前得让 nginx 转发给后端,后端再连数据库,现在 nginx 自己就把活儿干了。不过要注意,这玩意儿对 Lua 编程有要求,别指望零基础直接上手。
性能优化的第一个坑,就是连接池。nginx 每处理一个请求,如果都新建数据库连接,那跟自杀没区别。MySQL 的并发连接数有限,默认 151 个,开太多直接报错。正确做法是把 设成 50 到 100,再配合 ,比如 600 秒。这样连接用完不关,放回池子里复用。我之前调过一个小型 API 网关,连接池从 0 调到 50 后,QPS 从 800 飙升到 3200,数据库 CPU 负载反而下降了 20%。别小看这个参数,它直接决定了 nginx 能不能扛住突发流量。
安全配置上,最容易被忽略的是 SQL 注入。nginx 的 Lua 环境里,千万别用字符串拼接 SQL,例如 ,这是自杀式写法。要用 函数转义参数,或者直接用预编译语句。OpenResty 的 模块支持 方法传参,像 ,底层会自动做参数化查询。另外,数据库账号权限要最小化,nginx 只配一个只读账号,连写操作都不给。再在 块里加 和 指令,只让内网 IP 访问数据库端口,外网直接禁掉。
再说个高级玩法:缓存。nginx 直连数据库虽然快,但扛不住高频率的重复查询。比如首页的热门商品列表,每秒被访问几千次,每次都去数据库查一遍,数据库迟早会跪。解决方案是用 开一块共享内存做缓存,key 是 SQL 的哈希值,value 是查询结果,设置 5 秒左右的过期时间。代码里先查缓存,命中直接返回,未命中再去数据库,查询完再写缓存。实测下来,缓存命中率 80% 以上,数据库查询量直接降一个数量级。不过缓存更新策略要想清楚,数据变更后要么主动清除缓存,要么接受短暂的不一致。
日志和监控也不能马虎。nginx 访问数据库时出错了,需要快速定位。在 Lua 脚本里加 捕获异常,把错误信息写到 ,然后配合 记录数据库响应时间。还可以把慢查询单独拎出来,例如超过 100 毫秒的请求,用 异步写入一个文件。这样运维时一眼就能看出是哪条 SQL 拖慢了整体性能。别忘了给数据库加上 ,防止一条烂 SQL 把整个 nginx 拖死。
说个实战案例。我帮一个直播平台调过礼物排行榜,原来用 PHP 实现,每秒只能处理 500 个请求,数据库连接池经常被打满。换成 nginx + OpenResty 直连数据库后,Lua 脚本里用 Redis 做二级缓存,排行榜数据每 10 秒刷新一次。nginx 直接返回缓存结果,只有缓存失效时才查询 MySQL。最终 QPS 稳定在 1.2 万,数据库负载从 80% 降到 15%。当然,这种架构不适合所有场景,比如复杂事务、多表关联查询,还是交给后端语言处理更稳妥。nginx 直连数据库,本质是用空间换时间,用简单逻辑换极致性能,关键看业务能否接受这种“快刀斩乱麻”的玩法。


