Redis 面霸篇:高频问题横扫核心知识点 (二)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 接上文。

Redis 主从架构数据同步


Redis 提供了主从模式,通过主从复制,将数据冗余一份复制到其他 Redis 服务器。


面试官:主从之间数据如何保证一致性?


为了保证副本数据的一致性,主从架构采用了读写分离的方式。


  • 读操作:主、从库都可以执行;


  • 写操作:主库先执行,之后将写操作同步到从库;


image.png


面试官:主从复制还有其他作用么?


  1. 故障恢复:当主节点宕机,其他节点依然可以提供服务;


  1. 负载均衡:Master 节点提供写服务,Slave 节点提供读服务,分担压力;


  1. 高可用基石:是哨兵和 cluster 实施的基础,是高可用的基石。


面试官:主从复制如何实现的?


同步分为三种情况:


  1. 第一次主从库全量复制;


  1. 主从正常运行期间的同步;


  1. 主从库间网络断开重连同步。


面试官:第一次同步怎么实现?


主从库第一次复制过程大体可以分为 3 个阶段:连接建立阶段(即准备阶段)、主库同步数据到从库阶段、发送同步期间新写命令到从库阶段


image.png


  1. 建立连接:从库会和主库建立连接,从库执行 replicaof 并发送 psync 命令并告诉主库即将进行同步,主库确认回复后,主从库间就开始同步了


  1. 主库同步数据给从库:master 执行 bgsave命令生成 RDB 文件,并将文件发送给从库,同时主库为每一个 slave 开辟一块 replication buffer 缓冲区记录从生成 RDB 文件开始收到的所有写命令。从库保存 RDB 并清空数据库再加载 RDB 数据到内存中。


  1. 发送 RDB 之后接收到的新写命令到从库:在生成 RDB 文件之后的写操作并没有记录到刚刚的 RDB 文件中,为了保证主从库数据的一致性,所以主库会在内存中使用一个叫 replication buffer 记录 RDB 文件生成后的所有写操作。并将里面的数据发送到 slave。


面试官:主从库间的网络断了咋办?断开后要重新全量复制么?


在 Redis 2.8 之前,如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大。


从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步。


增量复制:用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效


断开重连增量复制的实现奥秘就是 repl_backlog_buffer 缓冲区,不管在什么时候 master 都会将写指令操作记录在 repl_backlog_buffer 中,因为内存有限, repl_backlog_buffer 是一个定长的环形数组,如果数组内容满了,就会从头开始覆盖前面的内容


master 使用 master_repl_offset记录自己写到的位置偏移量,slave 则使用 slave_repl_offset记录已经读取到的偏移量。


image.png


当主从断开重连后,slave 会先发送 psync 命令给 master,同时将自己的 runIDslave_repl_offset发送给 master。


master 只需要把 master_repl_offsetslave_repl_offset之间的命令同步给从库即可。


增量复制执行流程如下图:


image.png


面试官:那完成全量同步后,正常运行过程中如何同步数据呢?


当主从库完成了全量复制,它们之间就会一直维护一个网络连接,主库会通过这个连接将后续陆续收到的命令操作再同步给从库,这个过程也称为基于长连接的命令传播,使用长连接的目的就是避免频繁建立连接导致的开销。


哨兵原理连环问


面试官:可以呀,知道这么多,你知道 哨兵集群原理么?


哨兵是 Redis 的一种运行模式,它专注于对 Redis 实例(主节点、从节点)运行状态的监控,并能够在主节点发生故障时通过一系列的机制实现选主及主从切换,实现故障转移,确保整个 Redis 系统的可用性


他的架构图如下:


image.png


Redis 哨兵具备的能力有如下几个:


  • 监控:持续监控 master 、slave 是否处于预期工作状态。


  • 自动切换主库:当 Master 运行故障,哨兵启动自动故障恢复流程:从 slave 中选择一台作为新 master。


  • 通知:让 slave 执行 replicaof ,与新的 master 同步;并且通知客户端与新 master 建立连接。


面试官:哨兵之间是如何知道彼此的?


哨兵与 master 建立通信,利用 master 提供发布/订阅机制发布自己的信息,比如身高体重、是否单身、IP、端口……


master 有一个 __sentinel__:hello 的专用通道,用于哨兵之间发布和订阅消息。这就好比是 __sentinel__:hello 微信群,哨兵利用 master 建立的微信群发布自己的消息,同时关注其他哨兵发布的消息


面试官:哨兵之间虽然建立连接了,但是还需要和 slave 建立连接,不然没法监控他们呀,如何知道 slave 并监控他们的?


关键还是利用 master 来实现,哨兵向 master 发送 INFO 命令, master 掌门自然是知道自己门下所有的 salve 小弟的。所以 master 接收到命令后,便将 slave 列表告诉哨兵。


哨兵根据 master 响应的 slave 名单信息与每一个 salve 建立连接,并且根据这个连接持续监控哨兵。


image.png


Cluster 集群连环炮


面试官:除了哨兵以外,还有其他的高可用手段么?


有 Cluster 集群实现高可用,哨兵集群监控的 Redis 集群是主从架构,无法很想拓展。使用 Redis Cluster 集群,主要解决了大数据量存储导致的各种慢问题,同时也便于横向拓展。


在面向百万、千万级别的用户规模时,横向扩展的 Redis 切片集群会是一个非常好的选择。


面试官:什么是 Cluster 集群?


Redis 集群是一种分布式数据库方案,集群通过分片(sharding)来进行数据管理(「分治思想」的一种实践),并提供复制和故障转移功能。


将数据划分为 16384 的 slots,每个节点负责一部分槽位。槽位的信息存储于每个节点中。


它是去中心化的,如图所示,该集群有三个 Redis 节点组成,每个节点负责整个集群的一部分数据,每个节点负责的数据多少可能不一样。


image.png


三个节点相互连接组成一个对等的集群,它们之间通过 Gossip协议相互交互集群信息,最后每个节点都保存着其他节点的 slots 分配情况。


面试官:哈希槽又是如何映射到 Redis 实例上呢?


  1. 根据键值对的 key,使用 CRC16 算法,计算出一个 16 bit 的值;


  1. 将 16 bit 的值对 16384 执行取模,得到 0 ~ 16383 的数表示 key 对应的哈希槽。


  1. 根据该槽信息定位到对应的实例。


键值对数据、哈希槽、Redis 实例之间的映射关系如下:


image.png


面试官:Cluster 如何实现故障转移?


Redis 集群节点采用 Gossip 协议来广播自己的状态以及自己对整个集群认知的改变。比如一个节点发现某个节点失联了 (PFail),它会将这条信息向整个集群广播,其它节点也就可以收到这点失联信息。


如果一个节点收到了某个节点失联的数量 (PFail Count) 已经达到了集群的大多数,就可以标记该节点为确定下线状态 (Fail),然后向整个集群广播,强迫其它节点也接收该节点已经下线的事实,并立即对该失联节点进行主从切换。


面试官:客户端又怎么确定访问的数据到底分布在哪个实例上呢?


Redis 实例会将自己的哈希槽信息通过 Gossip 协议发送给集群中其他的实例,实现了哈希槽分配信息的扩散。


这样,集群中的每个实例都有所有哈希槽与实例之间的映射关系信息。


当客户端连接任何一个实例,实例就将哈希槽与实例的映射关系响应给客户端,客户端就会将哈希槽与实例映射信息缓存在本地。


当客户端请求时,会计算出键所对应的哈希槽,再通过本地缓存的哈希槽实例映射信息定位到数据所在实例上,再将请求发送给对应的实例。


image.png


面试官:什么是 Redis 重定向机制?


哈希槽与实例之间的映射关系由于新增实例或者负载均衡重新分配导致改变了,客户端将请求发送到实例上,这个实例没有相应的数据,该 Redis 实例会告诉客户端将请求发送到其他的实例上


Redis 通过 MOVED 错误和 ASK 错误告诉客户端。


MOVED


MOVED 错误(负载均衡,数据已经迁移到其他实例上):当客户端将一个键值对操作请求发送给某个实例,而这个键所在的槽并非由自己负责的时候,该实例会返回一个 MOVED 错误指引转向正在负责该槽的节点。


同时,客户端还会更新本地缓存,将该 slot 与 Redis 实例对应关系更新正确


image.png


ASK


如果某个 slot 的数据比较多,部分迁移到新实例,还有一部分没有迁移。


如果请求的 key 在当前节点找到就直接执行命令,否则时候就需要 ASK 错误响应了。


槽部分迁移未完成的情况下,如果需要访问的 key 所在 Slot 正在从 实例 1 迁移到 实例 2(如果 key 已经不在实例 1),实例 1 会返回客户端一条 ASK 报错信息:客户端请求的 key 所在的哈希槽正在迁移到实例 2 上,你先给实例 2 发送一个 ASKING 命令,接着发发送操作命令


比如客户端请求定位到 key = 「公众号:码哥字节」的槽 16330 在实例 172.17.18.1 上,节点 1 如果找得到就直接执行命令,否则响应 ASK 错误信息,并指引客户端转向正在迁移的目标节点 172.17.18.2。


image.png


注意:ASK 错误指令并不会更新客户端缓存的哈希槽分配信息


未完待续


本篇主要将 Redis 核心内容过了一遍,涉及到数据结构、内存模型、 IO 模型、持久化 RDB 和AOF 、主从复制原理、哨兵原理、cluster 原理。


「面霸」系列会分为几篇,分别从核心原理、高可用、实战、如何避坑等方面全方位拿下 Redis。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
20天前
|
运维 NoSQL 测试技术
从一个事故中理解Redis(几乎)所有知识点
作者从一个事故中总结了Redis(几乎)所有的知识点,供大家学习。
|
6月前
|
缓存 NoSQL 定位技术
深入探索Redis:面试中必须掌握的关键知识点
深入探索Redis:面试中必须掌握的关键知识点
|
12月前
|
存储 NoSQL 测试技术
关于redis涉及的知识点,C语言如何操作redis
关于redis涉及的知识点,C语言如何操作redis
|
存储 SpringCloudAlibaba 运维
Redis高级知识点总结
在 Redis 6.0 中,非常受关注的第一个新特性就是多线程。这是因为,Redis 一直被大家熟知的就是它的单线程架构,虽然有些命令操作可以用后台线程或子进程执行(比如数据删除、快照生成、AOF 重写),但是,**从网络 IO 处理到实际的读写命令处理,都是由单个线程完成的**。随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 IO 的处理上,也就是说,单个主线程处理网络请求的速度跟不上底层网络硬件的速度
257 0
Redis高级知识点总结
|
存储 缓存 NoSQL
redis知识点
redis 知识点
80 0
|
缓存 监控 NoSQL
【Redis】Redis知识点阶段性总结 2
【Redis】Redis知识点阶段性总结
58 0
|
NoSQL Linux Redis
【Redis】Redis知识点阶段性总结 1
【Redis】Redis知识点阶段性总结
95 0
|
存储 缓存 监控
全新Redis6全部知识点,零基础入门3
全新Redis6全部知识点,零基础入门
12225 1
|
存储 缓存 NoSQL
全新Redis6全部知识点,零基础入门2
全新Redis6全部知识点,零基础入门
|
存储 缓存 JSON
全新Redis6全部知识点,零基础入门1
全新Redis6全部知识点,零基础入门