动静分离把静态资源分流出去,热点文章缓存把高并发查询挡在数据库之前,两者叠加才能扛住突发流量。很多门户站在没做这两个动作前,一有爆款文章就卡死,做完后发现服务器压力小了一大半,下面直接讲怎么落地。
动静分离和缓存区别到底在哪?先别急着上手
不少站长把动静分离和缓存混为一谈,其实它们解决的是两个不同维度的瓶颈,动静分离关注的是请求该由谁处理,缓存关注的是数据能不能少查一次。
- 动静分离:把图片、CSS、JS、HTML静态页这类资源从应用服务器里剥离,交给Nginx、CDN或对象存储处理,动态请求才回到Java/PHP/Node后端。
- 热点文章缓存:把被频繁读取的文章内容、评论数、阅读量放到内存里,让数据库只承担写操作和冷数据查询。
用一个场景说明:用户打开一篇爆款文章,静态资源(样式、图片)走CDN,动态数据(文章正文、作者信息)走Redis缓存,如果这两步没做,所有请求都会打到Web服务器和数据库上,响应自然慢。
行业共识认为,门户站点性能优化的第一步永远是分流和缓存,而不是升级机器配置。
门户网站动静分离怎么配置?Nginx实操步骤
以最常见的Nginx + Tomcat架构为例,动静分离的配置其实不复杂,核心就是几个location规则。
静态资源与动态请求分流
在Nginx配置文件中创建一个server块,设置如下:
server {
listen 80;
server_name example.com;
# 静态资源直接由Nginx处理
location ~ .(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
root /data/static;
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# 文章详情页等动态请求转发给后端
location /article/ {
proxy_pass http://backend_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 其他动态请求
location / {
proxy_pass http://backend_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
这个配置做了两件事:
凡是静态资源后缀的请求,Nginx直接读磁盘或内存返回;其余请求转发给后端应用,注意静态资源的root路径要和实际存放目录一致,否则会出现404。
缓存头与CDN配合
静态资源的expires和Cache-Control头要设置好。expires 30d让浏览器强缓存,immutable则告诉浏览器文件内容不会变,不用重新验证,如果是部署CDN,通常只需要把静态资源域名CNAME到CDN服务商,然后在CDN控制台上设置缓存规则。
这里有一个实操建议:给静态资源文件名加上版本号或hash值,比如app-8f3a2b.css,这样更新版本时URL会变,浏览器自然拉取新文件,旧版本在缓存过期后自动淘汰。
动静分离后要注意的路径问题
- 图片、附件等上传文件不能放在应用服务器本地,要迁移到云存储或独立文件服务器。
- 涉及HTTPS时,证书配置在Nginx层面,后端不用再处理TLS。
- 如果动态请求包含用户登录态,Cookie的Domain要和静态资源域名分开,避免静态资源携带Cookie浪费带宽。
热点文章缓存策略有哪些?从本地缓存到分布式
缓存不是一个Redis就能搞定所有问题,针对门户站点的热点文章,需要分层级设计。
本地缓存与分布式缓存怎么选
- 本地缓存:Caffeine、Guava等,存在应用进程内,读取速度极快,适合单机场景,但集群环境下每个节点的数据不一致。
- 分布式缓存:Redis、Memcached,所有节点共享同一份数据,适合多实例部署,但有一次网络开销。
- 多级缓存:先查本地,未命中再查Redis,最后查数据库,这是一种常见组合拳。
门户站点通常是多实例部署,所以Redis是主力,本地缓存做辅助,比如把热点文章的ID列表放在本地缓存,把文章详情放在Redis,这样能减少对Redis的并发读取。
缓存更新策略
热点文章缓存不能只靠设置过期时间,因为一篇刚发布的爆款可能几分钟内就被疯狂点击,常用的更新策略有:
- TTL过期:设置一个固定时间,如10分钟,到期后自动重建,实现简单,但可能有短暂不一致。
- 主动更新:编辑后台发布或修改文章时,主动删除或刷新对应缓存,能保证数据实时性,适合低频率修改的场景。
- 异步重建:当缓存过期时,不直接让请求去查数据库,而是由后台线程统一重建缓存,请求先返回旧数据或等待,这种方式能有效防止缓存击穿。
缓存穿透、击穿与雪崩的应对
这三个问题在不同情况下发生,需要分别处理。
- 缓存穿透:查询一个不存在的文章ID,缓存和数据库都没有,请求直接打到DB,解决方法是缓存空值(expire设短一些),或者用布隆过滤器拦一下。
- 缓存击穿:某个热点文章的缓存刚好过期,同时大量请求涌进来,全部打到数据库,解决方法是互斥锁只让一个请求去重建缓存,其他请求等待或返回旧值。
- 缓存雪崩:大量key在同一时间失效,导致数据库压力骤增,解决方法是给TTL加随机值,让过期时间错开。
业内专家指出,门户站点不需要追求极致的缓存一致性,先保证高峰期不挂,再考虑数据同步的实时性。
动静分离与缓存协同工作的典型流程
假设一篇重要文章发布,访问量突然飙升,完整的请求链路应该是这样:
- 用户请求
article/12345,DNS解析后到达CDN节点,CDN返回静态资源(HTML骨架、CSS、JS)。 - 页面JS发起AJAX请求获取文章详情,这个请求命中Nginx静态规则?不,这是动态请求,转发到后端。
- 后端首先查询本地缓存中的热点标记,如果命中则直接走Redis读取文章内容。
- Redis命中则直接返回JSON;未命中则从数据库读取,然后异步写回Redis,并设置过期时间。
- 在请求处理过程中,Nginx对静态资源直接返回,不占用后端资源。
这个流程中,数据库只承担了第一次查询的压力,后续大量请求都被缓存和CDN扛住了,你可以通过Grafana监控看到,后端QPS可能只有几百,而缓存层QPS达到数万。
门户站点性能优化的几个常见坑
不要以为配置了动静分离和缓存就万事大吉,实际运维中经常遇到以下问题:
- 静态资源版本更新不及时:CSS或JS文件被浏览器缓存,用户看到旧页面,排查时用
curl -I看响应头,确认Cache-Control设置是否正确。 - 缓存key设计不合理:文章ID当作key,会导致移动端和PC端共用一份缓存,如果两端内容不同就会串数据,建议把UA和设备类型加入key。
- 热点key集中在同一台Redis上:Redis集群中,某个key的hashSlot固定,访问量大时单节点成为瓶颈,解决方法是对key做本地缓存,或者使用多级缓存。
- 所有页面都做缓存:门户首页和频道页动态性较强,不宜长时间缓存,可以用
Edge Side Includes或组件级缓存,而不是整页缓存。
动静分离和热点文章缓存是门户站点应对高并发的两个轮子,缺一个都容易翻车,先把Nginx分流做好,再把Redis缓存策略规划清楚,你的站点就能在爆款来临时稳如老狗。
门户站点动静分离与热点文章缓存策略常见问题解析
门户网站动静分离怎么配置才不破坏现有架构?
不需要改动业务代码,在Nginx层新增静态资源location规则,把静态文件迁移到独立目录或CDN,同时保留动态请求的proxy_pass,后端应用不需要感知变化,只需要把静态资源链接改为新域名或路径,如果后端有鉴权逻辑,注意静态资源不要经过鉴权中间件。
热点文章缓存策略中,缓存穿透和缓存击穿的区别是什么?
缓存穿透是指请求的数据在缓存和数据库中都不存在,导致每次请求都穿透到数据库,缓存击穿是指某个热点数据缓存过期,大量请求同时去数据库重建,穿透的解决方法是缓存空值或布隆过滤器,击穿则用互斥锁或异步重建,两者都可能导致数据库压力飙升,但发生时机和应对方式不同。
动静分离之后,动态页面还需要做热点文章缓存吗?
需要,动静分离解决的是静态资源占用后端连接的问题,动态页面请求依然会打到Web服务器,如果不做热点文章缓存,数据库依然会被高频查死,更好的做法是,将文章详情这类读多写少的数据做成接口缓存或页面片段缓存,与静态资源分流形成互补。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/646126.html





