【Redis核心知识 五】Redis的删除策略

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
云数据库 Tair(兼容Redis),内存型 2GB
简介: 【Redis核心知识 五】Redis的删除策略

其实同ElasticSearch的延迟删除【在段合并的时候才真正删除数据】【ElasticSearch从入门到放弃系列 九】Elasticsearch原理机制探索一样,Redis也不是马上删除数据,而是先进行标记,让其在内存中再多呆一会儿,等到满足一定条件的时候再进行统一删除。

什么是过期数据

当我们执行del删除redis数据以及expire过期的 ,过期数据:Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态:

127.0.0.1:6379> clear
127.0.0.1:6379> set name tml
OK
127.0.0.1:6379> set age 23 ex 30
OK
127.0.0.1:6379> set color red
OK
127.0.0.1:6379> del color
(integer) 1
127.0.0.1:6379> ttl name             -1:永久有效的数据 
(integer) -1
127.0.0.1:6379> ttl age              XX:具有时效性的数据,返回剩余时间
(integer) 5
127.0.0.1:6379> ttl color            -2:已经过期的数据、被删除的数据、未定义的数据
(integer) -2
127.0.0.1:6379> 
127.0.0.1:6379> ttl age
(integer) -2
127.0.0.1:6379> set second
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> ttl second
(integer) -2
127.0.0.1:6379>

所以过期数据就是ttl返回为-2的三种状态的数据,要删除的数据。为了防止CPU压力过大,采取不同的删除策略。

过期数据的删除策略

和ElasticSearch的定期段合并策略相同,Redis处理过期数据也有一套。时效性数据的内存结构如下,有个espires的hash结构来存储数据的内存地址和时间,到时删除

删除策略的目标是在内存占用和CPU性能之间寻找一种平衡,既不能让过期数据过多,又不能让CPU太忙。目前有三种处理策略:

定时删除

创建一个定时器,当key设置有过期时间,且过期时间到达时,由定时器任务立即执行对键的删除操作。

  • 优点:节约内存,到时就删除,快速释放掉不必要的内存占用
  • 缺点:CPU压力很大,无论CPU此时负载量多高,均占用CPU,会影响redis服务器响应时间和指令吞吐量

总而言之一句话:牺牲时间换取空间

惰性删除

定期删除可能会导致很多过期key到了时间并没有被删除掉。所以就有了惰性删除。过期key,依然停留在内存里,除非访问一下过期key,才会被redis给删除掉。这就是所谓的惰性删除。expireIfNeeded(),检查数据是否过期,执行get的时候调用

  • 优点:节约CPU性能,发现必须删除的时候才删除
  • 缺点:内存压力很大,出现长期占用内存的数据

总而言之一句话:牺牲空间换时间

定期删除

当然同AOF的几种策略相比,删除策略也不会走极端,于是就有了定期删除的策略:

这几个参数在配置中可以指定:

hz 10

周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度.

  • 优点: CPU性能占用设置有峰值,检测频度可自定义设置,内存压力不是很大,长期占用内存的冷数据会被持续清理

总而言之一句话:空间和时间具有平衡性

删除策略对比

三种删除策略及对比如下:

删除策略 特点 执行特点 总结
定时删除 节约内存,消耗CPU 不分时段执行,内存占用低,CPU损耗高 牺牲时间换空间
惰性删除 内存占用验证,CPU消耗低 延迟执行,内存占用高,CPU损耗低 牺牲空间换时间
定期删除 内存定期随机清理 每秒花费固定CPU资源维护内存,处理时间久的冷数据 定时抽查,重点抽查

一般会组合惰性删除定期删除进行使用。

Redis的逐出算法

当新数据进入redis时,如果内存不足怎么办?Redis使用内存存储数据,在执行每一个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。如果内存不满足新加入数据的最低存储要求,redis要临时删除一些数据为当前指令清理存储空间。清理数据的策略称为逐出算法

逐出算法

首先需要注意几个参数,这几个参数决定了逐出算法的后续逻辑。

  • 最大可使用内存maxmemory:占用物理内存的比例,默认值为0,表示不限制。通常设置在50%以上
  • 每次选取待删除数据的个数maxmemory-samples: 选取数据时并不会全库扫描,导致严重的性能损耗,降低读写性能。因此采用随机获取数据的方式作为待检测删除数据
  • 删除策略maxmemory-policy :达到最大内存后,对被选出来的数据进行删除的策略

逐出算法有三大类:

检测易失性数据(可能会过期的数据集server.db[i].expires)

检测易失数据有四种算法:

  • volatile-lru --> 从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
  • volatile-lfu–>从已设置过期时间的数据集中挑选最不经常使用的数据淘汰
  • volatile-ttl–>从已设置过期时间的数据集中挑选将要过期的数据淘汰
  • volatile-random -->从已设置过期时间的数据集中任意选择数据淘汰

检测全库数据(所有数据集server.db[i].dict)

检测易失数据有三种算法:

  • allkeys-lru --> 当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(最常用)
  • allkeys-random–>从数据集中任意选择数据淘汰
  • allkeys-lfu–>当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的key

因为不需要关心数据是否过期,所以没有volatile-ttl

放弃数据驱逐

no-eviction–>禁止驱逐数据(redis4.0默认策略),也就是说当内存不足以容纳新写入数据时,新写入操作或报错,回引发OOM(Out of memory)

综合以上,我们推荐使用的策略是:maxmemory-policy volatile-lru

无法逐出的情况

逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所有数据尝试完毕后,如果不能达到内存清理的要求【均无过期数据,且占用内存已满】,将出现错误信息。

(err)OOM command not allowed when used memory > 'maxmemory'

以上所有的信息均可以通过info来进行查看:

127.0.0.1:6379> info
# Server
redis_version:6.0.8
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:4c35dfe260ddf15c
redis_mode:standalone
os:Linux 3.10.0-1127.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:9.3.1
process_id:44507
run_id:14ab8c5119da4c338a94724975bb50054d3e9ce0
tcp_port:6379
uptime_in_seconds:70012
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:9778284
executable:/root/redis-6.0.8/redis-server
config_file:/root/redis-6.0.8/config/redis-6379.conf
io_threads_active:0
# Clients
connected_clients:2
client_recent_max_input_buffer:2
client_recent_max_output_buffer:0
blocked_clients:0
tracking_clients:0
clients_in_timeout_table:0
# Memory
used_memory:946288
used_memory_human:924.11K
used_memory_rss:2076672
used_memory_rss_human:1.98M
used_memory_peak:946288
used_memory_peak_human:924.11K
used_memory_peak_perc:100.14%
used_memory_overhead:910474
used_memory_startup:876184
used_memory_dataset:35814
used_memory_dataset_perc:51.09%
allocator_allocated:912048
allocator_active:2038784
allocator_resident:2038784
total_system_memory:1019609088
total_system_memory_human:972.38M
used_memory_lua:37888
used_memory_lua_human:37.00K
used_memory_scripts:0
used_memory_scripts_human:0B
number_of_cached_scripts:0
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:2.24
allocator_frag_bytes:1126736
allocator_rss_ratio:1.00
allocator_rss_bytes:0
rss_overhead_ratio:1.02
rss_overhead_bytes:37888
mem_fragmentation_ratio:2.28
mem_fragmentation_bytes:1164624
mem_not_counted_for_evict:174
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:33972
mem_aof_buffer:174
mem_allocator:libc
active_defrag_running:0
lazyfree_pending_objects:0
# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1603597171
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:98304
aof_enabled:1
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:139264
module_fork_in_progress:0
module_fork_last_cow_size:0
aof_current_size:1339
aof_base_size:105
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:0
# Stats
total_connections_received:7
total_commands_processed:97
instantaneous_ops_per_sec:0
total_net_input_bytes:2632
total_net_output_bytes:131444
instantaneous_input_kbps:0.01
instantaneous_output_kbps:11.36
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:2
expired_stale_perc:0.00
expired_time_cap_reached_count:0
expire_cycle_cpu_milliseconds:334
evicted_keys:0
keyspace_hits:12
keyspace_misses:6
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:165
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
tracking_total_keys:0
tracking_total_items:0
tracking_total_prefixes:0
unexpected_error_replies:0
total_reads_processed:117
total_writes_processed:111
io_threaded_reads_processed:0
io_threaded_writes_processed:0
# Replication
role:master
connected_slaves:0
master_replid:d71bf05a8550a15cb81e049e7baef5451dc8fd3f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# CPU
used_cpu_sys:17.306819
used_cpu_user:10.844898
used_cpu_sys_children:0.014531
used_cpu_user_children:0.014085
# Modules
# Cluster
cluster_enabled:0
# Keyspace
db0:keys=2,expires=0,avg_ttl=0


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
10天前
|
存储 缓存 监控
利用 Redis 缓存特性避免缓存穿透的策略与方法
【10月更文挑战第23天】通过以上对利用 Redis 缓存特性避免缓存穿透的详细阐述,我们对这一策略有了更深入的理解。在实际应用中,我们需要根据具体情况灵活运用这些方法,并结合其他技术手段,共同保障系统的稳定和高效运行。同时,要不断关注 Redis 缓存特性的发展和变化,及时调整策略,以应对不断出现的新挑战。
40 10
|
10天前
|
缓存 监控 NoSQL
Redis 缓存穿透及其应对策略
【10月更文挑战第23天】通过以上对 Redis 缓存穿透的详细阐述,我们对这一问题有了更深入的理解。在实际应用中,我们需要根据具体情况综合运用多种方法来解决缓存穿透问题,以保障系统的稳定运行和高效性能。同时,要不断关注技术的发展和变化,及时调整策略,以应对不断出现的新挑战。
31 4
|
30天前
|
缓存 分布式计算 NoSQL
大数据-47 Redis 缓存过期 淘汰删除策略 LRU LFU 基础概念
大数据-47 Redis 缓存过期 淘汰删除策略 LRU LFU 基础概念
60 2
|
1月前
|
存储 缓存 NoSQL
【redis】数据量庞大时的应对策略
【redis】数据量庞大时的应对策略
35 2
|
1月前
|
NoSQL Redis
redis 的 key 过期策略是怎么实现的(经典面试题)超级通俗易懂的解释!
本文解释了Redis实现key过期策略的方式,包括定期删除和惰性删除两种机制,并提到了Redis的内存淘汰策略作为补充,以确保过期的key能够被及时删除。
48 1
|
6月前
|
存储 监控 NoSQL
Redis处理大量数据主要依赖于其内存存储结构、高效的数据结构和算法,以及一系列的优化策略
【5月更文挑战第15天】Redis处理大量数据依赖内存存储、高效数据结构和优化策略。选择合适的数据结构、利用批量操作减少网络开销、控制批量大小、使用Redis Cluster进行分布式存储、优化内存使用及监控调优是关键。通过这些方法,Redis能有效处理大量数据并保持高性能。
95 1
|
2月前
|
缓存 监控 NoSQL
阿里面试让聊一聊Redis 的内存淘汰(驱逐)策略
大家好,我是 V 哥。粉丝小 A 面试阿里时被问到 Redis 的内存淘汰策略问题,特此整理了一份详细笔记供参考。Redis 的内存淘汰策略决定了在内存达到上限时如何移除数据。希望这份笔记对你有所帮助!欢迎关注“威哥爱编程”,一起学习与成长。
|
2月前
|
存储 缓存 NoSQL
Redis 过期删除策略与内存淘汰策略的区别及常用命令解析
Redis 过期删除策略与内存淘汰策略的区别及常用命令解析
65 0
|
2月前
|
NoSQL Java API
Redis数据淘汰策略的详细介绍
通过上述步骤,我们不仅解决了一个实际问题,也进一步了解了Java 8时间API的强大功能和灵活性。希望这个解答能够帮助你在日常开发中更加自如地处理时间和时区相关的问题。
36 0
|
3月前
|
存储 缓存 NoSQL
Redis内存管理揭秘:掌握淘汰策略,让你的数据库在高并发下也能游刃有余,守护业务稳定运行!
【8月更文挑战第22天】Redis的内存淘汰策略管理内存使用,防止溢出。主要包括:noeviction(拒绝新写入)、LRU/LFU(淘汰最少使用/最不常用数据)、RANDOM(随机淘汰)及TTL(淘汰接近过期数据)。策略选择需依据应用场景、数据特性和性能需求。可通过Redis命令行工具或配置文件进行设置。
71 2