Redis分布式技术面试题有哪些

发布时间:2022-01-07 20:16:09 作者:iii
来源:亿速云 阅读:141

这篇文章主要介绍“Redis分布式技术面试题有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Redis分布式技术面试题有哪些”文章能帮助大家解决问题。

1. 分布式缓存

1.1. Redis 有什么数据类型?分别用于什么场景?

数据类型可以存储的值操作
STRING字符串、整数或者浮点数对整个字符串或者字符串的其中一部分执行操作
对整数和浮点数执行自增或者自减操作
LIST列表从两端压入或者弹出元素
读取单个或者多个元素
进行修剪,只保留一个范围内的元素
SET无序集合添加、获取、移除单个元素
检查一个元素是否存在于集合中
计算交集、并集、差集
从集合里面随机获取元素
HASH包含键值对的无序散列表添加、获取、移除单个键值对
获取所有键值对
检查某个键是否存在
ZSET有序集合添加、获取、删除元素
根据分值范围或者成员来获取元素
计算一个键的排名

What Redis data structures look like

1.2. Redis 的主从复制是如何实现的?

  1. 服务器连接主服务器,发送 SYNC 命令;

  2. 主服务器接收到 SYNC 命名后,开始执行 BGSAVE 命令生成 RDB 文件并使用缓冲区记录此后执行的所有写命令;

  3. 主服务器 BGSAVE 执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;

  4. 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;

  5. 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;

  6. 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;

1.3. Redis 的 key 是如何寻址的?

背景

(1)redis 中的每一个数据库,都由一个 redisDb 的结构存储。其中:

(2)当 redis 服务器初始化时,会预先分配 16 个数据库(该数量可以通过配置文件配置),所有数据库保存到结构 redisServer 的一个成员 redisServer.db 数组中。当我们选择数据库 select number 时,程序直接通过 redisServer.db[number] 来切换数据库。有时候当程序需要知道自己是在哪个数据库时,直接读取 redisDb.id 即可。

(3)redis 的字典使用哈希表作为其底层实现。dict 类型使用的两个指向哈希表的指针,其中 0 号哈希表(ht[0])主要用于存储数据库的所有键值,而 1 号哈希表主要用于程序对 0 号哈希表进行 rehash 时使用,rehash 一般是在添加新值时会触发,这里不做过多的赘述。所以 redis 中查找一个 key,其实就是对进行该 dict 结构中的 ht[0] 进行查找操作。

(4)既然是哈希,那么我们知道就会有哈希碰撞,那么当多个键哈希之后为同一个值怎么办呢?redis 采取链表的方式来存储多个哈希碰撞的键。也就是说,当根据 key 的哈希值找到该列表后,如果列表的长度大于 1,那么我们需要遍历该链表来找到我们所查找的 key。当然,一般情况下链表长度都为是 1,所以时间复杂度可看作 o(1)。

寻址 key 的步骤
  1. 当拿到一个 key 后,redis 先判断当前库的 0 号哈希表是否为空,即:if (dict->ht[0].size == 0)。如果为 true 直接返回 NULL。

  2. 判断该 0 号哈希表是否需要 rehash,因为如果在进行 rehash,那么两个表中者有可能存储该 key。如果正在进行 rehash,将调用一次_dictRehashStep 方法,_dictRehashStep 用于对数据库字典、以及哈希键的字典进行被动 rehash,这里不作赘述。

  3. 计算哈希表,根据当前字典与 key 进行哈希值的计算。

  4. 根据哈希值与当前字典计算哈希表的索引值。

  5. 根据索引值在哈希表中取出链表,遍历该链表找到 key 的位置。一般情况,该链表长度为 1。

  6. 当 ht[0] 查找完了之后,再进行了次 rehash 判断,如果未在 rehashing,则直接结束,否则对 ht[1]重复 345 步骤。

1.4. Redis 的集群模式是如何实现的?

Redis Cluster 是 Redis 的分布式解决方案,在 Redis 3.0 版本正式推出的。

Redis Cluster 去中心化,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

Redis Cluster 节点分配

Redis Cluster 特点:

  1. 所有的 redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带宽。

  2. 节点的 fail 是通过集群中超过半数的节点检测失效时才生效。

  3. 客户端与 redis 节点直连,不需要中间 proxy 层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。

  4. redis-cluster 把所有的物理节点映射到[0-16383] 哈希槽 (hash slot)上(不一定是平均分配),cluster 负责维护 node、slot、value。

  5. Redis 集群预分好 16384 个桶,当需要在 Redis 集群中放置一个 key-value 时,根据 CRC16(key) mod 16384 的值,决定将一个 key 放到哪个桶中。

Redis Cluster 主从模式

Redis Cluster 为了保证数据的高可用性,加入了主从模式。

一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是从主节点拉取数据备份。当这个主节点挂掉后,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉。所以,在集群建立的时候,一定要为每个主节点都添加了从节点。

Redis Sentinel

Redis Sentinel 用于管理多个 Redis 服务器,它有三个功能:

Redis 集群中应该有奇数个节点,所以至少有三个节点。

哨兵监控集群中的主服务器出现故障时,需要根据 quorum 选举出一个哨兵来执行故障转移。选举需要 majority,即大多数哨兵是运行的(2 个哨兵的 majority=2,3 个哨兵的 majority=2,5 个哨兵的 majority=3,4 个哨兵的 majority=2)。

假设集群仅仅部署 2 个节点

+----+         +----+| M1 |---------| R1 || S1 |         | S2 |+----+         +----+

如果 M1 和 S1 所在服务器宕机,则哨兵只有 1 个,无法满足 majority 来进行选举,就不能执行故障转移。

1.5. Redis 如何实现分布式锁?ZooKeeper 如何实现分布式锁?比较二者优劣?

分布式锁的三种实现:

数据库实现
Redis 实现
  1. 获取锁的时候,使用 setnx 加锁,并使用 expire 命令为锁添加一个超时时间,超过该时间则自动释放锁,锁的 value 值为一个随机生成的 UUID,通过此在释放锁的时候进行判断。

  2. 获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁。

  3. 释放锁的时候,通过 UUID 判断是不是该锁,若是该锁,则执行 delete 进行锁释放。

ZooKeeper 实现
  1. 创建一个目录 mylock;

  2. 线程 A 想获取锁就在 mylock 目录下创建临时顺序节点;

  3. 获取 mylock 目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;

  4. 线程 B 获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点;

  5. 线程 A 处理完,删除自己的节点,线程 B 监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。

实现对比

ZooKeeper 具备高可用、可重入、阻塞锁特性,可解决失效死锁问题。 但 ZooKeeper 因为需要频繁的创建和删除节点,性能上不如 Redis 方式。

1.6. Redis 的持久化方式?有什么优缺点?持久化实现原理?

RDB 快照(snapshot)

将存在于某一时刻的所有数据都写入到硬盘中。

快照的原理

在默认情况下,Redis 将数据库快照保存在名字为 dump.rdb 的二进制文件中。你可以对 Redis 进行设置, 让它在“N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动保存一次数据集。你也可以通过调用 SAVE 或者 BGSAVE,手动让 Redis 进行数据集保存操作。这种持久化方式被称为快照。

当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:

这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。

快照的优点

快照的缺点

AOF

AOF 持久化方式记录每次对服务器执行的写操作。当服务器重启的时候会重新执行这些命令来恢复原始的数据。

AOF 的原理
AOF 的优点
AOF 的缺点

1.7. Redis 过期策略有哪些?

1.8. Redis 和 Memcached 有什么区别?

两者都是非关系型内存键值数据库。有以下主要不同:

数据类型

数据持久化

分布式

内存管理机制

1.9. 为什么单线程的 Redis 性能反而优于多线程的 Memcached?

Redis 快速的原因:

  1. 绝大部分请求是纯粹的内存操作(非常快速)

  2. 采用单线程,避免了不必要的上下文切换和竞争条件

  3. 非阻塞 IO

内部实现采用 epoll,采用了 epoll+自己实现的简单的事件框架。epoll 中的读、写、关闭、连接都转化成了事件,然后利用 epoll 的多路复用特性,绝不在 io 上浪费一点时间。

2. 分布式消息队列(MQ)

2.1. 为什么使用 MQ?

2.2. 如何保证 MQ 的高可用?

数据复制
  1. 将所有 Broker 和待分配的 Partition 排序

  2. 将第 i 个 Partition 分配到第(i mod n)个 Broker 上

  3. 将第 i 个 Partition 的第 j 个 Replica 分配到第((i + j) mode n)个 Broker 上

选举主服务器

2.3. MQ 有哪些常见问题?如何解决这些问题?

MQ 的常见问题有:

  1. 消息的顺序问题

  2. 消息的重复问题

消息的顺序问题

消息有序指的是可以按照消息的发送顺序来消费。

假如生产者产生了 2 条消息:M1、M2,假定 M1 发送到 S1,M2 发送到 S2,如果要保证 M1 先于 M2 被消费,怎么做?

Redis分布式技术面试题有哪些

解决方案:

(1)保证生产者 - MQServer - 消费者是一对一对一的关系

Redis分布式技术面试题有哪些

缺陷:

(2)通过合理的设计或者将问题分解来规避。

所以从业务层面来保证消息的顺序而不仅仅是依赖于消息系统,是一种更合理的方式。

消息的重复问题

造成消息重复的根本原因是:网络不可达。

所以解决这个问题的办法就是绕过这个问题。那么问题就变成了:如果消费端收到两条一样的消息,应该怎样处理?

消费端处理消息的业务逻辑保持幂等性。只要保持幂等性,不管来多少条重复消息,最后处理的结果都一样。 保证每条消息都有唯一编号且保证消息处理成功与去重表的日志同时出现。利用一张日志表来记录已经处理成功的消息的 ID,如果新到的消息 ID 已经在日志表中,那么就不再处理这条消息。

2.4. Kafka, ActiveMQ, RabbitMQ, RocketMQ 各有什么优缺点?

Redis分布式技术面试题有哪些

3. 分布式服务(RPC)

3.1. Dubbo 的实现过程?

Redis分布式技术面试题有哪些

节点角色:

节点角色说明
Provider暴露服务的服务提供方
Consumer调用远程服务的服务消费方
Registry服务注册与发现的注册中心
Monitor统计服务的调用次数和调用时间的监控中心
Container服务运行容器

调用关系:

  1. 务容器负责启动,加载,运行服务提供者。

  2. 服务提供者在启动时,向注册中心注册自己提供的服务。

  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。

  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。

  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

3.2. Dubbo 负载均衡策略有哪些?

Random

RoundRobin

LeastActive

ConsistentHash

3.3. Dubbo 集群容错策略 ?

Redis分布式技术面试题有哪些

3.4. 动态代理策略?

Dubbo 作为 RPC 框架,首先要完成的就是跨系统,跨网络的服务调用。消费方与提供方遵循统一的接口定义,消费方调用接口时,Dubbo 将其转换成统一格式的数据结构,通过网络传输,提供方根据规则找到接口实现,通过反射完成调用。也就是说,消费方获取的是对远程服务的一个代理(Proxy),而提供方因为要支持不同的接口实现,需要一个包装层(Wrapper)。调用的过程大概是这样:

Redis分布式技术面试题有哪些

消费方的 Proxy 和提供方的 Wrapper 得以让 Dubbo 构建出复杂、统一的体系。而这种动态代理与包装也是通过基于 SPI 的插件方式实现的,它的接口就是ProxyFactory。

@SPI("javassist")public interface ProxyFactory {    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}

ProxyFactory 有两种实现方式,一种是基于 JDK 的代理实现,一种是基于 javassist 的实现。ProxyFactory 接口上定义了@SPI("javassist"),默认为 javassist 的实现。

3.5. Dubbo 支持哪些序列化协议?Hessian?Hessian 的数据结构?

  1. dubbo 序列化,阿里尚不成熟的 java 序列化实现。

  2. hessian2 序列化:hessian 是一种跨语言的高效二进制的序列化方式,但这里实际不是原生的 hessian2 序列化,而是阿里修改过的 hessian lite,它是 dubbo RPC 默认启用的序列化方式。

  3. json 序列化:目前有两种实现,一种是采用的阿里的 fastjson 库,另一种是采用 dubbo 中自已实现的简单 json 库,一般情况下,json 这种文本序列化性能不如二进制序列化。

  4. java 序列化:主要是采用 JDK 自带的 java 序列化实现,性能很不理想。

  5. Kryo 和 FST:Kryo 和 FST 的性能依然普遍优于 hessian 和 dubbo 序列化。

Hessian 序列化与 Java 默认的序列化区别?

Hessian 是一个轻量级的 remoting on http 工具,采用的是 Binary RPC 协议,所以它很适合于发送二进制数据,同时又具有防火墙穿透能力。

  1. Hessian 支持跨语言串行

  2. 比 java 序列化具有更好的性能和易用性

  3. 支持的语言比较多

3.6. Protoco Buffer 是什么?

Protocol Buffer 是 Google 出品的一种轻量 & 高效的结构化数据存储格式,性能比 Json、XML 真的强!太!多!

Protocol Buffer 的序列化 & 反序列化简单 & 速度快的原因是:

  1. 编码 / 解码 方式简单(只需要简单的数学运算 = 位移等等)

  2. 采用 Protocol Buffer 自身的框架代码 和 编译器 共同完成

Protocol Buffer 的数据压缩效果好(即序列化后的数据量体积小)的原因是:

  1. 采用了独特的编码方式,如 Varint、Zigzag 编码方式等等

  2. 采用 T - L - V 的数据存储方式:减少了分隔符的使用 & 数据存储得紧凑

3.7. 注册中心挂了可以继续通信吗?

可以。Dubbo 消费者在应用启动时会从注册中心拉取已注册的生产者的地址接口,并缓存在本地。每次调用时,按照本地存储的地址进行调用。

3.8. ZooKeeper 原理是什么?ZooKeeper 有什么用?

ZooKeeper 是一个分布式应用协调系统,已经用到了许多分布式项目中,用来完成统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等工作。

Redis分布式技术面试题有哪些

  1. 每个 Server 在内存中存储了一份数据;

  2. Zookeeper 启动时,将从实例中选举一个 leader(Paxos 协议);

  3. Leader 负责处理数据更新等操作(Zab 协议);

  4. 一个更新操作成功,当且仅当大多数 Server 在内存中成功修改数据。

3.9. Netty 有什么用?NIO/BIO/AIO 有什么用?有什么区别?

Netty 是一个“网络通讯框架”。

Netty 进行事件处理的流程。Channel是连接的通道,是 ChannelEvent 的产生者,而ChannelPipeline可以理解为 ChannelHandler 的集合。

Redis分布式技术面试题有哪些

IO 的方式通常分为几种:

在使用同步 I/O 的网络应用中,如果要同时处理多个客户端请求,或是在客户端要同时和多个服务器进行通讯,就必须使用多线程来处理。

NIO 基于 Reactor,当 socket 有流可读或可写入 socket 时,操作系统会相应的通知引用程序进行处理,应用再将流读取到缓冲区或写入操作系统。也就是说,这个时候,已经不是一个连接就要对应一个处理线程了,而是有效的请求,对应一个线程,当连接没有数据时,是没有工作线程来处理的。

与 NIO 不同,当进行读写操作时,只须直接调用 API 的 read 或 write 方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入 read 方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将 write 方法传递的流写入完毕时,操作系统主动通知应用程序。 即可以理解为,read/write 方法都是异步的,完成后会主动调用回调函数。

3.10. 为什么要进行系统拆分?拆分不用 Dubbo 可以吗?

系统拆分从资源角度分为:应用拆分和数据库拆分。

从采用的先后顺序可分为:水平扩展、垂直拆分、业务拆分、水平拆分。

Redis分布式技术面试题有哪些

是否使用服务依据实际业务场景来决定。

当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。

当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。

3.11. Dubbo 和 Thrift 有什么区别?

关于“Redis分布式技术面试题有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注亿速云行业资讯频道,小编每天都会为大家更新不同的知识点。

推荐阅读:
  1. Redis经典面试题有哪些
  2. Redis有哪些高频面试题

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

redis

上一篇:大型电商分布式架构是怎样的

下一篇:Java分布式架构原理是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》