找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

815

积分

0

好友

109

主题
发表于 4 小时前 | 查看: 0| 回复: 0

从缓存到数据库性能优化的架构对比示意图

上周二,我一口气删掉了 847 行 Redis 代码
周三,我的技术负责人删了 1,200 行
到周五,我们的初级工程师删了 2,100 行

我们没有商量,没有开会,没有写冗长的技术提案。

我们只是都看了 同一组真实的生产基准测试数据,然后得出了同一个结论:我们正在为一层已经不再必要的基础设施付钱

这不是一篇关于数据库性能的理论文章,而是一个真实的故事,讲述了 PostgreSQL 18 是如何亲手颠覆我坚持了六年的、关于缓存必要性的信仰。

我曾经为之辩护了3年的架构

在做出改变之前,我们系统的结构是这样的:

┌─────────────────────────────────────────┐
│                Application              │
└─────────────────┬──────────────────────┘
                  │
                  ▼
         ┌────────────────┐
         │     Redis      │   ≈ 0.1ms
         │    (Cache)     │
         ┌────────────────┘
                  │
                  ▼
         ┌────────────────┐
         │   PostgreSQL   │   ≈ 5–15ms
         │   (Storage)    │
         └────────────────┘
               ↑
        cache invalidation hell

这套架构出自我手。我曾无数次在设计评审会上为它辩护,撰写文档解释为什么这是“正确的做法”,甚至还批量培训新人,教他们如何与繁琐的缓存失效逻辑共舞。

三年来,我维护的不仅仅是缓存,还包括:

  • 847 行缓存逻辑,分散在 12 个文件里。
  • 一个每月 $340 的托管 Redis 集群。
  • 每季度至少出现两次 的缓存失效 Bug。
  • 两套完全不同的监控面板和 On-Call 手册。
  • 一个我不断用“这就是工程现实”来安慰自己的巨大心智负担。

我甚至曾为这套复杂性感到一丝骄傲,它让我觉得自己像一个解决了真实难题的高级工程师。

直到 2025 年 9 月PostgreSQL 18 的发布改变了一切。

PostgreSQL 18:真正把我脑子敲碎的时刻

PostgreSQL 18 引入了一个关键功能:Asynchronous I/O (AIO,异步 I/O)

官方发布说明写得非常克制:“新的 I/O 子系统,可提升顺序扫描、位图堆扫描、清理(VACUUM)等操作的性能。”

这句话在技术上是精准的,但在情感上毫无冲击力。让我用更直白的语言解释这意味着什么。

旧的 PostgreSQL

就像一个非常礼貌但刻板的图书管理员:

  • 你要一本书。
  • 他走过去。
  • 拿回来。
  • 交给你。
  • 然后你再要下一本。
    一次只做一件事,秩序井然,但也非常慢

PostgreSQL 18

这位管理员突然意识到:自己原来有两只手,而且可以一次抱很多本书
你要10本书,他一次全给你抱过来,“啪”一声放在你桌上。完事。

技术核心是:io_uring 与 Linux 内核的深度集成
用人类的话说就是:PostgreSQL 终于学会同时干多件事了

官方宣称性能提升 2-3 倍,但我对这类数据库基准测试的信任度是零——我认为这是基本的职业素养。所以,我决定用 我们真实的生产查询 来验证。

改变一切的那组数字

我们有一个非常典型的看板查询,每天要运行上百万次:

SELECT date, sum(events)
FROM activity
WHERE user_id = $1
AND date > now() - interval '30 days'
GROUP BY date;

测试结果如下:

PostgreSQL 17

  • 冷缓存:12–18ms
  • 热缓冲池:4–6ms

PostgreSQL 18(开启 AIO 后)

  • 冷缓存:6–8ms
  • 热缓冲池:1.8–2.5ms

我反复跑了 4 次,因为起初我无法相信自己的眼睛。

不到 3 毫秒,查询30天的数据,没有 Redis没有缓存层,仅仅依靠 PostgreSQL 自身。

那个让人不舒服的算术题

是的,Redis 的读取性能可以轻松达到 0.1ms,听起来是无敌的。

但现实世界并非实验室,我们需要考虑所有因素:

  • 缓存命中率73%(这是我们的实际数据)。
  • 缓存未命中:需要15ms查询数据库,然后写入 Redis。
  • 序列化/反序列化成本:约0.3ms。
  • Redis 网络往返延迟(RTT):约0.8ms。
  • 缓存失效 Bug 带来的事故处理成本:无法用金钱简单衡量,且频繁发生。

计算加权平均延迟后,我们得到了一个惊人的数字:

引入 Redis 缓存后的实际平均延迟 ≈ 4.2ms

PostgreSQL 18(无缓存)的直接查询延迟是:

≈ 2.1ms

我对着这个对比结果沉默了许久。

让这一切成为现实的配置(只有5行)

性能的提升并非来自复杂的架构改造,仅仅是 PostgreSQL 配置文件中新增的几行:

io_method = 'io_uring'
effective_io_concurrency = 200
maintenance_io_concurrency = 50
shared_buffers = 16GB
io_combine_limit = 512kB

是的,就这些。

  • 没有修改一行应用代码。
  • 没有调整整体架构。
  • 没有启动一个耗时半年的迁移项目。

我们在周三部署了新配置,周四就看到看板查询延迟下降了 47%。到了周五,团队的三名成员不约而同地开始删除各自负责模块中的 Redis 缓存代码。

真正被忽略的杀手功能:Skip Scans

除了 AIO, PostgreSQL 18 还有一个被严重低估的特性:B-tree Skip Scans

我们有一个复合索引:(user_id, status, created_at)

但很多查询却长这样,缺少了索引的第一列 user_id

SELECT * FROM orders
WHERE status = 'pending'
AND created_at > '2025-01-01'
ORDER BY created_at DESC
LIMIT 50;

PostgreSQL 17 中:

  • 这个查询用不上那个复合索引。
  • 要么全表扫描,要么选择次优的执行计划。
  • 我们当时的解决方案是:用 Redis 配合 TTL 做一层缓存来兜底。

PostgreSQL 18 中:

  • 优化器会自动“跳过”索引的第一个列 (user_id)。
  • 对每个不同的 user_id 执行高效的范围扫描。
  • 结果是:索引被成功利用

性能提升立竿见影:

45ms → 8ms

同样,没有缓存,没有 TTL 逻辑,没有缓存失效的烦恼。

三年Redis的真实成本(远不止账单)

1. 直接基础设施成本

  • 三年托管 Redis 集群费用:$12,240

2. 处理缓存Bug的工程时间成本

  • 共发生 23 次相关事故。
  • 平均每次处理耗时 7 小时。
  • 按每小时 $150 的工程师成本计算。
  • 总计约 $24,150

3. 开发速度的隐性损失

  • 每个新功能都要先考虑缓存策略。
  • 每次数据库 Schema 改动都要同步思考缓存 Key 的设计。
  • 每次部署都要担心缓存预热(Warm-up)问题。
  • 保守估计,这导致了 至少 15% 的开发效率损失

4. 无法量化的心智负担

每一次代码审查、故障调试、系统设计,大脑里都必须额外加载一套缓存模型,这种持续的上下文切换消耗是真实存在却难以统计的。

保守估算,过去三年我们为这套“未经验证的”缓存方案付出的总成本超过 $36,000。而我们最初引入它,竟从未认真衡量过它是否真的必要。

Redis仍然不可替代的领域(请别误会)

我并非在给 Redis 写讣告。它在其核心领域依然是无可争议的王者:

  • 会话存储:对延迟和抖动有极致要求。
  • 限流INCRTTL 的组合简单高效。
  • 发布/订阅
  • 排行榜/有序集合
  • 分布式锁

我们现在更清晰的架构是:

Application
   ├── Redis(专用于 Session / Rate Limit / 分布式锁等)
   └── PostgreSQL 18(承载其他所有业务数据和查询)

系统变得更简单、更经济、更稳定,新同事也更容易理解。

那个真正让我反思的问题

我的代码库中,有多少决策是基于“高级工程师都这么干”,而不是基于“我们实际测量过,这样确实更快”?

我一开始就引入 Redis,并非因为数据证明了其必要性,而是因为它 “看起来像”一个专业的、标准的架构

PostgreSQL 的开发团队花了多年时间,重写 I/O 子系统、深度集成 Linux 内核、修复无数边界情况……最终,他们让我那 847 行精心维护的缓存代码 看起来像什么?

像一组从未被实际数据验证过的、昂贵的假设。

何时你仍需要谨慎对待此方案

请冷静评估你的场景,以下情况可能并不适合:

  • P99 延迟要求必须低于 2ms:此时 Redis 可能仍是必需品。
  • 存在百万 QPS 级别的热 KeyRedis 的内存处理能力更合适。
  • Linux 内核版本低于 5.10:不支持 io_uring,无法启用 AIO。
  • 存储磁盘仍是 HDD:I/O 层面的优化效果会大打折扣。
  • 云服务商尚未支持 PostgreSQL 18 的 AIO:需要确认你的环境是否可用。

这不是一场非此即彼的宗教战争,而是一个需要基于自身数据和环境做出的工程判断

最重要的结论

在每个代码库中,都可能存在一些:

  • 曾经合理,
  • 现在却无人质疑,
  • 但实际上已经过时的复杂性。

PostgreSQL 18 只是迫使我正视了其中之一。

我删除那 847 行代码的唯一原因是:我终于去测量了,并且相信了数据

也许,你也应该用真实的数据,重新审视一下你系统中那些“理所当然”的复杂性了。如果你想与更多开发者交流此类架构优化经验,欢迎来 云栈社区数据库/中间件 板块参与讨论。




上一篇:海康威视2025年财报深度分析:营收增长0.02%近乎停滞,利润反增18.46%的背后逻辑
下一篇:大公司引入AI后开发效率仅提升10%?揭秘组织层面的技术瓶颈与变革路径
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-25 18:17 , Processed in 0.249395 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表