<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Redis on Wimi's Space</title><link>https://wimi.space/tags/redis/</link><description>Recent content in Redis on Wimi's Space</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 12 Jun 2025 10:01:00 +0800</lastBuildDate><atom:link href="https://wimi.space/tags/redis/index.xml" rel="self" type="application/rss+xml"/><item><title>Redis 过期删除和内存淘汰策略</title><link>https://wimi.space/posts/2025/06/redis-memory-strategy/</link><pubDate>Thu, 12 Jun 2025 10:01:00 +0800</pubDate><guid>https://wimi.space/posts/2025/06/redis-memory-strategy/</guid><description>&lt;p>Redis 的过期删除策略 和内存淘汰策略 是两个不同机制，分别用于处理过期键的清理和内存不足时的数据淘汰问题。&lt;/p>
&lt;h2 id="过期删除策略">过期删除策略&lt;/h2>
&lt;p>常见的三种过期删除策略分别是定时删除、惰性删除和定期删除。&lt;/p>
&lt;h3 id="定时删除策略">定时删除策略&lt;/h3>
&lt;p>定时删除策略的做法是，在设置 Key 的过期时间时，同时创建一个定时事件，当时间到达时，由事件处理器自动执行 Key 的删除操作。&lt;/p>
&lt;ul>
&lt;li>定时删除可以保证过期 Key 会被尽快删除，也就是内存可以被尽快地释放（定时删除对内存是最友好的）。&lt;/li>
&lt;li>在过期 Key 比较多的情况下，删除过期 Key 可能会占用相当一部分 CPU 时间，会对服务器的响应时间和吞吐量造成影响（定时删除策略对 CPU 不友好）。&lt;/li>
&lt;/ul>
&lt;h3 id="惰性删除策略">惰性删除策略&lt;/h3>
&lt;p>惰性删除策略的做法是，不主动删除过期键，每次从数据库访问 Key 时，都检测 Key 是否过期，如果过期则删除该 Key。&lt;/p>
&lt;ul>
&lt;li>每次访问时才检查 Key 是否过期，所以该策略只会使用很少的系统资源（惰性删除策略对 CPU 时间最友好）。&lt;/li>
&lt;li>如果一个 Key 已经过期但仍然保留在数据库中，只要一直没有被访问，它所占用的内存就不会释放，造成了一定的内存空间浪费（惰性删除策略对内存不友好）。&lt;/li>
&lt;/ul>
&lt;h3 id="定期删除策略">定期删除策略&lt;/h3>
&lt;p>定期删除策略的做法是，每隔一段时间随机从数据库中取出一定数量的 Key 进行检查，并删除其中的过期 Key。&lt;/p>
&lt;ul>
&lt;li>通过限制删除操作执行的时长和频率，来减少删除操作对 CPU 的影响，同时也能删除一部分过期的数据减少了过期键对空间的无效占用。&lt;/li>
&lt;li>内存清理方面没有定时删除效果好，同时没有惰性删除使用的系统资源少。&lt;/li>
&lt;/ul>
&lt;p>难以确定删除操作执行的时长和频率。如果执行的太频繁，会变得和定时删除策略一样对 CPU不友好；如果执行的太少，则过期Key占用的内存不会及时得到释放。&lt;/p>
&lt;h3 id="redis-的删除策略">Redis 的删除策略&lt;/h3>
&lt;p>前面的三种过期删除策略，每一种都有优缺点，单独使用某一个策略都不能满足实际需求。Redis选择『惰性删除 + 定期删除』这两种策略配和使用，以求在合理使用CPU时间和避免内存浪费之间取得平衡。&lt;/p>
&lt;h2 id="内存淘汰策略">内存淘汰策略&lt;/h2>
&lt;p>当 Redis 的运行内存已经超过 Redis 设置的最大内存之后，会使用内存淘汰策略删除符合条件的 Key，以此来保障 Redis 高效的运行。&lt;/p>
&lt;p>Redis 内存淘汰策略共有八种，这八种策略大体分为『不进行数据淘汰』和『进行数据淘汰』两类策略。&lt;/p>
&lt;h3 id="不进行数据淘汰的策略">不进行数据淘汰的策略&lt;/h3>
&lt;ul>
&lt;li>noeviction（Redis 3.0 之后默认的内存淘汰策略）：当运行内存超过最大设置内存时，不淘汰任何数据，此时新的数据写入会被禁止。&lt;/li>
&lt;/ul>
&lt;h3 id="进行数据淘汰的策略">进行数据淘汰的策略&lt;/h3>
&lt;p>针对『进行数据淘汰』这一类策略，又可以细分为『在设置了过期时间的数据中进行淘汰』和『在所有数据范围内进行淘汰』这两类策略。&lt;/p></description></item><item><title>Redis 缓存策略和缓存异常</title><link>https://wimi.space/posts/2025/06/redis-cache-strategy/</link><pubDate>Wed, 11 Jun 2025 11:21:05 +0800</pubDate><guid>https://wimi.space/posts/2025/06/redis-cache-strategy/</guid><description>&lt;h2 id="缓存读写策略">缓存读写策略&lt;/h2>
&lt;p>Redis 中常用的缓存读写策略主要有以下几种，各有其适用场景和优缺点。&lt;/p>
&lt;h3 id="旁路缓存cache-aside">旁路缓存（Cache Aside）&lt;/h3>
&lt;p>服务端需同时维护数据库和缓存，读取时优先从缓存获取数据，缓存未命中则从数据库读取并回写缓存；写入时直接更新数据库并删除缓存。&lt;/p>
&lt;p>读策略：&lt;/p>
&lt;ol>
&lt;li>从缓存中读取数据，读取到就直接返回。&lt;/li>
&lt;li>缓存中读取不到数据，就从数据库中读取数据并返回。&lt;/li>
&lt;li>把读到的数据写入到缓存中。&lt;/li>
&lt;/ol>
&lt;p>写策略：&lt;/p>
&lt;ol>
&lt;li>先更新数据库。&lt;/li>
&lt;li>再直接删除缓存。&lt;/li>
&lt;/ol>
&lt;p>优点：&lt;/p>
&lt;ul>
&lt;li>简单易实现，适用于小规模系统。&lt;/li>
&lt;li>缓存数据不会因过期导致雪崩问题。&lt;/li>
&lt;li>通过缓存加速读取性能，减轻数据库压力。&lt;/li>
&lt;/ul>
&lt;p>缺点：&lt;/p>
&lt;ul>
&lt;li>首次请求数据一定不在缓存中，可通过预热热点数据缓解。&lt;/li>
&lt;li>数据一致性依赖业务逻辑维护，存在短暂不一致风险。&lt;/li>
&lt;li>写操作频繁时可能频繁删除缓存，影响性能。&lt;/li>
&lt;/ul>
&lt;h3 id="读写穿透readwrite-through">读写穿透（Read/Write Through）&lt;/h3>
&lt;p>单独提供一个缓存服务接管所有读写操作，服务端把缓存视为主要数据存储，从中读取数据并将数据写入其中，不直接与数据库交互。读取时若缓存未命中则由缓存层同步从数据库加载；写入时缓存层同时更新缓存和数据库。&lt;/p>
&lt;p>读写穿透策略实际只是在旁路缓存策略之上进行了封装，旁路策略的读写操作是由客户端来完成的，而读写穿透策略则是由缓存服务来完成的，后者对客户端是透明的，从而减轻了客户端的职责，简化了客户端的数据操作。&lt;/p>
&lt;ul>
&lt;li>在旁路缓存下，发生读请求的时候，如果缓存中不存在对应的数据，则由客户端自己负责把数据写入缓存，而读写穿透策略则是缓存服务自己来写入缓存的，这对客户端是不可见的。&lt;/li>
&lt;li>和旁路缓存一样，读写穿透也有首次请求数据一定不在缓存中的问题，对于热点数据可以提前放入缓存中。&lt;/li>
&lt;/ul>
&lt;h3 id="异步写入write-behind">异步写入（Write Behind）&lt;/h3>
&lt;p>仅在缓存层进行写操作，后续以异步方式更新数据库，降低实时写入压力。&lt;/p>
&lt;p>异步写入和读写穿透策略很相似，两者都是由缓存服务来负责缓存和数据库的读写。不同的是，读写穿透是同步更新缓存和数据库，而异步写入则是只更新缓存，不直接更新数据库，而是改为异步批量的方式来更新数据库。&lt;/p>
&lt;h2 id="缓存异常问题">缓存异常问题&lt;/h2>
&lt;p>引入了缓存层，就会有缓存异常的三个问题，分别是缓存雪崩、缓存击穿、缓存穿透。&lt;/p>
&lt;h3 id="缓存雪崩">缓存雪崩&lt;/h3>
&lt;p>当大量缓存在同一时间过期或 Redis 故障宕机时，如果此时有大量的请求无法从 Redis 中获取缓存数据，全部去直接访问数据库，会导致数据库压力激增，严重的会导致数据库宕机，从而导致一系列的连锁反应造成整个系统崩溃，这就是『缓存雪崩』问题。&lt;/p>
&lt;p>发生缓存雪崩有以下两个原因：&lt;/p>
&lt;ul>
&lt;li>大量数据同时过期&lt;/li>
&lt;li>Redis 故障宕机&lt;/li>
&lt;/ul>
&lt;p>针对大量数据同时过期而引发的缓存雪崩问题，常见的应对方法有下面这几种：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>均匀设置过期时间&lt;/p>
&lt;ul>
&lt;li>如果要给缓存数据设置过期时间，应该避免将大量的数据设置成同一个过期时间。我们可以在对缓存数据设置过期时间时，给这些数据的过期时间加上一个随机数，这样就保证数据不会在同一时间过期。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>互斥锁保证同一时间内只有一个请求构建缓存&lt;/p>
&lt;ul>
&lt;li>当业务线程在处理用户请求时，如果发现访问的数据不在 Redis 里，就加个互斥锁，保证同一时间内只有一个请求来构建缓存，当缓存构建完成后，再释放锁。未能获取互斥锁的请求，要么等待锁释放后重新读取缓存，要么就返回空值或者默认值。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>后台更新缓存&lt;/p>
&lt;ul>
&lt;li>业务线程不再负责更新缓存，缓存也不设置有效期，而是让缓存『永久有效』，并将更新缓存的工作交由后台线程定时更新。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>针对 Redis 故障宕机引发的缓存雪崩问题，常见的应对方法有下面这几种：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>服务熔断或请求限流机制&lt;/p>
&lt;ul>
&lt;li>Redis 故障宕机而导致缓存雪崩问题时，可以启动服务熔断机制，暂停业务应用对缓存服务的访问，直接返回错误，不用再继续访问数据库，从而降低对数据库的访问压力，保证数据库系统的正常运行，然后等到 Redis 恢复正常后，再允许业务应用访问缓存服务。&lt;/li>
&lt;li>为了减少对业务的影响，也可以启用请求限流机制，只将少部分请求发送到数据库进行处理，再多的请求就在入口直接拒绝服务，等到 Redis 恢复正常并把缓存预热完后，再解除请求限流的机制。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>构建 Redis 缓存高可靠集群&lt;/p>
&lt;ul>
&lt;li>如果 Redis 缓存的主节点故障宕机，从节点可以切换成为主节点，继续提供缓存服务，避免了由于 Redis 故障宕机而导致的缓存雪崩问题。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="缓存击穿">缓存击穿&lt;/h3>
&lt;p>业务中被频繁地访问的数据被称为热点数据，如果缓存中的某个热点数据过期了，此时大量的请求访问了该热点数据，就无法从缓存中读取，直接访问数据库，数据库很容易就被高并发的请求冲垮，这就是『缓存击穿』的问题。&lt;/p></description></item><item><title>Redis 持久化技术</title><link>https://wimi.space/posts/2025/06/redis-persistence-desc/</link><pubDate>Tue, 10 Jun 2025 09:42:44 +0800</pubDate><guid>https://wimi.space/posts/2025/06/redis-persistence-desc/</guid><description>&lt;p>Redis 的读写操作都是在内存中，所以 Redis 性能才会高，但是当 Redis 重启后，内存中的数据就会丢失，为了保证内存中的数据不会丢失，Redis 实现了数据持久化的机制，这个机制会把数据存储到磁盘，这样在 Redis 重启就能够从磁盘中恢复原有的数据。&lt;/p>
&lt;p>&lt;img src="https://static.wimi.space/blog/redis-persistence.png" alt="">&lt;/p>
&lt;p>Redis 共有三种数据持久化的方式：&lt;/p>
&lt;ul>
&lt;li>AOF 日志：每执行一条写操作命令，就把该命令以追加的方式写入到一个文件里；&lt;/li>
&lt;li>RDB 快照：将某一时刻的内存数据，以二进制的方式写入磁盘；&lt;/li>
&lt;li>混合持久化方式：Redis 4.0 新增的方式，集成了 AOF 和 RDB 的优点；&lt;/li>
&lt;/ul>
&lt;h2 id="rdbredis-database-backup">RDB（Redis Database Backup）&lt;/h2>
&lt;p>&lt;img src="https://static.wimi.space/blog/redis-rdb.png" alt="">&lt;/p>
&lt;p>Redis 可以通过创建快照来获得存储在内存里面的数据在『某个时间点』上的副本。Redis 创建快照之后，可以对快照进行备份。通过快照的方式，将内存中的数据定期保存到磁盘上，生成一个紧凑的二进制文件（.rdb）。可以将快照复制到其他服务器从而创建具有相同数据的服务器副本，还可以将快照留在原地以便重启服务器的时候使用。&lt;/p>
&lt;ul>
&lt;li>优点：文件体积小，恢复速度快，适合大规模数据备份。&lt;/li>
&lt;li>缺点：如果在两次快照之间发生崩溃，最近的写操作可能会丢失。&lt;/li>
&lt;/ul>
&lt;p>Redis 提供了两个命令来生成 RDB 快照文件：&lt;/p>
&lt;ul>
&lt;li>SAVE：同步保存操作，会阻塞 Redis 主线程；&lt;/li>
&lt;li>BGSAVE：fork 出一个子进程，子进程执行，不会阻塞 Redis 主线程，默认选项。&lt;/li>
&lt;/ul>
&lt;h3 id="rdb-基本流程">RDB 基本流程&lt;/h3>
&lt;ol>
&lt;li>通常是由客户端显式执行上述命令触发，或者由配置的规则触发 RDB 快照。&lt;/li>
&lt;li>子进程遍历数据库中的键值对，将数据序列化为 RDB 文件格式，并写入临时文件。主进程继续处理请求，期间修改的数据会通过写时复制（Copy-on-Write）技术记录到内存缓冲区。&lt;/li>
&lt;li>子进程完成写入后，用临时文件原子替换旧的 RDB 文件（如 dump.rdb），确保数据一致性。&lt;/li>
&lt;li>完成后通过 LASTSAVE 命令可查看最后一次生成 RDB 的时间。&lt;/li>
&lt;/ol>
&lt;h2 id="aofappend-only-file">AOF（Append-Only File）&lt;/h2>
&lt;p>&lt;img src="https://static.wimi.space/blog/redis-aof.png" alt="">&lt;/p>
&lt;p>与快照持久化相比，AOF 持久化的实时性更好。默认情况下 Redis 没有开启 AOF（append only file）方式的持久化（Redis 6.0 之后已经默认是开启了）。AOF 通过日志的方式，记录所有对数据库的写操作，保存在一个日志文件（.aof）中。重启时，Redis 会重放这些操作来恢复数据。&lt;/p></description></item><item><title>Redis 的基本介绍</title><link>https://wimi.space/posts/2025/06/redis-basic-introduction/</link><pubDate>Mon, 09 Jun 2025 11:00:43 +0800</pubDate><guid>https://wimi.space/posts/2025/06/redis-basic-introduction/</guid><description>&lt;blockquote>
&lt;p>⚠️️ 整理自互联网，用于概念了解。&lt;/p>&lt;/blockquote>
&lt;h2 id="redis-是什么">Redis 是什么&lt;/h2>
&lt;p>Redis（Remote Dictionary Server）是一种基于内存的数据库，对数据的读写操作都是在内存中完成，因此读写速度非常快，常用于缓存， 消息队列、分布式锁等场景。并且，Redis 存储的是 KV 键值对数据，为了满足不同的业务场景，Redis 内置了多种数据类型实现。并且 Redis 还支持事务、持久化、Lua 脚本、发布订阅模型、内存淘汰机制、过期删除机制等等。&lt;/p>
&lt;h2 id="redis-常见数据类型">Redis 常见数据类型&lt;/h2>
&lt;p>更多常用命令查询见 &lt;a href="https://redis.io/docs/latest/commands/">Redis 命令手册&lt;/a>。&lt;/p>
&lt;h3 id="string">String&lt;/h3>
&lt;p>String 是最基本的 key-value 结构，key 是唯一标识，value 是具体的值。&lt;/p>
&lt;p>value 可以是字符串，也可以是数字（整数或浮点数），value 最多可以容纳的数据长度是 512M。&lt;/p>
&lt;h3 id="list">List&lt;/h3>
&lt;p>List 是简单的字符串列表，按照插入顺序排序，可以从头部或尾部向 List 列表添加元素。&lt;/p>
&lt;p>列表的最大长度为 2^32-1，即每个列表支持超过 40 亿个元素。&lt;/p>

&lt;details>
 &lt;summary>常用指令&lt;/summary>
 &lt;pre>&lt;code class="language-bash"># 将一个或多个值 value 插入到 key 列表的表头（最左边），最后的值在最前面
LPUSH key value [value ...]

# 将一个或多个值 value 插入到 key 列表的表尾（最右边）
RPUSH key value [value ...]

# 移除并返回 key 列表的头元素
LPOP key

# 移除并返回 key 列表的尾元素
RPOP key

# 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 stop 指定，从 0 开始
LRANGE key start stop

# 从 key 列表表头弹出一个元素，没有就阻塞 timeout 秒，如果 timeout=0 则一直阻塞
BLPOP key [key ...] timeout

# 从 key 列表表尾弹出一个元素，没有就阻塞 timeout 秒，如果 timeout=0 则一直阻塞
BRPOP key [key ...] timeout
&lt;/code>&lt;/pre>
&lt;/details>

&lt;h3 id="hash">Hash&lt;/h3>
&lt;p>Hash 是一个键值对 key-value 集合，特别适合用于存储对象。&lt;/p></description></item></channel></rss>