如何保证 Redis 与数据库的数据一致性?

1.为什么会不一致 ? Redis 是缓存层,数据库是持久层。 二者数据可能不一致的原因包括: 更新数据库成功,但更新缓存失败; 缓存提前过期; 并发写操作覆盖(顺序问题); 异步更新延迟。 2.更新策略 2.1 Cache Aside(旁路缓存) 读操作 1. 读缓存 2. 如果缓存不存在 ,再读数据库 3. 将数据写入缓存(设置过期时间) 写操作: 先更新数据库,再删除缓存 缺点:删除缓存可能失败;删除顺序不当会不一致 2.2 Read/Write Through(读写穿透) 应用不直接访问DB,所有读写都经由缓存代理完成 缺点:实现复杂,性能略低 2.3 Write Behind(异步写回) 只写缓存,由缓存异步刷回数据库 缺点:容易丢数据 3.处理并发问题 3.1延迟双删策略(Double Delete) 1. 更新数据库; 2. 删除缓存; 3. 延迟 500ms 再删一次缓存。 //可以应对并发中缓存被“脏写”回的情况。 3.2异步消息队列(MQ) 数据更新时发送 MQ 消息,异步同步缓存状态。 3.3分布式锁 保证更新操作串行执行,避免交叉覆盖。

2025年10月14日 · Mumu

垃圾回收机制 Garbage Collection

1.垃圾回收的认识 1.1垃圾回收是什么,有什么作用 GC,全称 Garbage Collection,即垃圾回收,是一种自动内存管理的机制。 当程序向操作系统申请的内存不再需要时,垃圾回收主动将其回收并供其他代码进行内存申请 时候复用,或者将其归还给操作系统,这种针对内存级别资源的自动回收过程,即为垃圾回收。而 负责垃圾回收的程序组件,即为垃圾回收器。 垃圾回收其实是一个完美的“Simplicity is Complicated”的例子。一方面,程序员受益于 GC,也不再需要对内存进行手动的申请和释放操作,GC 在程序运行时自动释放残留的内存。另一 方面,GC 对程序员几乎不可见,仅在程序需要进行特殊优化时,通过提供可调控的 API,对 GC 的运行时机、运行开销进行把控的时候才得以现身。 通常,垃圾回收器的执行过程被划分为两个半独立的组件: 1)赋值器(Mutator):这一名称本质上是在指代用户态的代码。因为对垃圾回收器而言,用户 态的代码仅仅只修改对象之间的引用关系,也就是在对象图(对象之间引用关系的一个有向图)上 进行操作。 2)回收器(Collector):负责执行垃圾回收的代码。 1.2常见的垃圾回收的实现方式有哪些,Go使用的是什么 所有的 GC 算法其存在形式可以归结为追踪(Tracing)和引用计数(Reference Counting)这 两种形式的混合运用。 (1)追踪式 GC 从根对象出发,根据对象之间的引用信息,一步步推进直到扫描完毕整个堆并确定需要保留的 对象,从而回收所有可回收的对象。Go、 Java、V8 对 JavaScript 的实现等均为追踪式 GC。 (2)引用计数式 GC 每个对象自身包含一个被引用的计数器,当计数器归零时自动得到回收。因为此方法缺陷较 多,在追求高性能时通常不被应用。Python、Objective-C 等均为引用计数式 GC。 比较常见的 GC 实现方式包括: 1)追踪式,分为多种不同类型,例如: 标记清扫:从根对象出发,将确定存活的对象进行标记,并清扫可以回收的对象。 标记整理:为了解决内存碎片问题而提出,在标记过程中,将对象尽可能整理到一块连续的内 存上。 2)增量式:将标记与清扫的过程分批执行,每次执行很小的部分,从而增量推进垃圾回收,达到 近似实时、几乎无停顿的效果。 3)增量整理:在增量式的基础上,增加对对象的整理过程。 4)分代式:将对象根据存活时间的长短进行分类,存活时间小于某个值的为年轻代,存活时间大于 某个值的为老年代,永远不会参与回收的对象为永久代。并根据分代假设(如果一个对象存活时间不 长则倾向于被回收,如果一个对象已经存活很长时间则倾向于存活更长时间)对对象进行回收。

2025年10月12日 · Mumu

我的第一篇博客

今天开始记录我在 Go 高并发项目中的一些心得体会。

2025年9月2日 · Mumu