【Redis】面试知识点一点就会!
redis的数据类型
redis有五种基本数据类型,三种特殊数据类型
1、string 字符串类型,常见的key-value格式
2、hash 散列表,hash可以说是key-value格式的集合,一般用来表示对象,用户信息等等。
3、list 链表,list是一个简单的字符串链表,他是有序的可以在头尾插入数据,Lpush向头插入数据,Rpush向尾插入数据。
4、set 集合,set是无序且不重复的集合。
5、zset 有序集合
redis在3.2之后加入了三种特殊数据类型
1、geo 地理位置,一般实现定位,计算两者之间的距离都使用geo
2、Hyperloglog 基数统计,所谓基数就是一个可重复集合内不重复元素的个数
3、Bitmap 位图场景,只有0和1两个状态,可以用来判断是否登录,是否打卡,是否活跃等只有两个状态的情况
redis的使用场景
1、点赞,播放量、粉丝数等,使用string,每次+1;
2、使用hash存储部分变更数据,例如用户信息
3、利用set的不可重复,储存关注的人、粉丝等
4、利用list的有序性,当作消息队列使用,
5、zset可以进行排序,所以储存成绩表,业绩表等可以排序的信息。
6、geo是可以计算两点之间的距离,可以完成搜索附近商家、打车等功能
7、hyperloglog可以用来当作页面统计,统计有多少人访问,访问者都有谁等等
8、判断是否登录,是否打卡,是否活跃等只有两个状态的情况
9、缓存
10、 共享Session:如果一个分布式Web服务将用户的Session信息保存在各自服务器,用户刷新一次可能就需要重新登录了,这样显然有问题。实际上,可以使用Redis将用户的Session进行集中管理,每次用户更新或者查询登录信息都直接从Redis中集中获取。
11、分布式锁
关于redis的缓存穿透、缓存击穿、缓存雪崩
以上情况都是在使用redis作为缓存的情况下发生的,所谓redis作为缓存就是当请求查询数据时,先去redis中查询是否有结果,如果没有则去数据库中查询,将查到的结果保存到redis中并返回给请求方,这样当下次再有相同请求的时候就只需要在redis中获取即可。大大提升访问速度,并且减少了DB的访问压力。
1、缓存穿透
如果用户恶意重复请求资源 X,该资源在 Redis 和 DB 中都不存在。那么每次请求都会直接打到 DB 上,甚至导致物理 DB 宕机。
解决办法:
1)缓存空结果
如果redis以及数据库都没有该资源,可以在reids中缓存一个过期时间较短的空结果。
2)请求的合法性校验
判断请求是否合法,拦截恶意请求,例如请求id为-1的数据肯定是不存在的。
3)布隆过滤器
使用布隆过滤器判断结果是否存在,当然布隆过滤器并不是一定完全判断正确,但可以拦截掉大部分的空请求
2、缓存击穿
当一个访问量巨大的key到期失效,同时又有大量请求来到,这些请求就会全部打在db上,导致数据库宕机。
例如关于吴某凡的信息设置的是0点过期,但他突然出事,大量网友吃瓜,请求直接打在了微博的DB上导致宕机。
解决方法:
1)设置热点key永不过期。
2)使用互斥锁
当第一个请求发现某个key值没有结果的时候,给该key值上锁,然后去数据库查询结果并保存到redis中,再释放锁。这样在其他请求到来的时候发现key值上锁了,就只能等待锁释放,不会再去访问数据库。但缺点是影响吞吐量。
3、缓存雪崩
当缓存中的大量key同时过期,请求就会直接打在数据库上,因此就会引发数据库宕机。
解决方法:
1)失效时间增加随机值
在设置失效时间时增加随机值,让失效时间均匀分布。
2)设置永不过期
Redis 过期策略和内存淘汰策略
Redis的过期策略
我们在set key的时候,可以给它设置一个过期时间,比如expire key 60。指定这key60s后过期,60s后,redis是如何处理的嘛?我们先来介绍几种过期策略:
定时过期
每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即对key进行清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
惰性过期
只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
定期过期
每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。
Redis中同时使用了惰性过期和定期过期两种过期策略。
假设Redis当前存放30万个key,并且都设置了过期时间,如果你每隔100ms就去检查这全部的key,CPU负载会特别高,最后可能会挂掉。
因此,redis采取的是定期过期,每隔100ms就随机抽取一定数量的key来检查和删除的。
但是呢,最后可能会有很多已经过期的key没被删除。这时候,redis采用惰性删除。在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间并且已经过期了,此时就会删除。
但是呀,如果定期删除漏掉了很多过期的key,然后也没走惰性删除。就会有很多过期key积在内存内存,直接会导致内存爆的。或者有些时候,业务量大起来了,redis的key被大量使用,内存直接不够了,运维小哥哥也忘记加大内存了。难道redis直接这样挂掉?不会的!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数据库的持久化
redis是基于内存的k-v格式的非关系数据库,因为是基于内存的所以一旦机器重启,数据就会丢失,所以需要持久化到硬盘中。
redis的持久化机制分为RDB和AOF,持久化加载流程如下:
1、RDB
快照模式,每次持久化时生成一次当前数据的快照,下次启动时加载该快照。RDB也是redis默认的持久化方式。
RDB 的优点
- 适合大规模的数据恢复场景,如备份,全量复制等
RDB缺点
- 没办法做到实时持久化/秒级持久化。
- 新老版本存在RDB格式兼容问题
2、AOF
AOF(append only file) 持久化,采用日志的形式来记录每个写操作,追加到文件中,重启时再重新执行AOF文件中的命令来恢复数据。它主要解决数据持久化的实时性问题。默认是不开启的。
AOF的工作流程如下:
AOF的优点
数据的一致性和完整性更高
AOF的缺点
AOF记录的内容越多,文件越大,数据恢复变慢。
