1、redis的数据类型有哪些
2、redis为什么快
3、缓存击穿、缓存穿透、缓存雪崩
4、redis事务了解吗
5、数据的一致性怎么保证
6、redis的过期策略有哪些
7、内存淘汰策略有哪些
8、持久化的方式
9、怎么实现redis的高可用
1、redis的数据类型有哪些
- string
- List
- set
- hash
- zset
- geodist(经纬度)
2、redis为什么快
- 完全基于内存操作
- C语⾔实现,优化过的数据结构,基于⼏种基础的数据结构,redis做了⼤量的优化,性能极⾼
- 使⽤单线程,⽆上下⽂的切换成本。redis6.0之后启用了多线程,仅限于网络请求方面。命令执行依旧是单线程的。
- 基于⾮阻塞的IO多路复⽤机制
3、缓存击穿、缓存穿透、缓存雪崩
缓存穿透
对于系统A,假设一秒5000个请求,结果其中4000个请求是黑客发出的恶意攻击。
黑客发出的那4000个攻击,在缓存中查不到,每次去数据库查也查不到。举例:数据库id是从1开始的,结果黑客发的请求id全是负数。
解决:1、如果黑客每次id都一样,那么写个空值到缓存中,set -1 unknown
2、如果黑客每次id都不一样,写空值就不奏效了,在缓存之前添加布隆过滤器。
缓存雪崩
1、对于系统A,假设每天高峰期每秒5000个请求,本来缓存在高峰期可以抗住每秒4000个请求,但是缓存机器意外发生了全盘宕机。缓存挂了,此时1秒5000个请求全部落数据库导致数据库cpu升高或者宕机。
解决:
事前:redis高可用,主从+哨兵,redis cluster,避免全面崩盘
事中:本地ehcache缓存+hystrix限流&降级,避免MYSQL被打死。
事后:redis持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。
2、大量热点数据同时过期,导致大量请求需查询数据库并写到缓存。
解决:过期时间添加随机值,避免同一时间发生。
缓存击穿
某个热点key,处于集中式高并发访问时,当这个key突然失效,大量请求就击穿了缓存,直接请求数据库。
解决:
1、若缓存的数据是基本不会发生更新的,则尝试将该热点数据设置为永不过期。
2、数据更新不频繁,采用基于redis的互斥锁,只有少量请求能连接数据库,并更新构建缓存,其余线程则在锁释放之后访问缓存。
if(redis(LockName)) {
从数据库中取出数据并写入redis
} else {
Thread.sleep(200)
}
3、更新频繁的数据,利用定时任务在过期时间前主动重新构建缓存。
4、redis事务了解吗
redis事务,分为三个阶段:开启,入队和执行。以multi开启一个事务,然后将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列中,最后由exec命令触发。
redis不支持回滚。回滚不能解决变成错误带来的。
原子性:redis事务是原子性的:所有命令,要么全部执行,要么全部不执行。
一致性:可以保证命令失败的情况下得以回滚,数据能恢复到没有执行前的样子。
隔离性:保证,单进程单线程模式。
持久性:不支持持久型,因为redis持久化不管是rdb还是aof都是异步执行的。
5、数据的一致性如何保证
数据的一致性保证
- 简单:删除数据,更新数据库,查询时插入缓存
- 复杂:如果每天是上亿流量,每秒的并发读是几万,先删除缓存,去修改数据库,此时还没修改完,一个请求过来,去读数据库,发现缓存空了,去查数据库,查到了修改前的旧数据,放到了缓存中,数据库和缓存中数据就又不一样了。
- 解决:更新数据的时候,根据数据的唯一标识,发送到一个队列中,读数据的时候,如数据不在缓存中,那么讲重新执行“读数+更新缓存”的操作,根据唯一标识路由之后,也发送到一个队列中,一个队列对应一个工作线程,每个工作线程串行拿到对应的操作,然后一条条的去执行。
6、redis的过期策略有哪些
定期删除和惰性删除
惰性删除指的是当我们查询key的时候才对key进⾏检测,如果已经达到过期时间,则删除。显然,他有⼀个缺点就是如果这些过期的key没有被访问,那么他就⼀直⽆法被删除,⽽且⼀直占⽤内存。
定期删除指的是redis每隔⼀段时间对数据库做⼀次检查,删除⾥⾯的过期key。由于不可能对所有key去做轮询来删除,所以redis会每次随机取⼀些key去做检查和删除
7、内存淘汰策略有哪些
内存淘汰策略
- noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
- allkeys-lru:当内存不足以容纳新写入的数据时,在键空间中,移除最近最少使用的key(最常用)
- 当内存不足以容纳新写入数据时,在键空间中,随机移除某个key
- volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key
- volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
- volatile-ttl:当内存不足以容纳新写入的数据时,在设置了过期时间的键空间中,有更早过期时间的key先移除。
8、持久化的方式
rdb、aof
rdb优点:rdb文件是某个时间节点的快照,压缩后的文件体积远远小于内存大小。所以rdb文件恢复数据要快于aof
缺点:rdb实时性不够,无法做到秒级持久化。每次都需要fork子进程,频繁操作成本较高。默认5分钟生成一次
aof
将命令作为日志文件记录。
9、怎么实现redis的高可用
主从模式是最简单的实现⾼可⽤的⽅案,核⼼就是主从同步。主从同步的原理如下:
- slave发送sync命令到master
- master收到sync之后,执⾏bgsave,⽣成RDB全量⽂件
- master把slave的写命令记录到缓存
- bgsave执⾏完毕之后,发送RDB⽂件到slave,slave执⾏
- master发送缓存中的写命令到slave,slave执⾏
哨兵
- 初始化sentinel,将普通的redis代码替换成sentinel专⽤代码
- 初始化masters字典和服务器信息,服务器信息主要保存ip:port,并记录实例的地址和ID
- 创建和master的两个连接,命令连接和订阅连接,并且订阅sentinel:hello频道
- 每隔10秒向master发送info命令,获取master和它下⾯所有slave的当前信息
- 当发现master有新的slave之后,sentinel和新的slave同样建⽴两个连接,同时每个10秒发送info
命令,更新master信息 - sentinel每隔1秒向所有服务器发送ping命令,如果某台服务器在配置的响应时间内连续返回⽆效回
复,将会被标记为下线状态 - 选举出领头sentinel,领头sentinel需要半数以上的sentinel同意
- 领头sentinel从已下线的的master所有slave中挑选⼀个,将其转换为master
- 让所有的slave改为从新的master复制数据
- 将原来的master设置为新的master的从服务器,当原来master重新回复连接时,就变成了新
master的从服务器
sentinel会每隔1秒向所有实例(包括主从服务器和其他sentinel)发送ping命令,并且根据回复判断是
否已经下线,这种⽅式叫做主观下线。当判断为主观下线时,就会向其他监视的sentinel询问,如果超过
半数的投票认为已经是下线状态,则会标记为客观下线状态,同时触发故障转移。