免费网站注册,网站流量盈利,wordpress加载模板文件,怎样做网站链接Redis 是可以对 key 设置过期时间的#xff0c;因此需要有相应的机制将已过期的键值对删除#xff0c;而做这个工作的就是过期键值删除策略。
如何设置过期时间
先说一下对 key 设置过期时间的命令。 设置 key 过期时间的命令一共有 4 个#xff1a;
expire key n#x…Redis 是可以对 key 设置过期时间的因此需要有相应的机制将已过期的键值对删除而做这个工作的就是过期键值删除策略。
如何设置过期时间
先说一下对 key 设置过期时间的命令。 设置 key 过期时间的命令一共有 4 个
expire key n设置 key 在 n 秒后过期比如 expire key 100 表示设置 key 在 100 秒后过期pexpire key n 设置 key 在 n 毫秒后过期比如 pexpire key2 100000 表示设置 key2 在 100000 毫秒100 秒后过期。expireat key n设置 key 在某个时间戳精确到秒之后过期比如 expireat key3 1655654400 表示 key3 在时间戳 1655654400 后过期精确到秒pexpireat key n设置 key 在某个时间戳精确到毫秒之后过期比如 pexpireat key4 1655654400000 表示 key4 在时间戳 1655654400000 后过期精确到毫秒 当然在设置字符串时也可以同时对 key 设置过期时间共有 3 种命令 set key value ex n 设置键值对的时候同时指定过期时间精确到秒 set key value px n 设置键值对的时候同时指定过期时间精确到毫秒 setex key n value 设置键值对的时候同时指定过期时间精确到秒。 如果你想查看某个 key 剩余的存活时间可以使用 TTL 命令。
命令的原理
虽然有多种不同单位和不同形式的设置命令但实际上 EXPIRE、PEXPIRE、EXPIREAT 三个命令都是使用PEXPIREAT 命令来实现的无论客户端执行的是以上四个命令中的哪一个经过转换之后最终的执行效果都和执行 PEXPIREAT 命令一样。
# 设置键值对的时候同时指定过期时间位 60 秒setex key1 60 value1
OK
# 查看 key1 过期时间还剩多少ttl key1
(integer)56ttl key1
(integer)52
# 如果突然反悔取消 key 的过期时间则可以使用 PERSIST key 命令。
# 取消 key1 的过期时间persist key1
(integer)1# 使用完 persist 命令之后
# 查下 key1 的存活时间结果是 -1表明 key1 永不过期 ttl key1
(integer) -1如何判定 key 已过期了
每当我们对一个 key 设置了过期时间时Redis 会把该 key 带上过期时间存储到一个过期字典expires dict中也就是说「过期字典」保存了数据库中所有 key 的过期时间。
redisDb 结构的 expires 字典保存了数据库中所有键的过期时间我们称这个字典为过期字典 过期字典的键是一个指针这个指针指向键空间中的某个键对象也即是某个数据库键。 过期字典的值是一个 long long 类型的整数这个整数保存了键所指向的数据库键的过期时间——一个毫秒精度的 UNIX 时间戳。 过期字典存储在 redisDb 结构中如下
typedef struct redisDb{dict *dict;/* 数据库键空间存放着所有的键值对 */dict *expires;/* 键的过期时间 */
....
} redisDb;过期字典数据结构结构如下
过期字典的 key 是一个指针指向某个键对象过期字典的 value 是一个 long long 类型的整数这个整数保存了 key 的过期时间
过期字典的数据结构如下图所示 思考redis为什么不像java1.8HashMap那样当链表达到一定的长度转换为红黑树来提高查询效率呢 在做范围查找的时候平衡树比skiplist操作要复杂。在平衡树上我们找到指定范围的小值之后还需要以中序遍历的顺序继续寻找其它不超过大值的节点。如果不对平衡树进行一定的改造这里的中序遍历并不容易实现。而在skiplist上进行范围查找就非常简单只需要在找到小值之后对第1层链表进行若干步的遍历就可以实现。 平衡树的插入和删除操作可能引发子树的调整逻辑复杂而skiplist的插入和删除只需要修改相邻节点的指针操作简单又快速。 从内存占用上来说skiplist比平衡树更灵活一些。一般来说平衡树每个节点包含2个指针分别指向左右子树而skiplist每个节点包含的指针数目平均为1/(1-p)具体取决于参数p的大小。如果像Redis里的实现一样取p1/4那么平均每个节点包含1.33个指针比平衡树更有优势。 查找单个keyskiplist和平衡树的时间复杂度都为O(log n)大体相当而哈希表在保持较低的哈希值冲突概率的前提下查找时间复杂度接近O(1)性能更高一些。所以我们平常使用的各种Map或dictionary结构大都是基于哈希表实现的。 从算法实现难度上来比较skiplist比平衡树要简单得多。
哈希表
字典实际上是哈希表哈希表的最大好处就是让我们可以用 O(1) 的时间复杂度来快速查找。当我们查询一个 key 时Redis 首先检查该 key 是否存在于过期字典中 ● 如果不在则正常读取键值 ● 如果存在则会获取该 key 的过期时间然后与当前系统时间进行比对如果比系统时间大那就没有过期否则判定该 key 已过期。
过期删除策略有哪些
在说 Redis 过期删除策略之前先跟大家介绍下常见的三种过期删除策略
定时删除
定时删除策略的做法是在设置 key 的过期时间时同时创建一个定时事件当时间到达时由事件处理器自动执行 key 的删除操作。 定时删除策略的优点 ● 可以保证过期 key 会被尽快删除也就是内存可以被尽快地释放。因此定时删除对内存是最友好的。 定时删除策略的缺点 ● 在过期 key 比较多的情况下删除过期 key 可能会占用相当一部分 CPU 时间在内存不紧张但 CPU 时间紧张的情况下将 CPU 时间用于删除和当前任务无关的过期键上无疑会对服务器的响应时间和吞吐量造成影响。所以定时删除策略对 CPU 不友好。
惰性删除
惰性删除策略的做法是不主动删除过期键每次从数据库访问 key 时都检测 key 是否过期如果过期则删除该 key。 惰性删除策略的优点 ● 因为每次访问时才会检查 key 是否过期所以此策略只会使用很少的系统资源因此惰性删除策略对 CPU 时间最友好。 惰性删除策略的缺点 ● 如果一个 key 已经过期而这个 key 又仍然保留在数据库中那么只要这个过期 key 一直没有被访问它所占用的内存就不会释放造成了一定的内存空间浪费。所以惰性删除策略对内存不友好。
定期删除
定期删除策略的做法是每隔一段时间「随机」从数据库中取出一定数量的 key 进行检查并删除其中的过期key。 定期删除策略的优点 ● 通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响同时也能删除一部分过期的数据减少了过期键对空间的无效占用。 定期删除策略的缺点 ● 内存清理方面没有定时删除效果好同时没有惰性删除使用的系统资源少。 ● 难以确定删除操作执行的时长和频率。如果执行的太频繁定期删除策略变得和定时删除策略一样对CPU不友好如果执行的太少那又和惰性删除一样了过期 key 占用的内存不会及时得到释放。
Redis 过期删除策略是什么
前面介绍了三种过期删除策略每一种都有优缺点仅使用某一个策略都不能满足实际需求。 所以 Redis 选择「惰性删除定期删除」这两种策略配和使用以求在合理使用 CPU 时间和避免内存浪费之间取得平衡。
惰性删除
Redis 的惰性删除策略由 db.c 文件中的 expireIfNeeded 函数实现代码如下
int expireIfNeeded(redisDb *db, robj *key){// 判断 key 是否过期if(!keyIsExpired(db,key))return0;..../* 删除过期键 */....// 如果 server.lazyfree_lazy_expire 为 1 表示异步删除反之同步删除return server.lazyfree_lazy_expire ?dbAsyncDelete(db,key):dbSyncDelete(db,key);
}Redis 在访问或者修改 key 之前都会调用 expireIfNeeded 函数对其进行检查检查 key 是否过期 ● 如果过期则删除该 key至于选择异步删除还是选择同步删除根据 lazyfree_lazy_expire 参数配置决定Redis 4.0版本开始提供参数然后返回 null 客户端 ● 如果没有过期不做任何处理然后返回正常的键值对给客户端
定期删除
再回忆一下定期删除策略的做法每隔一段时间「随机」从数据库中取出一定数量的 key 进行检查并删除其中的过期key。
1、这个间隔检查的时间是多长呢 在 Redis 中默认每秒进行 10 次过期检查一次数据库此配置可通过 Redis 的配置文件 redis.conf 进行配置配置键为 hz 它的默认值是 hz 10。 特别强调下每次检查数据库并不是遍历过期字典中的所有 key而是从数据库中随机抽取一定数量的 key 进行过期检查。
2、随机抽查的数量是多少呢 我查了下源码定期删除的实现在 expire.c 文件下的 activeExpireCycle 函数中其中随机抽查的数量由 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 定义的它是写死在代码中的数值是 20。 也就是说数据库每轮抽查时会随机选择 20 个 key 判断是否过期。 接下来详细说说 Redis 的定期删除的流程
从过期字典中随机抽取 20 个 key检查这 20 个 key 是否过期并删除已过期的 key如果本轮检查的已过期 key 的数量超过 5 个20/4也就是「已过期 key 的数量」占比「随机抽取 key 的数量」大于 25%则继续重复步骤 1如果已过期的 key 比例小于 25%则停止继续删除过期 key然后等待下一轮再检查。 可以看到定期删除是一个循环的流程。 那 Redis 为了保证定期删除不会出现循环过度导致线程卡死现象为此增加了定期删除循环流程的时间上限默认不会超过 25ms。
内存淘汰策略
前面说的过期删除策略是删除已过期的 key而当 Redis 的运行内存已经超过 Redis 设置的最大内存之后则会使用内存淘汰策略删除符合条件的 key以此来保障 Redis 高效的运行。
如何设置 Redis 最大运行内存
在配置文件 redis.conf 中可以通过参数 maxmemory 来设定最大运行内存只有在 Redis 的运行内存达到了我们设置的最大运行内存才会触发内存淘汰策略。 不同位数的操作系统maxmemory 的默认值是不同的 ● 在 64 位操作系统中maxmemory 的默认值是 0表示没有内存大小限制那么不管用户存放多少数据到 Redis 中Redis 也不会对可用内存进行检查直到 Redis 实例因内存不足而崩溃也无作为。 ● 在 32 位操作系统中maxmemory 的默认值是 3G因为 32 位的机器最大只支持 4GB 的内存而系统本身就需要一定的内存资源来支持运行所以 32 位操作系统限制最大 3 GB 的可用内存是非常合理的这样可以避免因为内存不足而导致 Redis 实例崩溃。
Redis 内存淘汰策略有哪些
Redis 内存淘汰策略共有八种这八种策略大体分为「不进行数据淘汰」和「进行数据淘汰」两类策略。
1、不进行数据淘汰的策略 noevictionRedis3.0之后默认的内存淘汰策略 它表示当运行内存超过最大设置内存时不淘汰任何数据这时如果有新的数据写入则会触发 OOM但是如果没用数据写入的话只是单纯的查询或者删除操作的话还是可以正常工作。
2、进行数据淘汰的策略 针对「进行数据淘汰」这一类策略又可以细分为「在设置了过期时间的数据中进行淘汰」和「在所有数据范围内进行淘汰」这两类策略。 在设置了过期时间的数据中进行淘汰 ● volatile-random随机淘汰设置了过期时间的任意键值 ● volatile-ttl优先淘汰更早过期的键值。 ● volatile-lruRedis3.0 之前默认的内存淘汰策略淘汰所有设置了过期时间的键值中最久未使用的键值 ● volatile-lfuRedis 4.0 后新增的内存淘汰策略淘汰所有设置了过期时间的键值中最少使用的键值 在所有数据范围内进行淘汰 ● allkeys-random随机淘汰任意键值; ● allkeys-lru淘汰整个键值中最久未使用的键值 ● allkeys-lfuRedis 4.0 后新增的内存淘汰策略淘汰整个键值中最少使用的键值。
如何查看当前 Redis 使用的内存淘汰策略
可以使用 config get maxmemory-policy 命令来查看当前 Redis 的内存淘汰策略命令如下
127.0.0.1:6379 config get maxmemory-policy
1)maxmemory-policy
2)noeviction可以看出当前 Redis 使用的是 noeviction 类型的内存淘汰策略它是 Redis 3.0 之后默认使用的内存淘汰策略表示当运行内存超过最大设置内存时不淘汰任何数据但新增操作会报错。
如何修改Redis 内存淘汰策略
设置内存淘汰策略有两种方法 ● 方式一通过“config set maxmemory-policy 策略”命令设置。它的优点是设置之后立即生效不需要重启 Redis 服务缺点是重启 Redis 之后设置就会失效。 ● 方式二通过修改 Redis 配置文件修改设置“maxmemory-policy 策略”它的优点是重启 Redis 服务后配置不会丢失缺点是必须重启 Redis 服务设置才能生效。