在数据库与缓存双写的并发场景下,缓存很可能被"老数据"回填,造成脏读。本文讲解延迟双删策略的原理,以及如何用 RocketMQ 延时消息落地"第二次删除",保证 Redis 缓存最终一致。 **双写一致性**:更新数据时,确保数据库和缓存两个存储系统中的数据保持一致,避免脏读。 以一个极端并发场景为例(此时 Re...
more...
在数据库与缓存双写的并发场景下,缓存很可能被"老数据"回填,造成脏读。本文讲解延迟双删策略的原理,以及如何用 RocketMQ 延时消息落地"第二次删除",保证 Redis 缓存最终一致。 **双写一致性**:更新数据时,确保数据库和缓存两个存储系统中的数据保持一致,避免脏读。 以一个极端并发场景为例(此时 Re...
more...
当项目部署成多实例集群后,"本地缓存更新不一致"是绕不开的坑。本文从一个真实场景出发,引出消息中间件(MQ)的解决方案,再系统介绍 MQ 的基本概念、通信模型、适用场景,最后对比四大主流 MQ 并完成技术选型。 假设生产环境部署了三台笔记服务形成集群。用户更新笔记时,请求被网关转发到某个实例(比如实例 1),实例...
more...
当一个接口需要调用多个下游服务来拼装返回数据时,最容易被忽略的性能瓶颈就是:**这些互不依赖的 RPC 被串行执行了**。本文以笔记详情接口为例,讲解如何用 CompletableFuture 把串行调用改造成并行,让接口耗时从"相加"变成"取最大"。 笔记详情接口要展示发布者的昵称、头像,以及笔记正文,需要分别...
more...
上一篇介绍了 Caffeine 的淘汰算法(W-TinyLFU),这一篇我们聚焦**怎么用**:从 Caffeine 的基础用法入手,再到生产中最常见的高性能方案——**Caffeine 本地缓存 + Redis 分布式缓存组成的二级缓存**,最后梳理一下它和 Spring Cache、Ehcache、Guava...
more...
缓存的容量是有限的,当缓存满了,就必须淘汰一些旧数据来腾出空间。**缓存淘汰算法(Cache Eviction Policy)**就是决定"该淘汰谁"的策略。选错淘汰算法,缓存命中率会大幅下降,甚至比没有缓存还糟。 本文先讲三种经典淘汰算法(FIFO、LRU、LFU),再介绍现代 Java 缓存库 Caffein...
more...
很多人有个误解:一引入 Redis 缓存,就要配一个线程池配置类。其实如果只是同步 get/set,一个线程池都不需要。真正逼着你写线程配置的,是缓存场景里躲不开的**异步化**。 这篇文章就讲清楚:缓存为什么会牵扯出线程池、为什么不能直接用默认的、以及自定义时到底在配什么。 缓存最典型的三个异步场景: **异步...
more...
与访问磁盘上的数据相比,访问内存中的数据要快得多,因此内存级缓存可以极大地提升系统的响应速度和吞吐量。但缓存不是银弹,用不好反而会把数据库"打挂"。本篇文章就来系统梳理缓存领域的三大经典问题——**缓存雪崩、缓存穿透、缓存击穿**,以及各自的应对方案。 磁盘 I/O 与内存 I/O 的延迟相差几个数量级。当某个接...
more...
**分区键(Partition Key)决定一条数据被存到 Cassandra 集群里的哪个节点上**——它是 Cassandra 分布式存储的"路由地址"。 把 Cassandra 集群想象成**全国快递网络**,每个节点是一个**分拣中心**。 快递员收件时看**邮编**(分区键)→ 决定包裹发往哪个分拣中心...
more...
从规范项目上下文(AGENTS.md/PROJECT_INDEX.md 等)到用 codex 实战 vibe coding 的完整流程:不重复造轮子、深度链接复用、多模型协作、skill 积累与迭代。
more...