Java面试题干货系列(四)(掌握了这些Redis面试题,面试官会对你刮目相看)

前言

随着时代的发展,现在缓存是应用的核心,那么Redis缓存的使用,也是必不可少的,所以好多企业也是必问Redis,笔者这里总结了一些Redis相关的面试题,希望对老铁们有所帮助。

本系列文章,笔者准备对互联网缓存利器Redis的使用,做一下简单的总结,内容大概如下:

博文内容资源链接
Linux环境下搭建Redis基础运行环境https://blog.csdn.net/smilehappiness/article/details/107298145
互联网缓存利器-Redis的使用详解(基础篇)https://blog.csdn.net/smilehappiness/article/details/107592368
Redis基础命令使用Api详解https://blog.csdn.net/smilehappiness/article/details/107593218
Redis编程客户端Jedis、Lettuce和Redisson的基础使用https://blog.csdn.net/smilehappiness/article/details/107301988
互联网缓存利器-Redis的使用详解(进阶篇)https://blog.csdn.net/smilehappiness/article/details/107592336
如何基于Redis实现分布式锁https://blog.csdn.net/smilehappiness/article/details/107592896
基于Redis的主从复制、哨兵模式以及集群的使用,史上最详细的教程来啦~https://blog.csdn.net/smilehappiness/article/details/107433525
Redis相关的面试题总结https://blog.csdn.net/smilehappiness/article/details/107592686

1 什么是Redis?

Redis(Remote Dictionary Server) 是一个使用 C 语言编写的,开源的(BSD许可)高性能的非关系型(NoSQL)的键值对数据库

Redis是一个开源的,基于内存的数据结构存储服务器,被用作数据库、缓存、消息代理。它支持的数据结构类型有strings, hashes, lists, sets, sorted sets,bitmaps, hyperloglogs, geospatial, Stream。Redis有内置的复制,lua脚本,LRU(Least Recently Used最近最少使用)淘汰,事务,磁盘持久化,并提供高可用的Redis Sentinel哨兵自动分区的Redis Cluster集群

Redis可以存储键和9种不同类型的值之间的映射。Redis键的类型只能为字符串,value值常用的类型有5种:字符串列表集合有序集合散列表

Redis数据库与传统数据库不同的是Redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向,每秒可以处理超过10万次读写操作,是已知性能最快的Key-Value DB。另外,Redis 也经常用来做分布式锁。除此之外,Redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。

2 为什么要使用缓存?为什么选择Redis缓存

2.1 缓存的作用

用缓存一般来说,就是为了提高用户交互的效率,缓存主要有两个用途:高性能高并发

  • 高性能
    假设有一个场景,一个请求过来,从数据库获取数据,耗时 1000ms。但是这个结果可能接下来几个小时都不会变了,或者变了也可以不用立即反馈给用户。那么这种数据就可以使用缓存,从数据库获取数据以后,写入缓存,下次再进行查询时,直接从缓存里读取数据,这样性能就可以大大提高

    就是说对于一些需要复杂操作耗时查出来的结果,且确定后面不怎么变化,但是有很多读请求,那么直接将查询出来的结果放在缓存中,后面直接走缓存,可以大大提高系统的吞吐量。

  • 高并发
    mysql 这么重的数据库,压根儿设计不是让你玩儿高并发的,虽然也可以玩儿,但是天然支持不好。mysql 单机支撑到 2000QPS 也开始容易报警了。

    直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。所以要是你有个系统,高峰期一秒钟过来的请求有1万,那一个 mysql单机绝对会死掉。使用缓存,可以提高系统吞吐量。缓存是走内存的,内存天然就支撑高并发

2.2 为什么选择Redis缓存

缓存分为本地缓存和分布式缓存。以 Java 为例,使用自带的 map 或者 guava 实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着 jvm 的销毁而结束,并且在多实例的情况下,每个实例都需要各自保存一份缓存,缓存不具有一致性。

使用 redis 或memcached之类的称为分布式缓存,在多实例的情况下,各实例共用一份缓存数据,缓存具有一致性。缺点是需要保持 redis 或 memcached服务的高可用,整个程序架构上较为复杂。

Redis缓存性能极好,缓存功能也简单,说白了就是 key-value 式操作,单机支撑的并发量轻松一秒几万十几万,支撑高并发。在分布式事务实现上也比较简单。另外,Redis的哨兵或者集群,都可以保证分布式环境下Redis服务的高可用性。

Redis支持PDB和AOF持久化方式,当服务故障时,可以快速恢复缓存的数据。

3 Redis为什么这么快

  • 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是O(1)

  • 数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的

  • 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗

  • 核心是基于非阻塞的 IO 多路复用机制

  • C 语言实现,一般来说,C 语言实现的程序“距离”操作系统更近,执行速度相对会更快

  • 使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求

4 Redis有哪些数据类型,使用场景是什么

限于篇幅,可以参考我的另一篇博文中的介绍: https://blog.csdn.net/smilehappiness/article/details/107592368

5 Redis过期key自动删除(自动清理)的原理

面试中,可能会问到: Redis中的key失效是如何实现的,即失效的key是如何删除的?

过期策略通常有以下三种:
定时过期: 每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
惰性过期: 只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
定期过期: 每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
(expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)

Redis删除失效key的方法主要有两种:

  • 消极方法(passive way)
    在key被访问时如果发现它已经失效,那么就删除它

  • 积极方法(active way)
    周期性地从设置了过期时间的key中选择一部分过期的key删除。对于那些从未被查询的key,即便它们已经过期,消极方式也无法清除,因此Redis会周期性地随机测试一些key,已过期的key将会被删掉

    Redis每秒会进行10次操作,具体的流程:
    a、随机测试20个带有过期信息的key
    b、删除其中已经过期的key
    c、如果超过25%的key被删除,则重复执行步骤a
    这是一个简单的概率算法(trivial probabilistic algorithm),基于假设我们随机抽取的key代表了全部的key空间。

Redis中同时使用了惰性过期和定期过期两种过期策略。

6 Redis的持久化有了解吗

限于篇幅,可以参考我的另一篇博文中的介绍: https://blog.csdn.net/smilehappiness/article/details/107592336

7 什么是分布式锁? 如何实现分布式锁?

7.1 什么是分布式架构

分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。随着互联网的飞速发展,用户量急剧增多,互联网产品越来越多样化,内容越来越多,传统的单体应用结构系统已经无法满足需求,分布式系统就应运而生。

分布式系统通过服务化,即SOA架构的方式,采用分而治之的策略,通过业务上合适的拆分,将海量用户的访问量进行拆分分流,以满足系统的高可用性高性能可伸缩可扩展的需求。

在介绍分布式锁内容之前,先来简单介绍下,什么是分布式,与传统的单应用服务架构有什么区别,以便于更好地理解分布式锁。

下面介绍下分布式架构中的一些基础概念。

  • 分布:
    分布指的是在一定的范围内散布开,分布的反义词集中

  • 集中式架构:
    就是把所有的程序、功能、模块都集中到一个项目中,部署在一台服务器上,从而对外提供服务(单体架构、单体服务、单体应用)。

    这种结构在前几年很流行,当前互联网流行的是分布式架构,因为现在的业务系统很复杂,集中式架构已经不能够满足业务需要,回想一下,前些年还是一个项目,打一个war包,扔到Tomcat部署,就满足了业务需要,现在,远远不能满足当下的业务需求,所以,分布式架构应运而生。

  • 分布式架构:
    就是把所有的程序、功能、模块拆分成不同的子项目,部署在多台不同的服务器上,这些子项目相互协作,共同对外提供服务。

    直白来说,就是有很多项目,有很多jar(war)包,这些项目相互协作才能完成需要的功能,满足业务的需要。

    简单来说,就是之前的一个单体应用(后台管理系统),通过拆分,拆分成用户中心、产品中心、客户中心等多个小应用服务,这种把一个大的单体应用项目,拆分成多个小应用项目的方式,就是分布式系统应用

7.2 集群部署和分布式部署的区别

  • 集群
    集群就是将相同的程序、功能,部署在两台或多台服务器上,这些服务器对外提供的功能是完全一样的,集群是通过不断横向扩展增加服务器的方式,以提高服务的能力。

  • 分布式
    分布式就是将两个或多个程序、功能分别运行在两台或多台主机服务器上,这些服务器对外提供的功能并不一样,它们通过相互协作最终完成某一个服务或功能。

简单地来说,如果两台或者多台服务器部署的程序功能完全一样就是集群(常见的有Redis集群,MySQL主从复制,Nginx高可用,Zookeeper集群,服务应用集群等等),程序功能如果不一样就是分布式

分布式中的每一个服务节点,都可以做集群(根据服务压力决定部署几台服务器集群),而集群并不一定就是分布式的。

7.3 什么是分布式锁

  • 什么是分布式锁
    关于锁,我们并不陌生,比如Java语言有线程锁,比如:synchronize / Lock等,锁的目的很简单,即在多线程环境下,对共享资源的访问造成的线程安全问题,通过锁的机制来实现资源访问互斥。

    什么是分布式锁呢?为什么我们需要分布式锁?
    其实最根本原因就是锁(互斥)的范围发生了改变,因为在分布式架构中,所有的应用都是集群部署多份并且部署在多个不同的机器上,这些应用(进程)是隔离的,在多进程访问共享资源的时候我们需要满足互斥性,就需要一个所有进程都能看得到的范围,而这个范围可以使用Redis本身或者zookeeper或者数据库等外部设施,所以我们才需要把锁构建到Redis或者zookeeper或者数据库中。

7.4 基于Redis实现分布式锁

Redis里面提供了一些能够实现互斥特性的命令,比如SETNX (在key不存在的情况下为key设置值,key存在的话就不设置值),那么我们可以基于这些命令来去实现锁。

利用Redis实现分布式锁主要用到三个命令:

  • SETNX设置key及key的值,如果key存在就设置失败,key不存在就设置成功
  • EXPIRE设置key的过期时间
  • DEL 删除key

8 Redis内存回收策略有哪些

Redis中提供了多种内存回收策略,当内存容量不足时,为了保证程序的运行,这时就不得不淘汰内存中的一些对象,释放这些对象占用的空间,那么选择淘汰哪些对象呢?

其中,默认的策略为noeviction策略,当内存使用达到阈值的时候,所有引起申请内存的命令会报错。
首先,需要设置最大内存限制 maxmemory 5120mb

Redis官方:
Setting maxmemory to zero results into no memory limits. This is the default behavior for 64 bit systems, while 32 bit systems use an implicit memory limit of 3GB.

选择的策略类型:
maxmemory-policy noeviction

noeviction: 默认策略,不淘汰,如果内存已满,添加数据时报错

allkeys-lru: 在所有键中,选取最近最少使用的数据淘汰
volatile-lru: 在设置了过期时间的所有键中,选取最近最少使用的数据淘汰

allkeys-lfu: 在所有键中,选取最近最不常访问的数据淘汰
volatile-lfu: 在设置了过期时间的所有键中,选取最近最不常访问的数据淘汰

allkeys-random: 在所有键中,随机淘汰
volatile-random: 在设置了过期时间的所有键,随机淘汰

volatile-ttl: 在设置了过期时间的所有键,存活时间最短的数据淘汰

9 Redis键空间通知有了解过吗

限于篇幅,可以参考我的另一篇博文中的介绍: https://blog.csdn.net/smilehappiness/article/details/107592336

10 Redis主要消耗什么物理资源?

Redis主要把数据存储到物理内存中。一般建议Redis的内存数据不要超过5g

11 Redis的内存用完了会发生什么?

如果达到设置的上限,Redis的写命令会返回错误信息(但是读命令还可以正常返回),当然啦,你可以配置内存淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。

12 Redis缓存穿透 && 缓存击穿 && 缓存雪崩

12.1 缓存处理流程

前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。

Created with Raphaël 2.2.0 开始 Redis缓存中是否有数据 返回正常数据 结束 数据库中是否有数据 更新缓存数据 返回空数据 yes no yes no

12.2 Redis缓存穿透

缓存穿透是指大量不存在的key请求,由于缓存没有,便开始查询数据库,但数据库也没有查到数据,比如一些恶意攻击、爬虫等造成大量空命中。即:缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,会导致数据库压力过大,甚至宕机

解决方案:

  • 方案一: 缓存空结果,对数据库查询不存在的数据仍然记录在缓存中缓存一条数据,比如缓存一条空值 unknow,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用不存在的key暴力攻击,这样能有效的减少查询数据库的次数。(无论如何,要保证数据库的可用性

  • 方案二: 使用布隆过滤器

12.3 Redis缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力导致数据库不可用的现象。

高并发条件下,对于热点数据(一般地,80%的情况下都是访问某些热点数据,也就是访问某些热点key,其他key访问会比较少),当数据缓存失效的一瞬间,或者刚开始时缓存中还没有对热点数据进行缓存,所有请求都被发送到数据库去查询,导致数据库被压垮。

解决方案:

  • 方案一: 使用全局互斥锁,就是在访问数据库之前都先请求全局锁,获得锁的那个才有资格去访问数据库,其他线程必须等待。由于现在的业务都是分布式的,本地锁没法控制其他服务器也等待,所以要用到全局锁,比如分布式锁。

  • 方案二: 对即将过期的数据主动刷新,比如起一个后台定时任务轮询,主动更新缓存数据,保证缓存不会全部失效。

  • 方案三: 设置热点数据永远不过期

12.4 Redis缓存雪崩

缓存雪崩是指:比如我们给所有的数据设置了同样的过期时间,然后在某一个历史性时刻,整个缓存的数据全部过期了,然后瞬间所有的请求都落到数据库,数据库被压垮,或者是缓存发生故障,导致所有的请求都落入到数据库,数据库被压垮

简单来说就是,缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至宕机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库,缓存雪崩更加的严重。

缓存雪崩的核心就是你的缓存不能用了,不能用了包含两种情况:
突然有一个高并发请求:

  • 我要查的数据都没有缓存,那么都查询数据库,数据库可能被查询宕机
  • 缓存本身就不能用了,比如缓存宕机了,那么也导致所有请求都查询数据库,数据库宕机

解决方案:
事前:

  • redis要高可用(搭建集群或者主从哨兵),避免redis不可用
  • 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生
  • 如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中

事中:

  • 本地ehcache缓存(mybatis二级缓存)+限流&降级(比如返回:系统繁忙,请稍后再试或者网络开小差了等等),避免数据库被压垮
  • 也可以使用极端的处理,把热点数据设置为-1,即永远不过期

事后: redis持久化,快速恢复缓存数据
在这里插入图片描述

13 Redis线程模型

Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器(file event handler)。因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。它采用 IO 多路复用机制同时监听多个 socket,将产生事件的 socket 压入内存队列中,事件分派器根据 socket 上的事件类型来选择对应的事件处理器进行处理。

文件事件处理器的结构包含 4 个部分: 多个套接字socketIO多路复用程序文件事件分派器事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)

文件事件处理器使用I/O 多路复用(multiplexing)程序来同时监听多个套接字, 并根据套接字目前执行的任务来为套接字关联不同的事件处理器。

多个 socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程序会监听多个 socket,会将产生事件的 socket 放入队列中排队,事件分派器每次从队列中取出一个 socket,根据 socket 的事件类型交给对应的事件处理器进行处理。

当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时, 与操作相对应的文件事件就会产生, 这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。

虽然文件事件处理器以单线程方式运行, 但通过使用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又可以很好地与 redis 服务器中其他同样以单线程方式运行的模块进行对接, 这保持了 Redis 内部单线程设计的简单性

来看客户端与 Redis 的一次通信过程:
在这里插入图片描述
首先,Redis 服务端进程初始化的时候,会将 server socket 的 AE_READABLE 事件与连接应答处理器关联。

客户端 socket01 向 Redis 进程的 server socket 请求建立连接,此时 server socket 会产生一个 AE_READABLE 事件,IO 多路复用程序监听到 server socket 产生的事件后,将该 socket 压入队列中。文件事件分派器从队列中获取 socket,交给连接应答处理器。连接应答处理器会创建一个能与客户端通信的 socket01,并将该 socket01 的 AE_READABLE 事件命令请求处理器关联。

假设此时客户端发送了一个 set key value 请求,此时 Redis 中的 socket01 会产生AE_READABLE 事件,IO 多路复用程序将 socket01 压入队列,此时事件分派器从队列中获取到 socket01 产生的 AE_READABLE 事件,由于前面 socket01 的 AE_READABLE 事件已经与命令请求处理器关联,因此事件分派器将事件交给命令请求处理器来处理。命令请求处理器读取 socket01 的 key value 并在自己内存中完成 key value 的设置。操作完成后,它会将 socket01 的 AE_WRITABLE 事件与命令回复处理器关联

如果此时客户端准备好接收返回结果了,那么 Redis 中的 socket01 会产生一个 AE_WRITABLE 事件,同样压入队列中,事件分派器找到相关联的命令回复处理器,由命令回复处理器对 socket01 输入本次操作的一个结果,比如 ok ,之后解除 socket01 的 AE_WRITABLE 事件与命令回复处理器的关联。

这样便完成了一次通信。

14 Redis缓存预热 && 缓存热点key

14.1 缓存预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。用户直接查询到事先被预热的缓存数据。

缓存预热解决方案:

  • 直接写个缓存刷新页面,上线时手工操作一下;
  • 如果数据量不大,可以在项目启动的时候自动进行加载
  • 定时刷新缓存

14.2 缓存热点key

缓存中的一个Key(比如一个促销商品),在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期,一般都会从后端database中加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方案对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁。其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询 。

15 Redis缓存降级

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。

缓存降级的最终目的是保证核心服务可用,即使是有损的(至少要保证数据库不被压垮,系统服务可用)。而且有些服务是无法降级的(如加入购物车、结算)。

在进行降级之前要对系统进行梳理,看看系统是不是可以丢卒保帅,从而梳理出哪些必须誓死保护,哪些可降级。

比如可以参考日志级别设置预案:

  • 一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级
  • 警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警,可以返回兜底数据,如:网络繁忙,请稍后重试,或者网络开小差了…等等
  • 错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级
  • 严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级

服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户。

16 热点数据和冷数据

热点数据,缓存才有价值。对于热点数据,比如我们的产品中心,生日祝福模块,状态字典等,缓存以后可能读取数十万次。再举个例子,某导航产品,我们将导航信息,缓存以后可能读取数百万次。

对于冷数据而言,大部分数据可能还没有再次访问到就已经被挤出内存,不仅占用内存,而且价值不大。频繁修改的数据,看具体情况考虑是否使用缓存。

数据更新前至少读取两次,缓存才有意义,这个是最基本的策略,如果缓存还没有起作用就失效了,那就没有太大价值了。

那存不存在,修改频率很高,但是又不得不考虑缓存的场景呢?有!比如,这个读取接口对数据库的压力很大,但是又是热点数据,这个时候就需要考虑通过缓存手段,减少数据库的压力,比如我们的某助手产品的,点赞数,收藏数,分享数等是非常典型的热点数据,但是又不断变化,此时就需要将数据同步保存到Redis缓存,减少数据库压力。

17 如何保证缓存与数据库双写时的数据一致性?

你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题?

一般来说,就是如果你的系统不是严格要求缓存+数据库必须一致性的话,缓存可以稍微的跟数据库偶尔有不一致的情况,最好不要做这个方案,读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况。

串行化之后,就会导致系统的吞吐量会大幅度的降低,用比正常情况下多几倍的机器去支撑线上的一个请求。

还有一种方式就是可能会暂时产生不一致的情况,但是发生的几率特别小,就是先更新数据库,然后再删除缓存。
具体的部分,下次在介绍,更新中…

18 Redis 和 Memcached 有啥区别?

  • Redis 支持复杂的数据结构
    Redis 相比 Memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作。如果需要缓存能够支持更复杂的结构和操作, Redis 会是不错的选择。

  • Redis 原生支持集群模式
    在 Redis3.x 版本中,便能支持 cluster 模式,而 Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据。

  • 性能对比
    由于 Redis 只使用单核,而 Memcached 可以使用多核,所以平均每一个核上 Redis 在存储小数据时比 Memcached 性能更高。而在 100k 以上的数据中,Memcached 性能要高于 Redis。虽然 Redis 最近也在存储大数据的性能上进行优化,但是比起 Memcached,还是稍有逊色。

19 生产环境中的 Redis 是怎么部署的?

  • 面试官心理分析
    看看你了解不了解你们公司的 Redis 生产集群的部署架构,如果你不了解,那么确实你就很失职了,你的 Redis 是主从架构?集群架构?用了哪种集群方案?有没有做高可用保证?有没有开启持久化机制确保可以进行数据恢复?线上 Redis 给几个 G 的内存?设置了哪些参数?压测后你们 Redis 集群承载多少 QPS?

    兄弟,这些你必须是门儿清的,否则你确实是没好好思考过。

  • 面试题剖析
    Redis cluster,10 台机器,5 台机器部署了 Redis 主实例,另外 5 台机器部署了 Redis 的从实例,每个主实例挂了一个从实例,5 个节点对外提供读写服务,每个节点的读写高峰 QPS 可能可以达到每秒 5 万,5 台机器最多是 25 万读写请求每秒。

    机器是什么配置?32G 内存+ 8 核 CPU + 1T 磁盘,但是分配给 Redis 进程的是 10g 内存,一般线上生产环境,Redis 的内存尽量不要超过 10g,超过 10g 可能会有问题。

    5 台机器对外提供读写,一共有 50g 内存。

    因为每个主实例都挂了一个从实例,所以是高可用的,任何一个主实例宕机,都会自动故障迁移,Redis 从实例会自动变成主实例继续提供读写服务。

    你往内存里写的是什么数据?每条数据的大小是多少?商品数据,每条数据是 10kb。100 条数据是 1mb,10 万条数据是 1g。常驻内存的是 200 万条商品数据,占用内存是 20g,仅仅不到总内存的 50%。目前高峰期每秒就是 3500 左右的请求量。

    其实大型的公司,会有基础架构的 team 负责缓存集群的运维。

20 如何保证 redis 的高并发和高可用?

redis 的主从复制原理能介绍一下么?redis 的哨兵原理能介绍一下么?

如果你用 redis 缓存技术的话,肯定要考虑如何用 redis 来加多台机器,保证 redis 是高并发的,还有就是如何让 redis 保证自己不是挂掉以后就直接死掉了,即 redis 高可用。

redis 实现高并发主要依靠主从架构,一主多从,一般来说,很多项目其实就足够了,单主用来写入数据,单机几万 QPS,多从用来查询数据,多个从实例可以提供每秒 10w 的 QPS。

如果想要在实现高并发的同时,容纳大量的数据,那么就需要 redis 集群,使用 redis 集群之后,可以提供每秒几十万的读写并发。

redis 高可用,如果是做主从架构部署,那么加上哨兵就可以了,就可以实现,任何一个实例宕机,可以进行主备切换。

更新中…

参考资料链接:
https://github.com/doocs/advanced-java
https://zhuanlan.zhihu.com/p/134225409

写博客是为了记住自己容易忘记的东西,另外也是对自己工作的总结,希望尽自己的努力,做到更好,大家一起努力进步!

如果有什么问题,欢迎大家评论,一起探讨,代码如有问题,欢迎各位大神指正!

给自己的梦想添加一双翅膀,让它可以在天空中自由自在的飞翔!

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值