java学习之路

JavaGuide知识点整理——Redis面试题总结(上)

2022-09-10  本文已影响0人  唯有努力不欺人丶

Redis基础

简单来说redis就是一个使用C语言开发的数据库。不过与传统数据库不同的是Redis的数据是存在内存中的,也就是说它是内存数据库,所以读写速度非常快,因为Redis被广泛用于缓存方向。
另外Redis除了可以做缓存外,还经常被用来做分布式锁,甚至消息队列。
Redis提供了多种数据类型来支持不同的业务场景。Redis还支持事务,持久化,lua脚本,多种集群方案。

分布式缓存常见的技术选型方案有哪些?

分布式缓存的话,使用较多的是memcached和Redis。现在最主流的是Redis。
Memcached是分布式缓存刚兴起那会比较常用的。后来随着Redis发展,Redis使用率更高了。
分布式缓存主要解决的是单机缓存的容量受服务器限制并且无法保持通讯信息的问题。因为本地缓存只有在当前服务里有效。比如部署两个相同的服务器,他们之间的缓存是无法共同的。

Redis和Memcached的区别和共同点

共同点:

  1. 都是基于内存的数据库,一般都被当做缓存使用
  2. 都有过期策略
  3. 两者的性能都非常高

区别:

  1. Redis支持更丰富的数据类型。Memcached只支持K/V对。而Redis支持K/V对,list,set,zset,hash等数据结构的存储。
  2. Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用.Memcached把数据都存在内存中了。
  3. Redis有灾难恢复机制。这也是因为Redis可以持久化。
  4. Redis在服务器内存使用完后,可以将不用的数据放到磁盘上。但是Memcached在服务器内存使用完后会直接报异常
  5. Memcached没有原生的集群模式,需要依靠客户端来实现集群中分片写入数据。Redis目前是原生支持cluster模式的。
  6. Memcached是多线程,非阻塞IO复用的网络模型,而Redis使用的是单线程的多了IO复用模型(Redis6.0引入了多线程IO)
  7. Redis支持发布订阅模型,lua脚本,事务等功能,而Memcached不支持。
  8. Memcached过期数据的删除策略只用了惰性删除。而Redis同时使用了惰性删除与定期删除。

缓存数据的处理流程是怎样的?

简单来说如下:

  1. 用户请求的数据在缓存中有,就直接返回
  2. 缓存中不存在就去查看数据库是否存在
  3. 数据库中存在就更新缓存中的数据
  4. 数据库中不存在直接返回空

为什么要用Redis(为什么要用缓存)?

主要从高性能和高并发两点考虑的。
高性能:
数据库查询是磁盘IO,效率没有从内存中查询快。如果用户访问的数据属于高频且不会经常改变,放在缓存中可以提升访问速度。
高并发:
MySQL的OPS在1w左右,而Redis缓存之后很容易达到10W+。由此可见直接操作缓存能够承受的请求数量远远大于直接访问数据库的。

Redis除了做缓存还能做什么?

Redis如何实现消息对列?

Redis5.0新增了一个数据结构Stream可以用来做消息对列,其支持:

不过和专业的消息队列比较,还是有欠缺的地方。比如消息丢失和堆积问题不好解决。还是建议选择市面上成熟的消息队列,比如RocketMQ,Kafka等。

Redis数据结构

Redis常用的数据结构有哪些?

简单说一下每种类型都有哪些操作:

三种特殊类型用法:

String的应用场景有哪些?

String还是hash存储对象数据更好呢?

打个比方,购物车信息建议用Hash存储。用户id为key,商品id为field,商品数量为value。因为购物车中的商品会频繁改动。绝大多数情况我们建议用String存储对象数据。

使用Redis实现一个排行榜

Redis中zset经常被用在各种排行榜的场景,比如直播间礼物排行榜,朋友圈的微信步数排行榜,王者中的段位排行榜等。因为这个数据自带一些命令:zrange(从小到大排序),zrevrange(从大到小排序),zrevrank(按照自定元素排名)

使用Set实现抽奖需要用到什么命令?

使用Bitmap统计活跃用户做法

使用日期作为key,用户id为offset,,如果当日活跃过就设置为1.统计的时候用BITOP获取一段时间内的活跃度或者BICOUNT获得某日总活跃度:


统计活跃度

Redis线程模型

Redis单线程模型

Redis是基于Reactor模式来设计开发了自己的一套高效的事件处理模型(Netty的线程模型也是基于Reactor模式)。这套事件处理模型对应的是Redis中的文件事件处理器。由于文件事件处理器是单线程方式运行的,所以我们一般都说Redis是单线程模型。
既然是单线程,那么怎么监听大量的客户端连接呢?
Redis通过IO多路复用程序来监听来自客户端的大量连接(或者说是监听多个socket)。它会将感兴趣的时间以及类型注册到内核中并监听每个事件是否发生。
这样的好处非常明显:IO多路复用技术的使用让Redis不需要额外创建多余的线程来监听客户端的大量连接,降低了资源的消耗。
另外Redis服务器是一个事件驱动程序,服务器需要处理两类事件:

  1. 文件事件
  2. 时间事件

时间事件不需要多花时间了解,我们接触最多的还是文件事件(客户端进行读取写入等到左,涉及一系列网络通信)。

文件事件处理器主要包括四个部分:

Redis6.0之前为什么都是单线程模式?

虽说Redis是单线程模型,但是4.0之后就加入了对多线程的支持。不过4.0增加的多线程主要是针对一些大的键值对的删除操作命令,使这些命令异步处理。大体来说6.0之前还是单线程的。为什么要这样呢?主要原因有三个:

  1. 单线程编程容易并且更容易维护
  2. Redis的性能瓶颈不在CPU上,主要在内存和网络
  3. 多线程会存在死锁,线程上下文切换等问题,甚至会影响性能

Redis6.0为何引入了多线程?

Redis6.0引入多线程主要是为了提高网络IO读写性能。因为这个也算是性能瓶颈之一(内存和网络)。
虽然6.0引入了多线程,但是只是在网络数据的读写这类耗时操作上使用了。执行命令仍然是单线程顺序执行。
并且6.0的多线程默认是禁用的,如需要开启要修改配置文件:

io-threads-do-reads yes

开启多线程后还需要配置线程数,否则也是不生效的,同样是修改配置文件:

io-threads 4 #官网建议4核的机器建议设置为2或3个线程,8核的建议设置为6个线程

Redis内存管理

Redis给缓存数据设置过期时间用处

因为内存是有效的,如果缓存中的所有数据都一致保存的话,耗费性能且没必要。Redis子弟了给缓存数据设置国企时间的功能,除了字符串类型有自己独有设置过期时间的命令setex之外,其他方法都需要依靠expire命令来设置过期时间。另外presist命令可以移除一个键的过期时间。

过期时间除了缓解内存的消耗,还可以针对业务需求有实际的效果。比如验证码的有效期是五分钟,如果是传统数据库我们还要自己判断过期时间,更麻烦且性能还差。

Redis是如何判断数据是否过期的?

Redis通过一个叫做过期字典来保存数据的过期时间。过期字典的键指向Redis数据库中的key,值是log类型的证书,保存的key的过期时间。

过期的数据删除策略

有两个策略:

Redis采用的是定期删除+惰性删除

Redis内存淘汰机制

  1. volatile-lru:从设置过期时间的数据集中挑选最近最少使用的数据淘汰
  2. volatile-ttl:从设置过期时间的数据集中挑选将要过期的数据淘汰
  3. volatile-random:从设置过期时间的数据集中随机淘汰
  4. allkeys-lru:移除最近最少使用的key
  5. allkeys-random:随机淘汰
  6. no-eviction:不淘汰,内存满了直接报错

4.0版本后增加两个策略:
7.volatile-lfu:从设置过期时间的数据集中挑选最不经常用的淘汰

  1. allkeys-lfu:挑选最不经常用的key淘汰

Redis持久化机制

持久化其实是保证挂掉重启后可以进行数据恢复的保证。Redis相比于Memcached最大的优点也是支持持久化。Redis有两种持久化方式:RDB快照,AOF文件追加。

RDB持久化

创建快照获取存储在内存里的数据的某个时间点上的副本。Redis是默认开启这种持久化方式的,我们可以设置快照的频率。

save 900 1           #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 300 10          #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

AOF持久化

AOF其实就是redis的每一条命令都追加到文件中。恢复的时候从头执行一次就行。但是Redis默认是不开启AOF的。可以通过appendonly参数开启:

appendonly yes

这个原理类似MySQL的日志记录。每一个命令存到缓存文件中,然后根据配置同步到硬盘的文件中。Redis有三种不同的AOP持久化方式:

appendfsync always    #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec  #每秒钟同步一次,显式地将多个写命令同步到硬盘
appendfsync no        #让操作系统决定何时进行同步

AOF重写

其实这个功能不会对原有文件有任何的读取,分析或者写入的操作。而是根据读取数据库中的键值对来实现的。
比如对key1 这个键 设置值1,然后改成2,然后改成lsj,然后改成ll。正常的aof会有四条命令。但是其实有效的只有key1 = ll这一个。所以重写后会清理很多无用的东西。
重写本质就是读取当前kv.然后读取过程中创建线程记录读取时候的命令,在读取完后追加读取过程中的命令作为一个新的AOF文件替换旧的,这就是AOF重写。

Redis4.0对持久化机制优化

Redis4.0开始支持AOF和RDB混合持久化。
AOF重写的时候直接把RDB的内容写到AOF文件开头,既快速又避免丢失过多数据。缺点就是AOF文件不再是AOF格式,可读性差。

本篇笔记就记到这里,如果稍微帮到你了记得点个喜欢点个关注。也祝大家工作顺顺利利,中秋快乐哟~!

上一篇 下一篇

猜你喜欢

热点阅读