本文已参加「新人创作礼」活动,一起开启掘金创作之路.
一.什么是redis?
- redis可以理解为远程数据服务或远程字典服务,其底层是由C语言编写的key-value存储系统.
二.redis适合的场景
- 缓存:减轻MySQL的查询压力,提升系统性能;
- 排行榜:利用Redis的Sortset实现;
- 计算器/限速器:利用Redis中原子性的自增操作,我们可以统计类似点赞数,用户访问数等,限速器比较 典型 的使用场景是限制某个用户访问某个API(接口)的频率;
- 消息队列:除了Redis自身的发布/订阅模式,也可以用List来实现一个队列机制,例如:到货通知,邮件发送等需求,不需要高可靠,但是会带来非常大的DB压力,可以用List来完成异步解耦;
- Session共享: Session是保存在服务器的文件中,如果是集群服务,同一个用户过来可能要落在不同机器上,这就会导致用户频繁登录,采用redis保存Session后,无论用户落在哪台机器上都能获取到对应的Session信息.
三.redis不适合的场景
- 数据量太大,访问频率非常低的业务都不适合redis的使用,数据太大会增加成本,访问频率太低,保存在内存中浪费资源.
四.redis为什么这么快
- 内存存储数据,可以避免频繁的进行写盘操作,大大降低响应时间.
- redis是纯内存操作:数据存放在内存中
- 非阻塞I/O:Redis采用I/O多路复用技术的实现,单线程避免了线程切换和竞态产生的消耗.Redis是面向高速执行的数据库.
五.redis有哪些数据类型?可以应用在什么场景?
-
redis总共有八种数据类型,五种基本数据类型和三种特殊数据类型
-
五种基本数据类型
- String:字符串类型
- hashmap:key-value形式的,value是一个map
- list:基本的数据类型,列表.在Redis中可以把list用作栈,队列,阻塞队列.
- set:集合,不能有重复元素,点赞,收藏等.
- zset:有序集合,不能有重复元素,有序集合中的每个元素都需要指定一个分数,获取对应元素进行排序,可以做排行榜.
-
- 三种特殊数据类型(了解)
-
- geospatial :Redis 在 3.2 推出 Geo 类型,该功能可以推算出地理位置信息,两地之间的距离。
- hyperloglog :基数:数学上集合的元素个数,是不能重复的。这个数据结构常用于统计网站的 UV。
- bitmap :bitmap 就是通过最小的单位 bit 来进行0或者1的设置,表示某个元素对应的值或者状态。一个 bit 的值,或者是0,或者是1;也就是说一个 bit 能存储的最多信息是2。bitmap 常用于统计用户信息比如活跃粉丝和不活跃粉丝、登录和未登录、是否打卡等。
六.redis 是单线程还是多线程呢?
-
Redis 在 4.0 的时候引入了多线程来做大缓存的清除处理工作,主要是体现在大数据的异步删除功能上,例如 unlink key、flushdb async、flushall async 等,先清除 key ,接着异步清除对应的 value。
-
在 Redis 6.0 之前的网络模型都是标准的单线程 reactor 模型。在 6.0 开始引入了一个非标准的多线程 reactor 模型,sub-reactor 此时会使用 socket 读取 client 请求,并处理命令的解析,然后具体写还是在主线程上执行。
-
redis 使用了多线程不会有线程安全的问题吗?为什么redis 6.0 之后改多线程呢?不会,因为多线程用来处理读写和协议,还是使用单线程处理客户端的请求,执行命令也是用单线程,所以不会出现线程安全问题. 因为redis的瓶颈不是CPU而是网络IO,使用多线程能够提高网络IO的效率,从而整体提高redis性能.
七,redis的持久化方式
AOF|RDB(redis默认持久化方式)
- AOF持久化,redis每次执行一个命令时,都会将这个原本的话语请求放进一个aof文件中,然后通过fsync策略,将命令执行后的数据持久化存储到硬盘中,
AOF的优点
- 可以更好地保护数据不丢失,将命令直接追加到文件末尾[写入的性能非常高],aof的日志命令可以通过非常可读的方式进行记录.
AOF的缺点
-
在同一份文件下,AOF文件比RDB数据快照要大,每次命令都会写入,消耗的性能大,数据恢复也比较慢.
-
RDB是把某个时间段的数据用二进制的方法存储到一个以rdb为后缀的文件中,就是周期性的备份redis中的所有数据,也就是快照,采用fork进程的方式来写同步的.
RDB的优点
- 因为是周期进行数据保存,所以在做大型数据恢复时速度很快,由于RDB采用fork的进程机制,所以对于客户端提供读写
RDB的缺点
- 有可能会产生长时间的数据丢失,可能会有长时间停顿:我们前面讲了,fork子进程这个过程是和redis的数据量很大关系的,如果数据量很大,那么很有可能会使redis停顿几秒.
八.redis 的过期键的删除策略有哪些?
定时删除,惰性删除,定期删除
- 定时删除:每设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除,该策略可以立即清除过期的数据,对内存很友好,但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量.
- 惰性删除:只有访问这个key的时候才会判断该key是否过期,过期则清除,该策略可最大化地节省CPU资源,却对内存非常不友好,极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存.
- 定期删除:每隔一段时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key,该策略是定时和惰性两者的一个折中方案,通过调整定时扫描的时间间隔和每次扫描的限时耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果.
九. redis 的内存淘汰策略(8种策略,用来处理内存满的情况)
- noeviction:默认策略,直接返回错误,不淘汰任何已经存在的redis键;
- allkeys-lru:所有的键使用LRU(最近最少使用)算法进行淘汰;
- volatile-lru:从设置了过期时间的key中使用LRU(最近最少使用)算法进行淘汰;
- allkeys-random:随机删除 redis 键;
- volatile-random:随机删除有过期时间的 redis 键;
- volatile-ttl:删除快过期的redis键;
- volatile-lfu:根据LFU算法从有过期时间的键删除;
- allkeys-lfu:根据LFU算法从所有键删除;
十. redis 的热 key 问题怎么解决?
什么是热key?
- 热key就是说,在某一时刻,有非常多的请求访问某个key,流量过大,导致redis服务器宕机.
解决方案:
-
redis集群扩容:增加分片副本,均衡读流量;
-
可以将结果缓存到本地内存中;
-
将热key分散到不同的服务器中;
十一, 缓存穿透、缓存击穿、缓存雪崩是什么?怎么解决呢?
缓存穿透
- 缓存穿透是用户访问缓存时,缓存中没有数据,去访问数据库,数据库中也没有这个数据,导致数据库宕机;
解决方案:
- 使用布隆过滤器(可以缓解,为什么是缓解,因为使用过滤器还会造成误判的情况),返回空对象
缓存击穿
- 缓存击穿,是指一个 key 非常热点,在不停的扛着大并发,当这个 key 在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库导致宕机。
解决办法:
- 互斥锁: 缓存失效时,不是立即去加载db数据,而是先使用某些带成功返回的原子操作命令,如(Redis的setnx)去操作,成功的时候,再去加载db数据库数据和设置缓存。否则就去重试获取缓存。
永不过期:
-
(1) 从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期。
-
(2) 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期。
缓存雪崩
- 缓存雪崩是指缓存中不同的数据大批量到过期时间,而查询数据量巨大,请求直接落到数据库上导致宕机.
解决办法:
均匀过期
- 在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期。
双层缓存策略、二级缓存
- Cache1 为原始缓存,Cache2 为拷贝缓存,Cache1 失效时,可以访问 Cache2,Cache1 缓存失效时间设置为短期,Cache2 设置为长期。
加互斥锁
- 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个 key 只允许一个线程查询数据和写缓存,其他线程等待;
十二.redis有哪些部署方式?
- 单机模式: 这也是最基本的部署方式,只需要一台机器,负责读写,一般只用于开发人员自己测试。
- 哨兵模式: 哨兵模式是一种特殊的模式,首先 redis 提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待 redis 服务器响应,从而监控运行的多个 redis 实例。它具备自动故障转移、集群监控、消息通知等功能。
- cluster 集群模式: 在 redis3.0 版本中支持了 cluster 集群部署的方式,这种集群部署的方式能自动将数据进行分片,每个 master 上放一部分数据,提供了内置的高可用服务,即使某个 master 挂了,服务还可以正常地提供。
- 主从复制: 在主从复制这种集群部署模式中,我们会将数据库分为两类,第一种称为主数据库(master),另一种称为从数据库(slave)。主数据库会负责我们整个系统中的读写操作,从数据库会负责我们整个数据库中的读操作。其中在职场开发中的真实情况是,我们会让主数据库只负责写操作,让从数据库只负责读操作,就是为了读写分离,减轻服务器的压力。