redis中全局命令exists、del、expire、ttl(惰性删除和定期删除)
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">exists——判定 key 是否存在</a></li><li><a href="#_label1">del——删除指定的 key</a></li><li><a href="#_label2">expire——给 key 设置过期时间</a></li><li><a href="#_label3">ttl——查询过期时间</a></li><ul class="second_class_ul"><li><a href="#_lab2_3_0">过期策略是如何实现的</a></li><ul class="third_class_ul"><li><a href="#_label3_3_0_0">惰性删除</a></li><li><a href="#_label3_3_0_1">定期删除</a></li></ul></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>exists——判定 key 是否存在</h2><p>语法:</p>
<div class="jb51code"><pre class="brush:sql;">exists key
# 返回值:key 存在的个数
</pre></div>
<p>针对多个 <code>key</code> 来说,是非常有用的</p>
<p>时间复杂度 <span><span><span>O(1)O(1)</span><span><span><span>O</span><span>(</span><span>1</span><span>)</span></span></span></span></span></p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202511/2025110510562461.png" /></p>
<p><code>Redis</code> 组织这些 <code>key</code> 就是按照哈希表的方式来组织的。<code>Redis</code> 支持很多数据结构指的是 <code>value</code> 可以是一些复杂的数据结构<br /><code>Redis</code> 自身的这些键值对,是通过哈希表的方式来组织的,<code>Redis</code> 具体的值,又可以是一些数据结构</p>
<blockquote><ul><li>Redis 是一个客户端-服务器结构的程序,客户端和服务器之间通过网络来进行通信</li><li>每次我们敲的命令,都是由 Redis 客户端包装成一个请求,发送给 Redis 服务器,服务器再返回响应</li><li>因此最好不要把 key 分开写。分开写会产生更多轮次的网络通信,效率比较低,成本比较高</li></ul></blockquote>
<p><strong>封装和分用</strong></p>
<ul><li>进行网络通信的时候,发送方发送一个数据,这个数据就要从应用层,到物理层,层层封装(每一层协议都要加上报头或者尾)==>发送一个快递,要包装一下,要包装好多层</li><li>接收方收到一个数据,这个数据就要从物理层,到应用层,层层分用(把每一层协议中的报头或者尾给拆掉)==>收到一个快递,要拆快递,拆很多层</li><li>这些过程都是要消耗时间,消耗 CPU 的</li></ul>
<p>Redis 自身也非常清楚上述问题,所以 Redis 的很多命令都支持一次就能操作多个 key 的/多种操作</p>
<p class="maodian"><a name="_label1"></a></p><h2>del——删除指定的 key</h2>
<p>可以一次删除一个或者多个</p>
<p><strong>语法:</strong></p>
<div class="jb51code"><pre class="brush:sql;">del key
</pre></div>
<ul><li>时间复杂度 <span><span><span>O(1)O(1)</span><span><span><span>O</span><span>(</span><span>1</span><span>)</span></span></span></span></span></li><li>返回值:删除掉的 <code>key</code> 的个数</li></ul>
<blockquote><p>在 MySQL 中,删除类的操作</p>
<ul><li>drop database</li><li>drop table</li><li>drop from…<br />这些都是非常危险的操作,一旦删除之后,数据就没了。但在 Redis 中,危险程度就小很多了</li><li>因为 Redis 的主要应用场景,就是作为缓存,里面存的只是一个热点数据,而全量数据是在 MySQL 中。如果把 Redis 中的 key 删除了几个,问题不大,大不了再从 MySQL 中读就可以了。</li><li>但是如果把所有的数据,或者一大半数据都干没了,这种影响就会很大。本来是靠 Redis 帮 MySQL 负重前行,Redis 没数据了,大部分请求就直接打给 MySQL 了,然后就容易把 MySQL 搞挂</li><li>相比之下,如果是 MySQL 这样的数据,哪怕误删了一个数据,都可能影响是很大的</li><li>但如果是把 Redis 作为数据库,此时误删数据的影响就大了</li></ul></blockquote>
<p class="maodian"><a name="_label2"></a></p><h2>expire——给 key 设置过期时间</h2>
<p><strong>单位为秒</strong></p>
<p><code>key</code> 存活时间超过这个 <code>expire</code> 指定的值,就会被自动删除</p>
<ul><li>在很多业务场景,都是有时间限制的<ul><li>验证码。要实现验证码一分钟失效的功能,我们就可以把这个验证码信息存储到 <code>Redis</code> 中,将 <code>expire</code> 设置为 <code>60</code>,等到一分钟后 <code>Redis</code> 里面的验证码信息被删除,就查询不到了</li><li>点外卖。优惠券,在指定时间有效</li><li>分布式锁。基于 <code>Redis</code> 实现分布式锁,为了避免出现不能正确解锁的情况,通常都会在加锁的时候设置一下过期事假(所谓的使用 <code>Redis</code> 作为分布式锁,就是给 <code>Redis</code> 里写一个特殊的 <code>key</code> <code>value</code>)</li></ul></li></ul>
<p><strong>语法:</strong></p>
<div class="jb51code"><pre class="brush:sql;">expire key seconds
pexpire key 毫秒
</pre></div>
<ul><li>对于计算机来说,秒是一个非常长的时间,下面的时间单位是<strong>毫秒</strong></li></ul>
<p class="maodian"><a name="_label3"></a></p><h2>ttl——查询过期时间</h2>
<p><code>time to live</code></p>
<blockquote><p>在网络原理,IP 协议报头中,就有一个 TTL 字段</p>
<ul><li>IP 中的 TTL 不是用时间衡量过期的,而是次数</li></ul></blockquote>
<p>查询当前 key 的过期时间还剩多少<br /><strong>语法:</strong></p>
<div class="jb51code"><pre class="brush:sql;">ttl key //秒
pttl key //毫秒
</pre></div>
<ul><li>返回剩余过期时间</li><li>返回 <code>-1</code> 表示没有关联过期时间</li><li>返回 <code>-2</code> 表示 <code>key</code> 不存在</li></ul>
<p class="maodian"><a name="_lab2_3_0"></a></p><h3>过期策略是如何实现的</h3>
<p>#高频面试<br />一个 <code>Redis</code> 中可能同时存在很多很多 <code>key</code>,这些 <code>key</code> 中有很大一部分都有过期时间。此时,<code>Redis</code> 服务器怎么知道哪些 <code>key</code> 已经过期要被删除,哪些 <code>key</code> 还没过期?</p>
<ul><li>如果直接遍历所有的 key,显然是行不通的,效率非常低</li><li>Redis 整体的策略是两方面<ol><li>定期删除</li><li>惰性删除</li></ol></li></ul>
<p class="maodian"><a name="_label3_3_0_0"></a></p><h4>惰性删除</h4>
<ul><li>假设这个 <code>key</code> 已经到达过期时间了,但是暂时还没删除它,<code>key</code> 还在</li><li>紧接着,后面又一次访问,正好用到了这个 <code>key</code>,于是这次访问就会让 <code>Redis</code> 服务器触发删除 <code>key</code> 的操作,同时再放回一个 <code>nil</code></li></ul>
<blockquote><ul><li>你去超市买水,正要付钱的时候,看了一眼日期,发现过期了,于是老板就说不卖了,于是就把这瓶水下架了,这就是“惰性删除”</li><li>老板也不清楚哪些过期了,哪些没过期,就在卖出的时候做一次检查,如果过期了就不卖了,如果还没过期,就继续卖</li></ul></blockquote>
<p>但显然,单靠惰性删除肯定是不靠谱的,一个超市这么多商品,怎么可能全去靠用户去检查,所以肯定还得要有一个辅助的机制——<strong>定期删除</strong></p>
<p class="maodian"><a name="_label3_3_0_1"></a></p><h4>定期删除</h4>
<p>这个超市老板,要定期查看超市里面的商品,看是否有过期产品</p>
<ul><li>但是如果超市商品很多,那么每次遍历一遍就非常慢</li><li>所以,每次抽取一部分,进行验证过期时间。保证抽取检查的过程足够快</li></ul>
<p>为什么这对定期删除的时间有明确的要求呢?</p>
<ul><li>因为 <code>Redis</code> 是单线程程序,主要的任务是处理每个命令的任务(刚才扫描过期 <code>key</code>…)</li><li>如果扫描过期 <code>key</code> 消耗的时间太多了,就可能导致正常处理请求命令就被阻塞了(产生了类似 <code>key *</code> 的效果)</li></ul>
<p>虽然有了上述两种策略结合,但整体的效果仍一般。仍然有可能会有很多过期的 <code>key</code> 被残留了,没有及时删除掉</p>
<p>但是 <code>Redis</code> 为了对上述进行补充,还提供了一系列的<strong>内存淘汰策略</strong></p>
頁:
[1]