1. 为什么Redis很快
- 基于内存操作,速度比磁盘操作快得多
- 单线程,避免了多线程的线程安全操作,避免了上下文切换
- 缓存了时间戳,渐进式hash
2. Redis的使用场景
- string:缓存、分布式session、计数器
- hash:存储对象
- list:消息队列:通过lpush命令让生产者客户端从列表左边插入消息,而brpop命令让多个消费者客户端从队列为阻塞式抢占队列尾部的消息
- set:交集,共同好友筛选
- zset:排行榜
- bitmaps(位图):布隆过滤器:通过几个hash函数,对一个key进行哈希,将命中的bitmaps(实际上是一个二进制数组)的桶值修改为1,在确定是否存在某个key时,通过同样的hash函数,找到对应的位置,如果都为1,判断该值存在,如果存在一个位置为0,则判断该值不存在,都为1时不一定存在,存在0时,一定不存在,通过这种方式可以防止缓存穿透。
3. 为何6.0之前使用单线程而之后引入了多线程
- 6.0之前使用单线程的原因是因为Redis的性能瓶颈不在上下文的切换上,而是在与CPU计算和网络请求上,无需使用多线程操作
- 6.0之后引入的原因是为了解决一下io密集型的任务,比如aof日志,rdb快照的持久化,其他批量操作
4. Redis的高级功能有哪些
- 慢查询:快速定位系统中的慢查询操作
- watch命令:相当于乐观锁,确保事务读取时数据没有被其他事务修改,如果修改则不读取
- 分布式锁:通过setnx命令,多个客户端set同一个key,如果key已经存在,则set失败,由此实现互斥
- 高性能与高并发:主从复制架构可以做到读写分类
- 哨兵模式:如果主节点发生故障,哨兵可以将从节点指定为主节点,主节点恢复后变为从节点
5. 为什么引入Redis
- 高并发:
Redis支持主从复制,主节点复制写操作,而从节点复制读操作,读写分离,可以支持高并发场景,当主节点出现故障的时候,通过哨兵模式,切换主节点,保证系统正常使用 - 高性能:Redis是基于内存的操作,速度十分快速
6. Redis事务
Redis事务通过两个命令完成:
- multi:开启事务
- exec:退出事务
将要执行的事务操作放在两个命令之间即可,此外还有一个discard命令用于回滚,但是Redis事务只能对基本的语法错误进行回滚,运行时错误无法回滚
7. Redis的过期策略
- 定时过期:定时从设置了过期时间的数据字典里面读取一组key(默认20个),删除其中过期了的key,默认是10次/s读取,当一组key里面有超过四分之一是过期的,则再读取一组(贪心算法)
- 惰性过期:在使用到key时才回去判断是否过期
从库的过期策略:主库中的key过期后,会在给从库发送的同步文件中增加一条del命令,删除过期key
8. 缓存淘汰机制
当Redis分配的内存满了,会开始频繁与磁盘进行交互,导致性能下降
Redis可以通过设置maxmemory修改最大内存空间
缓存淘汰机制:
- Noevication:默认情况下不淘汰key,此时只许读不许写
- volatile_lru:从设置了过期时间的key中淘汰最少使用的key
- volatile_ttl:从设置了过期时间的key中淘汰剩余存活时间最短的key
- volatile_random:从设置了过期时间的key里面随机淘汰key
- allkeys_lru:从所有key里面淘汰最少使用的key
- allkeys_random:从所有key里面随机淘汰key
9. 缓存雪崩、缓存击穿、缓存穿透
- 缓存雪崩
- 缓存中的热点数据同一时间失效,导致大量请求请求到数据库,造成系统崩溃
- 解决方案:
. 热点数据不设置过期时间
. 使用主从复制架构,提高系统的可用性,主节点故障的时候,从节点提供服务
- 缓存击穿
- 数据库中存在的数据而缓存中没有,在高并发情况下,大量请求直接落到数据库或其他缓存中,导致数据库负担过大,影响性能
- 解决方案:
. 使用lru缓存淘汰机制 ,及时将不常用的数据从缓存中删除,给热点数据提供缓存空间
. 使用布隆过滤器的缓存预热功能,提前将热点数据加载到缓存中
. 使用分布式锁,让同一时间只有一个请求可以访问同一数据
- 缓存穿透
- 缓存中没有且数据库中也没有的数据被大量请求,导致数据库负担过大,通常是恶意请求
- 解决方案:
. 使用缓存空对象,将空对象缓存到缓存中,返回空对象,而不再请求数据库
. 使用布隆过滤器,对恶意请求进行拦截
10. Redis分布式锁
- 通过setnx设置key,同一时间只有一个客户端能设置该key,如果设置成功则返回1,否则返回0,由此实现互斥
- 存在一个客户端宕机,key无法释放,其他客户端一直不能set的情况,可以通过设置过期时间来解决
- 过期时间结束而客户端没有完成业务处理的情况,可以加入看门狗来解决,当客户端设置过期时间后,开启一个守护线程,定时检查剩余过期时间,如果业务没有完成,而过期时间将要结束,则自动续期
11. bigkey
- 定义:字符串类型的key存储了超过10kb的字符串(通常来说);其他如list,hash,set,zset存储了太多元素
- 危害:空间分布不均;大容量造成网络堵塞
- 解决:拆分
12. 如何解决key冲突
- 在key设计上:添加唯一标识,如数据库ID
- 代码实现上:使用分布式锁
13. 如何提高缓存的命中率
- 提前加载,缓存预热
- 增加缓存可用的内存空间
14. Redis持久化
- aof
以独立日志的方式,将每一次写操作记录到日志中,每次重启时加载
缺点:性能差 - rdb
以快照的方式备份数据
缺点:两次快照之间有空窗
15. 为什么Redis使用内存作为工作空间
- 内存中的操作速度远高于磁盘中
- 内存价格不再那么贵,性价比提高
- 内存中的数据可以持久化到磁盘中
- 即使内存满了也有内存淘汰机制保证系统正常运行