极简架构的缓存分层设计:浏览器、CDN、应用与数据库的全链路缓存策略

发布时间:2026/7/15 23:29:29

极简架构的缓存分层设计:浏览器、CDN、应用与数据库的全链路缓存策略
极简架构的缓存分层设计浏览器、CDN、应用与数据库的全链路缓存策略一、同一条 SQL 被执行了 4700 次对一个营销落地页做性能分析时发现页面底部的热门文章模块每次请求都查询数据库SQL 完全一样。日活 2 万的情况下这条 SQL 一天被执行了 47 万次每个页面约 25 次。数据库 CPU 利用率中42% 的时间在处理这条查询。问题不是 SQL 慢——它执行只需要 8ms。问题是从浏览器到数据库每一层都没有做缓存。如果每一层承担它该承担的缓存责任这条 SQL 的重复执行可以降到每天 200 次0.04% 的原频率。二、全链路缓存的三层架构flowchart TD U[用户浏览器] -- L1[L1: 浏览器缓存] L1 --|Cache Miss| CDN[L2: CDN 边缘节点] CDN --|Cache Miss| APP[L3: 应用服务器] APP -- L3A[L3a: 应用内存缓存] L3A --|Cache Miss| L3B[L3b: 分布式缓存 Redis] L3B --|Cache Miss| DB[数据库] L1 -.-|Cache Hit| U CDN -.-|Cache Hit| U L3A -.-|Cache Hit| APP L3B -.-|Cache Hit| APP每层的缓存命中都在为下一层减负。L1 命中时不需要网络请求CDN 命中时不需要到达源站应用缓存命中时不需要查询数据库。2.1 浏览器缓存策略HTTP/1.1 200 OK # 强缓存1 小时内直接从浏览器缓存读取不发请求 Cache-Control: public, max-age3600, immutable # 图片等静态资源使用更长的缓存时间 Cache-Control: public, max-age31536000, immutable # 协商缓存带上 ETag服务器判断资源是否修改 ETag: abc123关键区分max-age期间浏览器完全不发请求强缓存ETag/Last-Modified是协商缓存——浏览器发请求但服务器可能返回 304 Not Modified无需传输 body。对于带有 content hash 的静态资源如app.a1b2c3.js使用immutable 1 年 max-age 是最优策略——文件内容变了 hash 就变URL 跟着变不需要担心缓存更新。2.2 CDN 缓存的分层策略# Nginx 作为源站时对不同类型的响应设置不同的 CDN 缓存规则 # 静态资源CDN 缓存 7 天 location /assets/ { add_header Cache-Control public, max-age604800, s-maxage604800; } # API 响应CDN 缓存 30 秒公共数据接口用户不敏感 location /api/public/ { add_header Cache-Control public, max-age30, s-maxage30; } # 用户私有数据CDN 不缓存 location /api/user/ { add_header Cache-Control private, no-cache, no-store; } # HTML 页面CDN 缓存 5 分钟 location / { add_header Cache-Control public, max-age300, s-maxage300; }s-maxage是专门给共享缓存CDN的指令优先级高于max-age。用它可以在浏览器和 CDN 上设置不同的缓存时长。2.3 应用层缓存实现// 应用内存缓存LRU 策略固定大小热点数据常驻 type AppCache struct { lru *lru.Cache metrics *CacheMetrics } func (c *AppCache) GetOrFetch( ctx context.Context, key string, ttl time.Duration, fetcher func(context.Context) (interface{}, error), ) (interface{}, error) { // 内存缓存命中 if val, ok : c.lru.Get(key); ok { c.metrics.hit(lru) return val, nil } c.metrics.miss(lru) // 等待数据源 val, err : fetcher(ctx) if err ! nil { return nil, fmt.Errorf(获取数据失败: %w, err) } c.lru.Add(key, val) return val, nil } // Redis 分布式缓存带防击穿的互斥锁 func (c *RedisCache) GetOrFetch( ctx context.Context, key string, ttl time.Duration, fetcher func(context.Context) (string, error), ) (string, error) { val, err : c.client.Get(ctx, key).Result() if err nil { return val, nil } if !errors.Is(err, redis.Nil) { return , fmt.Errorf(Redis 查询失败: %w, err) } // 缓存击穿防护拿不到锁的请求等待结果而非重复查询 lockKey : key :lock locked, err : c.client.SetNX(ctx, lockKey, 1, 5*time.Second).Result() if err ! nil { return , err } if !locked { // 自旋等待锁持有者完成数据加载 for i : 0; i 10; i { time.Sleep(100 * time.Millisecond) val, err c.client.Get(ctx, key).Result() if err nil { return val, nil } } return , fmt.Errorf(等待缓存加载超时) } defer c.client.Del(ctx, lockKey) val, err fetcher(ctx) if err ! nil { return , err } // 随机化 TTL 避免缓存雪崩 jitter : time.Duration(rand.Int63n(int64(ttl) / 10)) c.client.Set(ctx, key, val, ttljitter) return val, nil }随机化 TTL增加 ±10% 的抖动是防止缓存雪崩的关键技巧——不要让所有 Key 在同一时刻过期。三、缓存失效策略的渐进式设计不是所有场景都需要精确的缓存失效。按数据实时性要求分层数据类型缓存时长失效策略示例静态配置1 小时定时刷新站点名称、功能开关准实时数据30 秒时间窗口过期文章列表、热门排行用户数据5 分钟主动失效用户信息、订单状态实时数据不缓存-库存余量、支付状态主动失效的成本最高需要知道何时失效但数据一致性最好。对用户数据使用写穿透Write-Through写入数据库的同时更新缓存。func (s *UserService) UpdateUser(ctx context.Context, user *User) error { // 1. 更新数据库 if err : s.db.Update(ctx, user); err ! nil { return fmt.Errorf(数据库更新失败: %w, err) } // 2. 更新缓存写穿透 cacheKey : fmt.Sprintf(user:%d, user.ID) data, _ : json.Marshal(user) if err : s.cache.Set(ctx, cacheKey, data, 10*time.Minute); err ! nil { // 缓存更新失败不影响主流程记录告警 log.Printf(缓存更新失败(key%s): %v, cacheKey, err) } return nil }四、边界与权衡缓存穿透查询不存在的数据恶意请求查询不存在的用户 ID每次都穿透到数据库。用布隆过滤器或缓存空值设置较短的 TTL。内存缓存的 GC 压力Go 的内存缓存如 freecache、bigcache使用预分配的字节数组存储避免 GC 扫描。LRU 缓存中的指针对象会被 GC 扫描在大量缓存条目场景下 100 万可能导致 GC 暂停增加。一致性的最终答案缓存带来的数据不一致窗口是经常被高估的风险。对于用户个人数据5 分钟缓存5 分钟内用户看到旧的用户名其实不会造成实际损害。精确权衡不一致的后果 数据库查询的成本时才值得投入主动失效。不适合缓存的场景支付流程、实时库存扣减、竞拍出价——数据的实时性要求压倒一切。在这些场景中缓存是 bug 的来源而非性能优化的手段。五、总结全链路缓存的核心思想是让每层干好自己的事。浏览器缓存管用户重复访问CDN 缓存管地域分发的延迟应用缓存管数据库保护每层命中都在为下一层减负。落地方案从最低成本、最高收益开始先配置 CDN 缓存静态资源Nginx 加几行Cache-Control头→ 再为高频查询加应用内存缓存代码改动量小→ 然后在流量增长后加入 Redis 分布式缓存 → 最后配置浏览器缓存策略。缓存的 TTL 设置不是一次性完成的——上线后观察缓存命中率如 Redis 的keyspace_hits/keyspace_misses比率逐步调优。

相关新闻

独立开发者的成本优化:云资源选型与 AI API 调用的精细化成本控制

独立开发者的成本优化:云资源选型与 AI API 调用的精细化成本控制

2026/7/15 23:29:29

独立开发者的成本优化:云资源选型与 AI API 调用的精细化成本控制 一、$320/月的账单中,71% 花在了"用不到"的资源上 一个独立开发者的 SaaS 工具,AWS 月账单 $320。细看账单明细:RDS t3.medium 每月 $85,EC…

Agent 推理链的性能剖析:从 Token 消耗到工具调用延迟的端到端优化

Agent 推理链的性能剖析:从 Token 消耗到工具调用延迟的端到端优化

2026/7/15 23:29:29

Agent 推理链的性能剖析:从 Token 消耗到工具调用延迟的端到端优化 一、一个 Agent 推理的"隐形账单" 对一个代码生成 Agent 做性能剖析时,发现了几个反直觉的数据: 模型推理耗时 3.2 秒,但端到端延迟 8.7 秒——其中 5…

电容去耦与滤波的设计规范-应用实战D03

电容去耦与滤波的设计规范-应用实战D03

2026/7/15 23:29:29

电容去耦与滤波的设计规范-应用实战D03 在电路设计中,有一个看似简单却至关重要的环节常常被新手忽视,那就是去耦电容和滤波电容的设计。许多人认为,只要在电源引脚旁随便放几个电容就万事大吉,但实际情况却远非如此。你是否曾遇到这样的困惑:明明给芯片加了一排电容,电…

每天认识一种投资品类:保险

每天认识一种投资品类:保险

2026/7/16 1:09:33

文章目录1. 什么是保险?2. 保险的核心功能3. 保险的主要分类3.1 财产保险3.2 人身保险4. 保险 vs 其他投资品类5. 谁适合配置保险?6. 总结1. 什么是保险? 保险,是一种风险管理的财务安排。投保人向保险人支付保险费,当…

EeveeSpotify终极指南:如何在iOS上免费解锁Spotify Premium完整功能

EeveeSpotify终极指南:如何在iOS上免费解锁Spotify Premium完整功能

2026/7/16 1:09:33

EeveeSpotify终极指南:如何在iOS上免费解锁Spotify Premium完整功能 【免费下载链接】EeveeSpotify A tweak to get Spotify Premium for free, just like Spotilife 项目地址: https://gitcode.com/GitHub_Trending/ee/EeveeSpotify 还在为Spotify Premium的…

3步掌握SteamAutoCrack:快速实现Steam游戏自动化破解

3步掌握SteamAutoCrack:快速实现Steam游戏自动化破解

2026/7/16 1:09:33

3步掌握SteamAutoCrack:快速实现Steam游戏自动化破解 【免费下载链接】Steam-auto-crack Steam Game Automatic Cracker 项目地址: https://gitcode.com/gh_mirrors/st/Steam-auto-crack SteamAutoCrack是一个专为技术爱好者和游戏收藏者设计的开源工具&…

gui+python,把乱糟代码变填空神器,爽到飞起

gui+python,把乱糟代码变填空神器,爽到飞起

2026/7/16 1:09:33

1 学习初衷曾经有那么一天, 当我正在思考本人所编写的那些代码之际, 忽然间涌起了一阵阵的躁动, 这是为何? 因为本人并非计算机专业科班出身的缘故, 每当看到一行又一行的代码, 就如同一条又一条的小虫子一般, 这使得我内心觉得, 这些代码实在是太过杂乱无章了。另外还有一个情…

Java培训砸钱不如砸对路,陕西18%岗位增长等你抢

Java培训砸钱不如砸对路,陕西18%岗位增长等你抢

2026/7/16 1:09:33

以陕西当地 IT 产业发展的当下情形而言, 西安身为西部关键 IT 枢纽, 汇聚了众多诸如金融科技、政务信息化、电商服务等大量依靠 Java 技术的企业, 在最近三年里, Java 开发岗位的招聘数量平均每年增长 18%, 专业技能过硬的 Java 人才一直处在供不应求的状况之中。对于那些想要踏…

开源新纪元:深度解析小米 MiMo Code 的技术架构与实战应用

开源新纪元:深度解析小米 MiMo Code 的技术架构与实战应用

2026/7/16 0:59:33

开源新纪元:深度解析小米 MiMo Code 的技术架构与实战应用 在当今的大模型领域,参数量的竞争似乎已不再是唯一的焦点,社区正在将目光转向模型的推理能力与实际落地效果。近期,一个名为 MiMo Code 的项目悄然登上各大技术社区的热榜…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/16 0:35:09

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/13 20:43:19

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/15 0:26:43

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…

Python实现跨境电商商品图批量翻译教程

Python实现跨境电商商品图批量翻译教程

2026/7/16 0:09:31

一、问题引入做跨境电商的卖家朋友,你是否遇到过这样的困扰?每次上架新品到亚马逊、Shopee或Lazada等平台,都需要处理大量商品图片的多语言版本。比如上架200款衣服,每款需要翻译成英语、日语、韩语等5种语言,这意味着…

跨境电商多语言商品图翻译方案实现

跨境电商多语言商品图翻译方案实现

2026/7/16 0:09:31

一、问题引入对于做跨境电商的卖家来说,多语言商品图的制作一直是令人头疼的环节。当你准备在亚马逊、Shopee、Lazada等多个平台同步上架新品时,首先遇到的就是图片翻译问题。以一位做家居用品的卖家为例,他需要将200张商品图片中的英文文案全…

Windows系统文件d3dx9_36.dll丢失找不到问题解决

Windows系统文件d3dx9_36.dll丢失找不到问题解决

2026/7/16 0:09:31

在使用电脑系统时经常会出现丢失找不到某些文件的情况,由于很多常用软件都是采用 Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC运行库或者安装…