RDB和AOF的写回策略分别是什么?

典型回答 ✅Redis的持久化机制是怎样的? 写回策略是指将数据从内存写入到持久化存储(如磁盘)的方式和时机。在Redis中,不同的持久化机制有着不同的写回策略。 RDB的写回策略 在 Redis 中,RDB 的写回策略主要包括以下几个方面: 定期触发 Redis通过配置文件中 save 参数定义了 RDB 的自动保存条件。以下是默认配置的示例: 1 2 3 save 900 1 # 如果900秒内至少有1个键发生变化,则保存快照 save 300 10 # 如果300秒内至少有10个键发生变化,则保存快照 save 60 10000 # 如果60秒内至少有10000个键发生变化,则保存快照 策略: Redis会定期检查这些条件,如果满足,触发 RDB 的保存操作。 条件可以通过修改 redis.conf 文件自定义,也可以通过命令动态设置,例如: 1 CONFIG SET save "300 10 60 10000" 手动触发 在Redis中,我们可以通过以下命令手动生成 RDB 文件: SAVE:会阻塞 Redis 服务器,直到快照完成。 BGSAVE:在后台异步生成 RDB 文件,不会阻塞 Redis。 SAVE 操作直接在主线程完成,不适合生产环境。BGSAVE 会 fork 一个子进程生成快照,更高效,但需要一定的系统资源(如内存和CPU)。 AOF的写回策略 AOF有三种数据写回策略,分别是Always,Everysec和No。 Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘; Everysec,每秒写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘; No,操作系统控制的写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。 “同步写回”可靠性肯定是最高的,但是它在每一个写命令后都有一个落盘操作,而且还是同步的,这和直接写磁盘类型的数据库有啥区别? “操作系统控制的写回"这种是最不靠谱的,谁知道操作系统啥时候帮你做持久化,万一没来及持久化就宕机了,不就gg了。 “每秒写回"是在二者之间折中了一下,异步的每秒把数据写会到磁盘上,最大程度的提升效率和降低风险。

March 22, 2026 · 1 min · santu

Redisson 的 watchdog 什么情况下可能会失效?

典型回答 ✅Redisson的watchdog机制是怎么样的? 上文先看懂 watchdog 的原理。 如果 watchdog 失效了,或者是说该续期但是没有按时续期,主要有以下几个可能。 1、你主动设置了超时时间,在上面的文章中我们看了源码,深入的介绍了,当你调用 Redisson 的加锁方法时,如果自己指定了超时时间,redisson 就不会再帮你续期了。 2、没能及时的执行续期动作,续期是通过时间轮在后台执行的,如果到了该执行的时候,因为种种原因,没有执行成功,比如说机器崩溃了,或者机器的 CPU 被打满了,无法执行这个动作了,都有可能导致没能及时执行续期动作。 3、执行续期失败了,还有一种情况就是续期任务执行了,但是执行的时候失败了,比如 Redis服务器挂了,网络连不上了,也可能会导致无法续期。

March 22, 2026 · 1 min · santu

Redis的事务和MySQL的事务区别?

典型回答 我们知道,Redis和MySQL都宣称自己支持事务的,但是他们的事务是不一样的。或者说他们对事务的定义是有差别的。 Redis中提供了一种简单的事务机制,通过 MULTI、EXEC、DISCARD 和 WATCH 命令来实现的。他可以保证一组命令按顺序执行,中间不会被其他客户端的命令打断。 但是,Redis 的事务不支持回滚,一旦事务中的某条命令出错,其他命令仍会继续执行。而且Redis的事务也没有隔离级别的定义,本身是单线程的,也没啥隔离的必要了。 ✅Redis 的事务机制是怎样的? Redis的事务的好处是,简单,轻量,不需要复杂的事务管理,之所以这么设计,是因为Redis天生就是一个缓存框架,他的目的就是为了性能。所以他放弃了数据的强一致性,而选择了优先保性能! ✅为什么Redis不支持回滚? MySQL 的事务机制是遵循标准的 ACID 的,所谓ACID,就是 原子性(Atomicity):事务内的操作要么全部成功,要么全部失败并回滚。 一致性(Consistency):事务执行后,数据库从一个一致状态转换到另一个一致状态。 隔离性(Isolation):事务之间相互独立,避免相互影响。 持久性(Durability):事务提交后,数据持久化存储。 ✅什么是数据库事务机制? MySQL 支持多种事务隔离级别,控制事务间的可见性和数据一致性: READ UNCOMMITTED:事务可以看到其他未提交事务的数据(会出现脏读)。 READ COMMITTED:只能看到已提交事务的数据(可以防止脏读,但是会出现不可重复读)。 REPEATABLE READ:同一事务内的查询结果一致(防止不可重复读,但是会出现幻读,MySQL 默认)。 SERIALIZABLE:最高隔离级别,事务完全串行化执行(防止所有读现象)。 ✅MySQL中的事务隔离级别? MySQL 的事务依赖锁机制来实现并发控制。MySQL 使用 Undo Log 实现事务的回滚,Redo Log 提供崩溃恢复能力,保证数据一致性。 所以,MySQL作为一种专门用来持久化的数据库,他有很好的数据一致性保障,并且有强大的并发支持,但是它的性能不如Redis。

March 22, 2026 · 1 min · santu

Redis能完全保证数据不丢失吗?

典型回答 ✅Redis的持久化机制是怎样的? Redis提供了两种持久化的机制,分别是RDB和AOF。AOF和RDB各自有优缺点,为了让用户能够同时拥有上述两种持久化的优点, Redis 4.0 推出了 RDB-AOF 混合持久化。 在开启混合持久化的情况下,AOF 重写时会把 Redis 的持久化数据,以 RDB 的格式写入到 AOF 文件的开头,之后的数据再以 AOF 的格式追加的文件的末尾。 那么,有了这个机制之后,能保证Redis的数据一定不丢吗? 不能! 首先Redis是基于内存存储的,虽然有了RDB和AOF的持久化机制,当Redis进程异常退出或服务器断电等情况发生时,内存中的数据可能会丢失。 有一种极端情况,那就是AOF这个持久化方案中,有一种Always的写回策略,即同步写回。也就是说每个写命令执行完,立马同步地将日志写回磁盘; ✅RDB和AOF的写回策略分别是什么? 但是即使是在always策略下,也不能保证100%不丢失数据的,主要出于以下原因: 磁盘和系统故障:如果在写入操作和同步到磁盘之间发生硬件故障或系统崩溃,可能会丢失最近的写操作。 操作系统缓冲区:即使Redis请求立即将数据同步到磁盘,操作系统的I/O缓冲区可能会导致实际写入磁盘的操作延迟发生。如果在写入缓冲区之后,没写磁盘前,机器挂了,那么数据就丢了。 操作系统缓冲区,通常指的是操作系统用于管理数据输入输出(I/O)的一种内存区域。当程序进行文件写入操作时,数据通常首先被写入到这个缓冲区,而不是直接写入到硬盘。 磁盘写入延迟:磁盘的写入并非实时完成,特别是在涉及到机械硬盘时,写入延迟主要由磁盘旋转速度(RPM)和寻道时间决定。如果在这这个延迟过程中,机器挂了,那么数据也就丢了。 归根结底,Redis就不是用来干持久化的。要持久化,就用关系型数据库。

March 22, 2026 · 1 min · santu

Redis 8.0有哪些新特性?

典型回答 2025年5月1日,Redis 8.0发布了:https://redis.io/blog/redis-8-ga/ 以下是关于8.0的更新文档:https://redis.io/docs/latest/develop/whats-new/8-0/ 简答总结下他的更新内容, 开源协议调整:重归 AGPLv3(重要) 协议变更:Redis 8.0 在保留 RSALv2/SSPLv1 双协议的基础上,新增 AGPLv3(Affero General Public License v3)授权选项,重新获得开源社区认可。 名称调整:免费版从“Redis Community Edition”更名为“Redis Open Source”,强调开源属性。 新增数据结构与功能增强(重要) 这个版本中增加了8个数据结构。 Vector Set(Beta):专为 AI 设计的向量集合,支持高维向量嵌入的存储与相似性搜索,适用于推荐系统、语义搜索等场景。 原生 JSON 支持:内置 JSON 数据类型,支持基于 JSONPath 的原子操作,无需转换格式即可直接存储和查询 JSON 文档。 **时间序列:**简化了处理快速变化的带时间戳数据的用例(例如物联网传感器、系统遥测、股票价格、商品价格、外汇汇率和加密货币价格等场景)。 概率数据结构:新增 5 种类型: Bloom Filter & Cuckoo Filter:高效判断元素是否存在(允许误判)。 Count-min Sketch:估计元素出现频率。 Top-K:统计数据流中最频繁的 K 个元素。 t-digest:计算数值分位数(如 95% 数据小于某值)。 性能优化与扩展性提升(重要) I/O 多线程改进:通过优化 I/O 线程实现,在启用 io-threads 后,吞吐量最高提升 112%(约 2 倍),尤其在高并发场景下突破百万 QPS。 命令执行加速:90 个常用命令的延迟降低 5.4%-87.4%,例如 BITMAP 操作提升 87%。 主从复制优化:新复制机制减少同步时间 18%,主节点写入速率提升 7.5%。 水平与垂直扩展:支持集群模式下的索引管理,通过多进程扩展应对海量数据。 面向 AI 与大数据的能力扩展 向量计算支持:结合 Vector Set,Redis 8.0 在基准测试中实现每秒 66K-160K 向量插入,支持实时索引和高精度搜索。 Redis for AI:整合向量数据库与缓存技术,降低对大型语言模型的依赖,提升生成式 AI(GenAI)应用的响应速度。 Redis Flex:通过 DRAM 与 SSD 混合存储,降低存储成本达 80%,同时保持高性能。 5. 开发者工具与生态整合 Redis Copilot:集成自然语言 AI 助手,帮助生成代码片段和查询语句,提升开发效率。 可视化工具增强:Redis Insight 和 VS Code 插件全面兼容 8.0,支持 Redis Copilot 交互。 模块整合:将 JSON、时间序列、概率数据结构等独立模块整合到核心,简化部署。 扩展知识 布隆过滤器的支持 在 Redis 4.0 之前,布隆过滤器并非原生功能,而是通过以下方式间接实现: ...

March 22, 2026 · 1 min · santu

Redis中hash结构比string的好处有哪些?

不知道最近为啥这个问题出现的概率很高,这俩有啥好比较的,使用的场景都不一样,唉。 典型回答 String就是字符串,用于存储简单的值,而Hash是一种哈希表结构,用于存储本身具有k-v结构的数据。一般来说他俩没啥对比的必要,只不过他们有个共同特点,那就是都可以用来存储对象。 对于String类型,要存储对象的话,需要把对象序列化成一个JSON字符串,然后把整个字符串保存在Redis的String结构中,而使用Hash接口的话,则只需要把对象转成map(比如使用fastjson可以直接转),就可以直接把这个map存储到Redis的hash结构中了。 相比之下,同样是存储对象的话,使用hash结构有一个好处,那就是如果要修改某个特定的字段,可以直接修改,而使用String的话,需要把整个字符串查出来,做反序列化以后再修改,然后再序列化之后存储到Redis中。所以,非常直观的可以看见Hash结构的操作更加简单。 而且如果要做一次修改的话,操作也要复杂的多,会存在多次网路交互,而且因为修改是在内存中做的,这个过程如果没做好分布式锁,会导致并发问题。 当然,也可以不把一个对象都存在一个key里面,也可以拆分一下,比如用独立键的方式,如 1 2 3 4 # String 方案(3个独立键) SET user:1000:name "Alice" SET user:1000:age 30 SET user:1000:email "alice@example.com" 但是这么做的话,相比用一个hash结构存储来说,key就多了很多,浪费很多空间。

March 22, 2026 · 1 min · santu

Redis中的setnx和setex有啥区别?

典型回答 这个其实只要知道了他们是什么东西的缩写就容易回答了。 SETNX ,SET if Not eXists , 只有键不存在时才设置值 不能设置过期时间 SETEX , SET with EXpiration, 设置值并指定过期时间 无条件进行设置,并带有过期时间 SETNX 示例: 1 SETNX holliskey "hello" 如果 holliskey 不存在,就设置为 "hello",**返回 ****1** 如果 holliskey 已存在,不做修改,**返回 ****0** SETEX 示例: 1 SETEX holliskey 60 "hello" **无论 **holliskey** 是否存在,都会设置为 ****"hello"** 并设置过期时间为 60 秒(TTL) 在使用场景上,setnx常用于分布式锁的实现,或者幂等处理上面。而setex常用于缓存的过期控制上面。 扩展知识 只在键不存在时设置,并设置过期时间 前面提到了,SETNX是不能设置超时时间的,那么想要实现“只在键不存在时设置,并设置过期时间 ”需要通过EXPIRE命令来配合才行,即: 1 2 SETNX hollis_key "666" EXPIRE hollis_key 10 但是这样做就不是原子命令了,需要配合事务或者lua脚本才行。 或者直接使用SET命令也能实现: 1 SET hollis_key "666" NX EX 10

March 22, 2026 · 1 min · santu

ZSet为什么在数据量少的时候用ZipList,而在数据量大的时候转成SkipList?

典型回答 ✅Redis中的Zset是怎么实现的? 通过上文我们知道,在 Redis 中,ZSet在特定条件下会使用ZipList作为其内部表示。这通常发生在有序集合较小的时候**,默认情况下,当元素数量少于128,每个元素的长度都小于64字节的时候,使用ZipList(ListPack),否则,使用SkipList!** Redis 之所以在数据量少的时候使用ZipList(包括后来的ListPack),而在数据量大时转成SkipList(跳表),是出于 内存优化 和 性能考量 的双重目的。 内存对比 首先ZipList是一个压缩的数据结构,它的每个元素都是连续存储的(和数组有点像),因此内存的使用非常紧凑。与其他数据结构相比,ZipList在小规模数据存储时显著减少了内存占用。 而在内存方面,SkipList 相比于 ZipList 内存开销要大得多,因为它是通过多个链表层级来实现的,每个元素需要额外的指针来维护层级结构。 那么按理说,ZipList的内存占用要比Skip要小的,所以他更适合用来存储数据,所以ZSet会使用ZipList,那为啥不全都用,而只有在数据量小的额时候采用呢? 这就涉及到ZipList的一个缺点了。 性能对比 前面说过了ZipList 是一个紧凑的线性结构,所以如果在 ZipList 中查找一个元素时,可能需要遍历整个列表,同理插入和删除操作也是线性的。所以它的插入、删除和查找操作的时间复杂度通常是 O(N)。 而SkipList 采用多级索引结构,它的查找、插入、删除操作的时间复杂度是 O(log N),远远优于 ZipList 的 O(N)。 总结 所以,ZipList的存储更节省空间,而SkipList的操作性能会更好。 所以,对于少量数据,ZipList更好,因为它的内存开销很小,而且性能也可以接受(N越小,logN和N的差别更小)。但是当数据量大到一定程度时,SkipList的 O(log N) 性能会显著优于ZipList 的 O(N) 性能,尤其是涉及到范围查询和顺序遍历时。 所以,默认情况下,当元素数量少于128,每个元素的长度都小于64字节的时候,ZSet使用ZipList(ListPack),否则,使用SkipList!

March 22, 2026 · 1 min · santu

Redisson里面的锁是怎么来防止误删的?

典型回答 先看问题,Redisson怎么误删,其实所谓的误删其实就是删除了别的线程加的锁,为什么会发生这种情况呢?假如两个线程的执行顺序是如下的: 线程1 线程2 加锁成功(设置了超时时间) 执行业务逻辑 锁到期,被自动删除 加锁成功 执行业务逻辑 业务逻辑执行完,解锁 那么,如果没有在解锁的时候做一些额外的判断,是可能会线程1把线程2的锁给解了的。那么,Redisson作为一个成熟的框架,他是如何解决这个问题的呢? Redisson一旦设置了超时时间,watchdog就不会续期了,就可能出现上面的情况。https://www.yuque.com/hollis666/ec96i7/fg0f0wh41g8eu5ik 这种题,就是讲源码最有说服力了。 先来看Redisson加锁的核心lua相关的代码,在RedissonLock#tryLockInnerAsync中。 1 2 3 4 5 6 7 8 9 10 11 <T> RFuture<T> tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) { return evalWriteSyncedNoRetryAsync(getRawName(), LongCodec.INSTANCE, command, "if ((redis.call('exists', KEYS[1]) == 0) " + "or (redis.call('hexists', KEYS[1], ARGV[2]) == 1)) then " + "redis.call('hincrby', KEYS[1], ARGV[2], 1); " + "redis.call('pexpire', KEYS[1], ARGV[1]); " + "return nil; " + "end; " + "return redis.call('pttl', KEYS[1]);", Collections.singletonList(getRawName()), unit.toMillis(leaseTime), getLockName(threadId)); } 这段lua脚本执行之后,最终会在Redis中存一个Hash结构,key就是我们指定的加锁的key的名字,比如Hollis666,然后存储的hash的key是一个真正的lockName,存储的值是这个锁被重入的次数。 ...

March 22, 2026 · 2 min · santu

Redis中的hash和Java中的HashMap有啥区别?

典型回答 这个问题挺有意思的,如果真要对比,可以列出几十条的区别来,因为毕竟他们俩差异太大了, 一个是Redis中的,一个是Java中的,虽然都是hash结构。如果面试官问这个问题的话,我认为他可能比较关注的是这几个区别: 1、底层数据结构 2、并发安全相关 3、扩容机制 数据结构 Redis的hash结构底层是基于ziplist(压缩列表)和hashtable实现的(6.0中ziplist改为了listpack)。 ziplist用于小的hash结构,而hashtable用于大的hash结构,和zset差不多,也是可以通过配置来调整具体使用的结构的,以下两个同时满足时用ziplist,否则用hashtable。 Hash 中 k-v 对的数量 <= hash-max-ziplist-entries (默认 512) 所有 k 和 v 的字符串长度 <= hash-max-ziplist-value (默认 64 字节) ✅Redis的ZipList、SkipList和ListPack之间有什么区别? ziplist/listpack的优点是极其节省内存。没有指针开销,内存局部性好。但是缺点就是增删改查操作(尤其是中间插入/删除)时间复杂度 O(n),效率较低。 hashtable的优点是查找、插入、删除的平均时间复杂度 O(1),适合大数据量。缺点就是内存开销较大,需要额外存储指针。 ✅ZSet为什么在数据量少的时候用ZipList,而在数据量大的时候转成SkipList? 而HashMap采用的是数组+链表+红黑树的存储结构。 ✅HashMap的数据结构是怎样的? 并发安全 因为Redis本身是单线程执行命令的,所以所有对 Redis Hash 的操作都是线程安全的。 而Java中的HashMap本身并不是线程安全的,需要用使用ConcurrentHashMap来保证线程安全。(Collections.synchronizedMap(new HashMap<>())也可以) 扩容机制 Redis的hash结构在扩容的时候,采用一种渐进式rehash的方案,可以实现平滑扩容,避免一次性迁移所有数据导致的请求延迟。但是缺点就是在数据迁移期间,内存占用是翻倍的。 ✅什么是Redis的渐进式rehash Java中的HashMap是没有采用渐进式rehash的,而是会一次性完成整个 Map 中所有元素的迁移。好处和缺点刚好和上面的渐进式rehash相反,优点是不占用过多空间,缺点就是迁移过程会阻塞。 但是其实HashMap也没必要搞渐进式rehash,因为HashMap一般都是存很少的数据,不像Redis一样大家会拿他来存很多东西。

March 22, 2026 · 1 min · santu

留言给博主