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

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
云数据库 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
相关文章
|
20天前
|
NoSQL Redis
05- Redis的数据淘汰策略有哪些 ?
Redis 提供了 8 种数据淘汰策略:挥发性 LRU、LFU 和 TTL(针对有过期时间的数据),挥发性随机淘汰,以及全库的 LRU、LFU 随机淘汰,用于在内存不足时选择删除。另外,还有不淘汰策略(no-eviction),允许新写入操作报错而非删除数据。
303 1
|
2月前
|
缓存 监控 NoSQL
【Redis性能瓶颈揭秘】「调优系列」深入分析热Key的排查策略和解决方案
【Redis性能瓶颈揭秘】「调优系列」深入分析热Key的排查策略和解决方案
215285 8
|
2月前
|
缓存 监控 NoSQL
解析Redis缓存雪崩及应对策略
解析Redis缓存雪崩及应对策略
|
4月前
|
NoSQL 算法 Redis
Redis进阶-Redis对于过期键的三种清除策略
Redis进阶-Redis对于过期键的三种清除策略
52 0
|
5天前
|
缓存 NoSQL 数据库
探秘Redis读写策略:CacheAside、读写穿透、异步写入
本文介绍了 Redis 的三种高可用性读写模式:CacheAside、Read/Write Through 和 Write Behind Caching。CacheAside 简单易用,但可能引发数据不一致;Read/Write Through 保证数据一致性,但性能可能受限于数据库;Write Behind Caching 提高写入性能,但有数据丢失风险。开发者应根据业务需求选择合适模式。
34 2
探秘Redis读写策略:CacheAside、读写穿透、异步写入
|
14天前
|
缓存 NoSQL Java
使用Redis进行Java缓存策略设计
【4月更文挑战第16天】在高并发Java应用中,Redis作为缓存中间件提升性能。本文探讨如何使用Redis设计缓存策略。Redis是开源内存数据结构存储系统,支持多种数据结构。Java中常用Redis客户端有Jedis和Lettuce。缓存设计遵循一致性、失效、雪崩、穿透和预热原则。常见缓存模式包括Cache-Aside、Read-Through、Write-Through和Write-Behind。示例展示了使用Jedis实现Cache-Aside模式。优化策略包括分布式锁、缓存预热、随机过期时间、限流和降级,以应对缓存挑战。
|
21天前
|
NoSQL 安全 Redis
redis内存限制与淘汰策略
Redis内存管理包括限制和淘汰策略。`maxmemory`配置参数决定内存上限,无设置时64位系统默认不限制,可能导致系统资源耗尽,生产环境建议设定合理值。当内存满时,未设置淘汰策略会导致写入错误。Redis提供8种淘汰策略,如LRU(最近最少使用)和LFU(最不经常使用),以及随机或基于过期时间的删除。需根据数据重要性、访问频率和一致性选择合适策略。
282 0
|
28天前
|
存储 缓存 NoSQL
Redis的内存淘汰策略是什么?
【4月更文挑战第2天】Redis内存淘汰策略在内存满时,通过删除旧数据为新数据腾空间。策略包括:volatile-lru/LFU(基于LRU/LFU算法淘汰有过期时间的键),volatile-random/ttl(随机/按TTL淘汰),allkeys-lru/LFU(所有键的LRU/LFU),allkeys-random(随机淘汰所有键),以及noeviction(不淘汰,返回错误)。选择策略要考虑访问模式、数据重要性和性能需求。
|
3月前
|
存储 NoSQL Redis
Redis淘汰策略、持久化、主从同步与对象模型
Redis淘汰策略、持久化、主从同步与对象模型
90 0
|
4月前
|
存储 缓存 NoSQL
Redis如何实现LRU(Least Recently Used)淘汰策略?
Redis如何实现LRU(Least Recently Used)淘汰策略?
45 0