1023 字
5 分钟
提升 Web 性能:基于 Nginx 和 Memcached 的页面缓存方案
1. 为什么选择 Nginx + Memcached?
在传统的 Web 架构中,即使使用了后端缓存(如在 PHP 或 Python 代码中调用 Redis),请求依然需要经过 Nginx -> 后端应用解析器 -> 缓存系统 这一漫长的链路。
通过使用 Nginx 的 ngx_http_memcached_module 模块,我们可以实现 Nginx -> Memcached 的直接通信。当缓存命中时,请求无需触达后端应用逻辑,从而实现“零开销”分发动态内容,单机并发处理能力通常可提升数倍甚至数十倍。
2. 工作原理图解
- 请求拦截:Nginx 接收请求,根据预设规则生成缓存键(通常基于 URL)。
- 直接提取:Nginx 发起向 Memcached 的异步查询。
- 缓存命中 (Hit):数据直接由 Nginx 返回客户端,耗时极低。
- 缓存未命中 (Miss):Nginx 通过
error_page或try_files将请求回源给后端应用(如 FastCGI),后端处理完逻辑后将结果回写至 Memcached。
3. 生产环境配置指南
第一步:配置 Nginx 缓存逻辑
在 Nginx 配置文件中,我们需要定义上游服务器地址,并精细化处理请求头,以确保缓存能够正确返回。
# 定义 Memcached 集群upstream memcached_backend { server 10.1.240.166:11211; keepalive 32; # 保持长连接,提升性能}
server { listen 80; server_name example.com;
location / { # 1. 定义缓存 Key:这里使用完整请求 URI set $memcached_key "$request_uri";
# 2. 尝试从缓存中获取 memcached_pass memcached_backend;
# 3. 设置默认类型及响应头以便调试 default_type text/html; add_header X-Cache-Status HIT; add_header X-Memcached-Key $memcached_key;
# 4. 如果发生错误(404/502/504),则跳转到内部命名的 location @fallback error_page 404 502 504 = @fallback; }
# 后端逻辑处理与缓存写入 location @fallback { add_header X-Cache-Status MISS; proxy_pass http://your_backend_server; # 或者 fastcgi_pass }}第二步:后端应用写入缓存(以 PHP 为例)
后端不仅要负责处理业务逻辑,还要在生成内容后,将结果通过 Key-Value 形式存入 Memcached。
<?php$m = new Memcached();$m->addServer('10.1.240.166', 11211);
// 建议使用当前请求的 URI 作为 Key$cacheKey = $_SERVER['REQUEST_URI'];$content = $m->get($cacheKey);
if ($content) { echo $content;} else { // 开启缓冲区捕获页面输出 ob_start();
// 执行复杂的业务逻辑、数据库查询等 render_complex_page();
$output = ob_get_contents(); ob_end_flush();
// 存入缓存,设置过期时间(例如 3600 秒) $m->set($cacheKey, $output, 3600);}4. 关键避坑与进阶建议
4.1 内容类型(Content-Type)丢失问题
标准的 ngx_http_memcached_module 并不存储 HTTP 头信息。如果你的页面有多种 MIME 类型,直接读取可能会导致浏览器无法正确识别 HTML 或图片。
- 对策:在后端存入缓存时,额外存储一个头信息 Key,或者在 Nginx 中根据扩展名固定
default_type。
4.2 缓存压缩(Gzip)
为了节省内存,后端通常会将内容压缩后存入 Memcached。
- 注意:如果你在后端压缩了内容,必须在 Nginx 配置中手动添加
gunzip on;(需要安装ngx_http_gunzip_module),或者在返回时强制加上add_header Content-Encoding gzip;。
4.3 缓存失效(Cache Invalidation)
Memcached 不支持模糊删除。如果某个新闻分类下的所有页面都变了,你很难一次性清除所有相关的 Key。
- 进阶方案:引入版本号机制(Namespace),在 Key 中加入版本号前缀,更新时只需修改版本号即可让旧缓存全部失效。
5. 方案对比:Memcached vs Redis
| 特性 | Memcached | Redis |
|---|---|---|
| 性能 | 极高(简单 KV 协议,系统开销更小) | 高(功能丰富,略有系统开销) |
| 持久化 | 不支持 | 支持 |
| Nginx 支持 | 原生模块支持,配置简单 | 需安装 srcache-nginx-module 等第三方模块 |
| 数据类型 | 仅字符串 | 字符串、哈希、列表、集合等 |
6. 总结
结合 Nginx 与 Memcached 的页面缓存方案是 “用空间换时间” 的经典实践。它尤其适用于:
- 高频访问的 CMS 页面(如新闻首页、公告)。
- API 查询结果缓存。
- 计算代价昂贵的报表页面。
虽然现在 Redis 非常流行,但在追求极致的简单 KV 查询性能时,Nginx + Memcached 的原生组合依然是运维利器。
提升 Web 性能:基于 Nginx 和 Memcached 的页面缓存方案
https://sw.rscclub.website/posts/nginx-memcache/