Redis
-
什么是Redis?
Redis(Remote Dictionary Server)是一个开源的高性能键值存储内存数据库,以高性能、灵活的数据结构和丰富的功能著称。
-
数据结构
字符串(string):可以存储图片或者序列化的对象,值最大存储为512M。应用场景:共享session、分布式锁,计数器、限流。
字典(map):缓存用户信息
集合(set):用户标签
有序集合(Sorted Set):排行榜
列表(list):消息队列,文章列表
高级数据结构:位图,地理空间索引,流
-
redis为什么快
![img]()
- Mysql索引为了提高效率,选择了B+树的数据结构。其实合理的数据结构,就是可以让你的应用/程序更快。
- Redis是单线程模型的,而单线程避免了CPU不必要的上下文切换和竞争锁的消耗。多路I/O复用技术可以让单个线程高效的处理多个连接请求。
- 虚拟内存机制就是暂时把不经常访问的数据(冷数据)从内存交换到磁盘中,从而腾出宝贵的内存空间用于其它需要访问的数据(热数据)。通过VM功能可以实现冷热数据分离,使热数据仍在内存中、冷数据保存到磁盘。这样就可以避免因为内存不足而造成访问速度下降的问题。
-
缓存击穿、缓存穿透、缓存雪崩
-
缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。
产生情况:
- 新的缓存模式没有考虑系统发布或重启后,缓存完全为空时,突发大量请求。
- 业务/运维/开发失误的操作,比如缓存和数据库的数据都被误删除了。
- 黑客非法请求攻击,比如黑客故意捏造大量非法请求,以读取不存在的业务数据。
解决方案:
- 1.如果是非法请求,我们在API入口,对参数进行校验,过滤非法值。
- 2.如果查询数据库为空,我们可以给缓存设置个空值,或者默认值。但是如有有写请求进来的话,需要更新缓存哈,以保证缓存一致性,同时,最后给缓存设置适当的过期时间。(业务上比较常用,简单有效)
- 3.使用布隆过滤器快速判断数据是否存在。即一个查询请求过来时,先通过布隆过滤器判断值是否存在,存在才继续往下查。
-
缓存雪崩: 指缓存中数据大批量到过期时间,而查询数据量巨大,请求都直接访问数据库,引起数据库压力过大甚至down机。
- 缓存雪奔一般是由于大量数据同时过期造成的,对于这个原因,可通过均匀设置过期时间解决,即让过期时间相对离散一点。如采用一个较大固定值+一个较小的随机值,5小时+0到1800秒酱紫。
- Redis 故障宕机也可能引起缓存雪奔。这就需要构造Redis高可用集群啦。
-
缓存击穿: 指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到db。
-
1.使用互斥锁方案。缓存失效时,不是立即去加载db数据,而是先使用某些带成功返回的原子操作命令,如(Redis的setnx)去操作,成功的时候,再去加载db数据库数据和设置缓存。否则就去重试获取缓存。
只允许一个请求线程去重建缓存,其他线程等待,缓存重建完成后,所有线程直接从新缓存中获取数据。
-
2. “永不过期”,是指没有设置过期时间,但是热点数据快要过期时,异步线程去更新和设置过期时间。
-
缓存雪崩是指数据库压力过大甚至down机,缓存击穿只是大量并发请求到了DB数据库层面。可以认为击穿是缓存雪崩的一个子集吧。
-
-
热点key
如果某一热点key的请求到服务器主机时,由于请求量特别大,可能会导致主机资源不足,甚至宕机,从而影响正常的服务。
如何解决热key问题?(写热点,读热点)
方案 核心思想 优点 缺点 适用场景 本地缓存(读热点) 将压力从 Redis 转移到应用内存 性能极致,彻底解决 数据一致性难保证 读多写少的热点数据(首选) Key 分片(写热点) 将一个热点分散成多个(减少CPU等待时间) 分散压力,提高吞吐 业务逻辑复杂 可拆分的计数器类数据(库存扣减、点赞计数) 逻辑过期 避免缓存集中失效 平滑更新,用户体验好 短期数据不一致 极高并发的写更新 限流降级 拒绝多余请求,保护系统 保证系统不崩溃 牺牲部分用户体验 突发流量,最后的防线 分片对于必须原子更新的写操作,可能不适用。
-
Redis的过期策略
我们在
setkey的时候,指定这key60s后过期,60s后,redis是如何处理的?定时过期
每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即对key进行清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
惰性过期
只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
定期过期
每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。Redis中同时使用了惰性过期和定期过期两种过期策略。
- redis采取的是定期过期,每隔100ms就随机抽取一定数量的key来检查和删除的。
- 但是呢,最后可能会有很多已经过期的key没被删除。这时候,redis采用惰性删除。在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间并且已经过期了,此时就会删除。
但是,如果定期删除漏掉了很多过期的key,然后也没走惰性删除。就会有很多过期key积在内存,直接会导致内存爆的。或者有些时候,业务量大起来了,redis的key被大量使用,内存直接不够了。Redis有8种内存淘汰策略
Redis 内存淘汰策略
- volatile-lru:当内存不足以容纳新写入数据时,从设置了过期时间的key中使用LRU(最近最少使用)算法进行淘汰;
- allkeys-lru:当内存不足以容纳新写入数据时,从所有key中使用LRU(最近最少使用)算法进行淘汰。
- volatile-lfu:4.0版本新增,当内存不足以容纳新写入数据时,在过期的key中,使用LFU算法进行删除key。
- allkeys-lfu:4.0版本新增,当内存不足以容纳新写入数据时,从所有key中使用LFU算法进行淘汰;
- volatile-random:当内存不足以容纳新写入数据时,从设置了过期时间的key中,随机淘汰数据;。
- allkeys-random:当内存不足以容纳新写入数据时,从所有key中随机淘汰数据。
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的key中,根据过期时间进行淘汰,越早过期的优先被淘汰;
- noeviction:默认策略,当内存不足以容纳新写入数据时,新写入操作会报错。
-
持久化机制
为了保证内存中的数据在断电或故障时不会丢失,Redis提供了两种主要的持久化机制:RDB(Redis Database)和AOF(Append Only File)。
- RDB:是指在指定的时间间隔内,执行指定次数的写操作,将内存中的数据集快照写入磁盘中,它是Redis默认的持久化方式。它适合于数据备份和灾难恢复,但在发生故障后,自上次快照以来的所有数据都有可能丢失。
- AOF:记录每一个写操作命令到一个日志文件中,命令以追加的方式保存。它主要解决数据持久化的实时性问题。默认是不开启的。它可以配置为每次写操作后同步到磁盘,或者每秒同步一次。在Redis重启时,AOF文件中的命令会被重新执行,以重建内存中的数据状态。通过AOF恢复数据通常比RDB更慢,但可以更频繁地记录数据状态,减少数据丢失的可能性。
-
redis的高可用
Redis 实现高可用有三种部署模式:主从模式,哨兵模式,集群模式。
-
主从模式:Redis部署了多台机器,有主节点,负责读写操作,有从节点,只负责读操作。从节点的数据来自主节点,实现原理就是主从复制机制。从服务器发送同步请求,主节点生成RDB并缓存生成RDB期间的写命令,主节点向全部从节点发送RDB,并缓存此期间的写命令。主节点向从节点同步全部写命令。
-
哨兵模式:
- 发送命令,等待Redis服务器(包括主服务器和从服务器)返回监控其运行状态;
- 哨兵监测到主节点宕机,会自动将从节点切换成主节点,然后通过发布订阅模式通知其他的从节点,修改配置文件,让它们切换主机;
- 哨兵之间还会相互监控,从而达到高可用。
-
Cluster集群模式:对数据进行分片,每台Redis节点上存储不同的内容,来解决在线扩容的问题。并且,它也提供复制和故障转移的功能。
-
降低单节点内存需求:通过分片避免单节点存储全量数据。
-
提高资源利用率:从节点仅保护对应分片,而非全量数据。
-
支持弹性扩展:新增节点只需承担部分数据,避免内存爆炸。
本质:Cluster 将“全量冗余”改为“分片级冗余”,用更细粒度的资源分配换取横向扩展能力。
-
-
-
redis分布式锁
分布式锁,是控制分布式系统不同进程共同访问共享资源的一种锁的实现。
优势:高性能(Redis 操作纯内存,命令天生原子性),高可用(Redis 集群(哨兵或 Cluster)支持主节点宕机时自动切换,锁状态不会丢失), 灵活的过期机制(防死锁)
-
MySQL与Redis 如何保证双写一致性
-
缓存延时双删
- 写请求
- 先删除缓存
- 再更新数据库
- 休眠一会(比如1秒),再次删除缓存。
-
删除缓存重试机制
延时双删可能会存在第二步的删除缓存失败,导致的数据不一致问题
- 写请求更新数据库
- 缓存因为某些原因,删除失败
- 把删除失败的key放到消息队列
- 消费消息队列的消息,获取要删除的key
- 重试删除缓存操作
-
读取binlog异步删除缓存
重试删除缓存机制会造成好多业务代码入侵
"业务代码入侵"指为实现非业务功能需求(如缓存一致性),需要在业务逻辑中插入大量与核心业务无关的代码。
![img]()



浙公网安备 33010602011771号