贵阳网站建设1685,vps网站权限,家里公网宽带做网站要备案么,大庆建设局网站迁址概述 Redis 是一种常用的内存数据库#xff0c;其所有的数据结构都可以设置过期时间#xff0c;时间一到#xff0c;就会自动删除。你可以想象 Redis 内部有一个死神#xff0c;时刻盯着所有设置了过期时间的 key#xff0c;寿命一到就会立即收割。 你还可以进一步站在死神…
概述 Redis 是一种常用的内存数据库其所有的数据结构都可以设置过期时间时间一到就会自动删除。你可以想象 Redis 内部有一个死神时刻盯着所有设置了过期时间的 key寿命一到就会立即收割。 你还可以进一步站在死神的角度思考会不会因为同一时间太多的 key 过期以至于忙不过来。同时因为 Redis 是单线程的收割的时间也会占用线程的处理时间如果收割的太过于繁忙会不会导致线上读写指令出现卡顿。所有在过期这件事上Redis 非常小心。
一、Redis 数据过期
1.1 Redis中key的过期时间 通过 EXPIRE key seconds 命令来设置数据的过期时间。返回1表明设置成功返回0表明key不存在或者不能成功设置过期时间。在key上设置了过期时间后key将在指定的秒数后被自动删除。
127.0.0.1:6379 SETEX key 5 value
OK127.0.0.1:6379 ttl s
(integer) 5127.0.0.1:6379 GET key
value127.0.0.1:6379 GET key ## 5 秒过后
(nil)命令 TTL 用于返回给定键距离过期还有多长时间。注意当key被DEL命令删除或者被SET、GETSET命令重置后与之关联的过期时间会被清除。 Redis 有四个命令可以设置键的生存时间可以存活多久和过期时间什么时候到期如下表所示
命令说明expire key seconds以秒为单位设置键的生存时间pexpire key milliseconds以毫秒为单位设置键的生存时间expireat key timestamp以秒为单位设置键的过期 UNIX 时间戳pexpireat key milliseconds-timestamp以毫秒为单位设置键的过期 UNIX 时间戳
1.2 基于时间的过期策略 在Redis中可以使用EXPIRE和PEXPIRE命令为键设置生存时间以秒或毫秒为单位。例如 # 设置多少秒后过期
EXPIRE key seconds
# 设置多少毫秒后过期
PEXPIRE key milliseconds
# 设置 key 过期时间的时间戳(unix timestamp) 以秒计
EXPIREAT key timestamp
# 设置 key 过期时间的时间戳(unix timestamp) 以毫秒计
PEXPIREAT key milliseconds-timestamp可以使用TTL命令或PTTL命令来查看键的剩余生存时间以秒或毫秒为单位。例如 # 以秒为单位返回给定 key 的剩余生存时间
TTL key
# 以毫秒为单位返回 key 的剩余的过期时间
PTTL key可以使用PERSIST命令来取消键的生存时间使其永久保存。例如 # 移除key的过期时间key将保持永久
PERSIST key二、Redis数据过期策略
Redis的过期策略主要是通过定时删除、惰性删除和定期删除三种方式来管理键的生命周期。 #mermaid-svg-aNn48ARGBqhMM52B {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-aNn48ARGBqhMM52B .error-icon{fill:#552222;}#mermaid-svg-aNn48ARGBqhMM52B .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aNn48ARGBqhMM52B .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-aNn48ARGBqhMM52B .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aNn48ARGBqhMM52B .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aNn48ARGBqhMM52B .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aNn48ARGBqhMM52B .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aNn48ARGBqhMM52B .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aNn48ARGBqhMM52B .marker.cross{stroke:#333333;}#mermaid-svg-aNn48ARGBqhMM52B svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aNn48ARGBqhMM52B .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-aNn48ARGBqhMM52B .cluster-label text{fill:#333;}#mermaid-svg-aNn48ARGBqhMM52B .cluster-label span{color:#333;}#mermaid-svg-aNn48ARGBqhMM52B .label text,#mermaid-svg-aNn48ARGBqhMM52B span{fill:#333;color:#333;}#mermaid-svg-aNn48ARGBqhMM52B .node rect,#mermaid-svg-aNn48ARGBqhMM52B .node circle,#mermaid-svg-aNn48ARGBqhMM52B .node ellipse,#mermaid-svg-aNn48ARGBqhMM52B .node polygon,#mermaid-svg-aNn48ARGBqhMM52B .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aNn48ARGBqhMM52B .node .label{text-align:center;}#mermaid-svg-aNn48ARGBqhMM52B .node.clickable{cursor:pointer;}#mermaid-svg-aNn48ARGBqhMM52B .arrowheadPath{fill:#333333;}#mermaid-svg-aNn48ARGBqhMM52B .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-aNn48ARGBqhMM52B .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-aNn48ARGBqhMM52B .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-aNn48ARGBqhMM52B .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-aNn48ARGBqhMM52B .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-aNn48ARGBqhMM52B .cluster text{fill:#333;}#mermaid-svg-aNn48ARGBqhMM52B .cluster span{color:#333;}#mermaid-svg-aNn48ARGBqhMM52B div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-aNn48ARGBqhMM52B :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 数据过期策略 定时删除 定期删除 惰性删除 过期策略说明定时删除为每个设置了过期时间的键创建一个定时器一旦过期就立即删除。但是这种方式可能会消耗大量的CPU资源因此Redis默认不使用这种策略。定期删除每隔一段时间随机抽查一些键删除其中已经过期的键。这种方式是前两种方式的折衷结合了定时任务和惰性删除的优点是Redis默认采用的策略。惰性删除只有在访问键时才会检查键是否过期过期则删除。这种方式可以最大程度地节省CPU资源但可能会导致大量的空间浪费。
2.1 定时删除 Redis 在设置键的过期时间时创建一个定时事件当过期时间到达时由事件处理器自动执行键的删除操作。定时删除策略对内存是最友好的因为它保证过期键会在第一时间被删除 过期键所消耗的内存会立即被释放。但它对 CPU 时间是最不友好的因为删除操作可能会占用大量的 CPU 时间将 CPU 时间花在删除那些和当前任务无关的过期键上从而影响缓存的响应时间和吞吐量这种做法毫无疑问会是低效的因此Redis默认不使用这种策略。
2.2 定期删除 Redis 的定期删除策略是一种平衡的方法它定时地检查 Redis 库中的过期数据采用随机抽样的方法根据过期数据的比例来调整删除的速度。过期数据的比例是指 Redis 在定期删除策略中根据每次随机抽样的键中有多少是过期的来决定是否继续删除。如果过期的键比例超过 1/4就继续抽样和删除。这样可以根据过期数据的密集程度来控制删除的频率避免过多占用 CPU 资源或内存空间。 Redis 会将每个设置了过期时间的 key 存入到一个单独的字典中默认每秒进行 10 次过期检查一次数据库。每次检查数据库并不是遍历过期的所有 key而是从数据库中随机抽取一定数量的 key 进行过期检查。接下来详细说说 Redis 的定期删除的流程。 #mermaid-svg-y7GQhrXV0w09mCat {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-y7GQhrXV0w09mCat .error-icon{fill:#552222;}#mermaid-svg-y7GQhrXV0w09mCat .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-y7GQhrXV0w09mCat .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-y7GQhrXV0w09mCat .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-y7GQhrXV0w09mCat .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-y7GQhrXV0w09mCat .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-y7GQhrXV0w09mCat .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-y7GQhrXV0w09mCat .marker{fill:#333333;stroke:#333333;}#mermaid-svg-y7GQhrXV0w09mCat .marker.cross{stroke:#333333;}#mermaid-svg-y7GQhrXV0w09mCat svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-y7GQhrXV0w09mCat .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-y7GQhrXV0w09mCat .cluster-label text{fill:#333;}#mermaid-svg-y7GQhrXV0w09mCat .cluster-label span{color:#333;}#mermaid-svg-y7GQhrXV0w09mCat .label text,#mermaid-svg-y7GQhrXV0w09mCat span{fill:#333;color:#333;}#mermaid-svg-y7GQhrXV0w09mCat .node rect,#mermaid-svg-y7GQhrXV0w09mCat .node circle,#mermaid-svg-y7GQhrXV0w09mCat .node ellipse,#mermaid-svg-y7GQhrXV0w09mCat .node polygon,#mermaid-svg-y7GQhrXV0w09mCat .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-y7GQhrXV0w09mCat .node .label{text-align:center;}#mermaid-svg-y7GQhrXV0w09mCat .node.clickable{cursor:pointer;}#mermaid-svg-y7GQhrXV0w09mCat .arrowheadPath{fill:#333333;}#mermaid-svg-y7GQhrXV0w09mCat .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-y7GQhrXV0w09mCat .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-y7GQhrXV0w09mCat .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-y7GQhrXV0w09mCat .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-y7GQhrXV0w09mCat .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-y7GQhrXV0w09mCat .cluster text{fill:#333;}#mermaid-svg-y7GQhrXV0w09mCat .cluster span{color:#333;}#mermaid-svg-y7GQhrXV0w09mCat div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-y7GQhrXV0w09mCat :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是 否 是 否 开始 随机抽取 20 个 key 删除已经过期的 key 判断执行时间 是否超过上限 stop 判断过期 key 比例超过 1/4 此时会有人问“至于为什么不扫描所有的 key”这个问题很简单Redis 作为一个单线程系统全面扫描所有键值对可能会大幅度地影响性能。因此Redis 限制每次过期扫描的最大耗时这个限制默认是 25ms。如果用户将操作超时设置得太短比如 10ms那么许多连接可能会由于超时而关闭导致应用出现许多异常。此时Redis 的慢查询日志可能并没有任何记录因为慢查询记录的只是命令的处理时间而不包括等待时间。当大量键值对在同一时刻过期时Redis 会多次扫描过期字典直到过期键的比例低于四分之一。这可能会导致短暂的系统卡顿尤其在并发请求高的情况下这可能引发所谓的缓存雪崩。
2.3 惰性删除 与定期删除不同懒惰删除策略并不会定时地去扫描和删除过期的键而是在每次访问 key 时才会判断该key是否已过期。若是过期则清除并且删除的目标仅限于当前处理的键如果没有过期不做任何处理然后返回正常的键值对给客户端。如下图所示 #mermaid-svg-9wBU8aXrlqzetYWs {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-9wBU8aXrlqzetYWs .error-icon{fill:#552222;}#mermaid-svg-9wBU8aXrlqzetYWs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9wBU8aXrlqzetYWs .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-9wBU8aXrlqzetYWs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9wBU8aXrlqzetYWs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9wBU8aXrlqzetYWs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9wBU8aXrlqzetYWs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9wBU8aXrlqzetYWs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9wBU8aXrlqzetYWs .marker.cross{stroke:#333333;}#mermaid-svg-9wBU8aXrlqzetYWs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9wBU8aXrlqzetYWs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9wBU8aXrlqzetYWs .cluster-label text{fill:#333;}#mermaid-svg-9wBU8aXrlqzetYWs .cluster-label span{color:#333;}#mermaid-svg-9wBU8aXrlqzetYWs .label text,#mermaid-svg-9wBU8aXrlqzetYWs span{fill:#333;color:#333;}#mermaid-svg-9wBU8aXrlqzetYWs .node rect,#mermaid-svg-9wBU8aXrlqzetYWs .node circle,#mermaid-svg-9wBU8aXrlqzetYWs .node ellipse,#mermaid-svg-9wBU8aXrlqzetYWs .node polygon,#mermaid-svg-9wBU8aXrlqzetYWs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9wBU8aXrlqzetYWs .node .label{text-align:center;}#mermaid-svg-9wBU8aXrlqzetYWs .node.clickable{cursor:pointer;}#mermaid-svg-9wBU8aXrlqzetYWs .arrowheadPath{fill:#333333;}#mermaid-svg-9wBU8aXrlqzetYWs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9wBU8aXrlqzetYWs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9wBU8aXrlqzetYWs .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-9wBU8aXrlqzetYWs .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-9wBU8aXrlqzetYWs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9wBU8aXrlqzetYWs .cluster text{fill:#333;}#mermaid-svg-9wBU8aXrlqzetYWs .cluster span{color:#333;}#mermaid-svg-9wBU8aXrlqzetYWs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9wBU8aXrlqzetYWs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是 否 开始 对 key 进行读写操作 判断 key 是否已过期 删除已过期 key 返回 null 给客户端 正常进行读写操作 返回数据客户端 结束 惰性删除对比定期删除而言可以节省处理器时间因为只有在键被访问时Redis 才会去检查并删除过期的键。这种策略在很多情况下都能有效地处理过期的键因为很多过期的键可能永远都不会被访问因此没有必要花费时间去删除它们。 然而惰性删除可能会导致过期的键占用内存空间。因为只有在键被访问时Redis才会删除它如果一个过期的键一直没有被访问那么它就会一直占用内存空间这在内存紧张的环境下可能会成为一个问题。举个例子 对于一些按时间点来更新的数据 比如日志log 在某个时间点之后 对它们的访问就会大大减少 如果大量的这些过期数据积压在数据库里面 用户以为它们已经过期了已经被删除了 但实际上这些键却没有真正的被删除内存也没有被释放 那结果肯定是非常糟糕。
三、结语 Redis 缓存的过期策略是保证缓存可靠性和性能的关键之一通过设置键值对缓存、设置过期时间、取消过期时间和查看 Redis 内存使用情况等操作可以实现对缓存的控制和管理。需要注意的是在设置缓存过期时间时应根据业务场景和数据类型来选择合适的时间。