那一天,我被Redis主从架构支配的恐惧
面试官:要不你来讲讲你最近在看的点呗?可以拉出来一起讨论下(今天我也不知道要问什么)
候选者:最近在看「Redis」相关的内容
面试官:嗯,我记得已经问过Redis的基础和持久化了
面试官:要不你来讲讲你公司的Redis是什么架构的咯?
候选者:我前公司的Redis架构是「分片集群」,使用的是「Proxy」层来对Key进行分流到不同的Redis服务器上
候选者:支持动态扩容、故障恢复等等...
面试官:那你来聊下Proxy层的架构和基本实现原理?
候选者:抱歉,这块由中间件团队负责,具体我也没仔细看过
候选者:...
面试官:....
候选者:不过,我可以给你讲讲现有常见开源的Redis架构(:
面试官:那只能这样了,好吧,你开始吧
候选者:那我从基础讲起吧?
候选者:在之前提到了Redis有持久化机制,即便Redis重启了,可以依靠RDB或者AOF文件对数据进行重新加载
候选者:但在这时,只有一台Redis服务器存储着所有的数据,此时如果Redis服务器「暂时」没办法修复了,那依赖Redis的服务就没了
候选者:所以,为了Redis「高可用」,现在基本都会给Redis做「备份」:多启一台Redis服务器,形成「主从架构」
候选者:「从服务器」的数据由「主服务器」复制过去,主从服务器的数据是一致的
候选者:如果主服务器挂了,那可以「手动」把「从服务器」升级为「主服务器」,缩短不可用时间
面试官:那「主服务器」是如何把自身的数据「复制」给「从服务器」的呢?
候选者:「复制」也叫「同步」,在Redis使用的是「PSYNC」命令进行同步,该命令有两种模型:完全重同步和部分重同步
候选者:可以简单理解为:如果是第一次「同步」,从服务器没有复制过任何的主服务器,或者从服务器要复制的主服务器跟上次复制的主服务器不一样,那就会采用「完全重同步」模式进行复制
候选者:如果只是由于网络中断,只是「短时间」断连,那就会采用「部分重同步」模式进行复制
候选者:(假如主从服务器的数据差距实在是过大了,还是会采用「完全重同步」模式进行复制)
面试官:那「同步」的原理过程可以稍微讲下嘛?
候选者:嗯,没问题的
候选者:主服务器要复制数据到从服务器,首先是建立Socket「连接」,这个过程会干一些信息校验啊、身份校验啊等事情
候选者:然后从服务器就会发「PSYNC」命令给主服务器,要求同步(这时会带「服务器ID」RUNID和「复制进度」offset参数,如果从服务器是新的,那就没有)
候选者:主服务器发现这是一个新的从服务器(因为参数没带上来),就会采用「完全重同步」模式,并把「服务器ID」(runId)和「复制进度」(offset)发给从服务器,从服务器就会记下这些信息。
面试官:嗯...
候选者:随后,主服务器会在后台生成RDB文件,通过前面建立好的连接发给从服务器
候选者:从服务器收到RDB文件后,首先把自己的数据清空,然后对RDB文件进行加载恢复
候选者:这个过程中,主服务器也没闲着(继续接收着客户端的请求)
面试官:嗯...
候选者:主服务器把生成RDB文件「之后修改的命令」会用「buffer」记录下来,等到从服务器加载完RDB之后,主服务器会把「buffer」记录下的命令都发给从服务器
候选者:这样一来,主从服务器就达到了数据一致性了(复制过程是异步的,所以数据是『最终一致性』)
面试官:嗯...
面试官:那「部分重同步」的过程呢?
候选者:嗯,其实就是靠「offset」来进行部分重同步。每次主服务器传播命令的时候,都会把「offset」给到从服务器
候选者:主服务器和从服务器都会将「offset」保存起来(如果两边的offset存在差异,那么说明主从服务器数据未完全同步)
候选者:从服务器断连之后,就会发「PSYNC」命令给主服务器,同样也会带着RUNID和offset(重连之后,这些信息还是存在的)
面试官:嗯...
候选者:主服务器收到命令之后,看RUNID是否能对得上,对得上,说明这可能以前就复制过一部分了
候选者:接着检查该「offset」是否在主服务器记录的offset还存在
候选者:(这里解释下,因为主服务器记录offset使用的是一个环形buffer,如果该buffer满了,会覆盖以前的记录)
候选者:如果找到了,那就把从缺失的一部分offer开始,把对应的修改命令发给从服务器
候选者:如果从环形buffer没找到,那只能使用「完全重同步」模式再次进行主从复制了
面试官:主从复制这块我了解了,那你说到现在,Redis主库如果挂了,你还是得「手动」将从库升级为主库啊
面试官:你知道有什么办法能做到「自动」进行故障恢复吗?
候选者:必须的啊,接下来就到了「哨兵」登场了
面试官:开始你的表演吧。
候选者:「哨兵」干的事情主要就是:监控(监控主服务器的状态)、选主(主服务器挂了,在从服务器选出一个作为主服务器)、通知(故障发送消息给管理员)和配置(作为配置中心,提供当前主服务器的信息)
候选者:可以把「哨兵」当做是运行在「特殊」模式下的Redis服务器,为了「高可用」,哨兵也是集群架构的。
候选者:首先它需要跟Redis主从服务器创建对应的连接(获取它们的信息)
候选者:每个哨兵不断地用ping命令看主服务器有没有下线,如果主服务器在「配置时间」内没有正常响应,那当前哨兵就「主观」认为该主服务器下线了
候选者:其他「哨兵」同样也会ping该主服务器,如果「足够多」(还是看配置)的哨兵认为该主服务器已经下线,那就认为「客观下线」,这时就要对主服务器执行故障转移操作。
面试官:嗯...
候选者:「哨兵」之间会选出一个「领头」,选出领头的规则也比较多,总的来说就是先到先得(哪个快,就选哪个)
候选者:由「领头哨兵」对已下线的主服务器进行故障转移
面试官:嗯...
候选者:首先要在「从服务器」上挑选出一个,来作为主服务器
候选者:(这里也挑选讲究,比如:从库的配置优先级、要判断哪个从服务器的复制offset最大、RunID大小、跟master断开连接的时长...)
候选者:然后,以前的从服务器都需要跟新的主服务器进行「主从复制」
候选者:已经下线的主服务器,再次重连的时候,需要让他成为新的主服务器的从服务器
面试官:嗯...我想问问,Redis在主从复制的和故障转移的过程中会导致数据丢失吗
候选者:显然是会的,从上面的「主从复制」流程来看,这个过程是异步的(在复制的过程中:主服务器会一直接收请求,然后把修改命令发给从服务器)
候选者:假如主服务器的命令还没发完给从服务器,自己就挂掉了。这时候想要让从服务器顶上主服务器,但从服务器的数据是不全的(:
候选者:还有另一种情况就是:有可能哨兵认为主服务器挂了,但真实是主服务器并没有挂( 网络抖动),而哨兵已经选举了一台从服务器当做是主服务器了,此时「客户端」还没反应过来,还继续写向旧主服务器写数据
候选者:等到旧主服务器重连的时候,已经被纳入到新主服务器的从服务器了...所以,那段时间里,客户端写进旧主服务器的数据就丢了
候选者:上面这两种情况(主从复制延迟&&脑裂),都可以通过配置来「尽可能」避免数据的丢失
候选者:(达到一定的阈值,直接禁止主服务器接收写请求,企图减少数据丢失的风险)
面试官:要不再来聊聊Redis分片集群?
候选者:嗯...分片集群说白了就是往每个Redis服务器存储一部分数据,所有的Redis服务器数据加起来,才组成完整的数据(分布式)
候选者:要想组成分片集群,那就需要对不同的key进行「路由」(分片)
候选者:现在一般的路由方案有两种:「客户端路由」(SDK)和「服务端路由」(Proxy)
候选者:客户端路由的代表(Redis Cluster),服务端路由的代表(Codis)
面试官:要不来详细讲讲它们的区别呗?
候选者:今天有点儿困了,要不下次呗?
本文总结:
Redis实现高可用:
- AOF/RDB持久化机制
- 主从架构(主服务器挂了,手动由从服务器顶上)
- 引入哨兵机制自动故障转义
主从复制原理:
- PSYNC命令两种模式:完全重同步、部分重同步
- 完全重同步:主从服务器建立连接、主服务器生成RDB文件发给从服务器、主服务器不阻塞(相关修改命令记录至buffer)、将修改命令发给从服务器
- 部分重同步:从服务器断线重连,发送RunId和offset给主服务器,主服务器判断offset和runId,将还未同步给从服务器的offset相关指令进行发送
哨兵机制:
- 哨兵可以理解为特殊的Redis服务器,一般会组成哨兵集群
- 哨兵主要工作是监控、告警、配置以及选主
- 当主服务器发生故障时,会「选出」一台从服务器来顶上「客观下线」的服务器,由「领头哨兵」进行切换
数据丢失:
- Redis的主从复制和故障转移阶段都有可能发生数据丢失问题(通过配置尽可能避免)
欢迎关注我的微信公众号【Java3y】来聊聊Java面试,对线面试官系列持续更新中!
【对线面试官-移动端】系列 一周两篇持续更新中!
【对线面试官-电脑端】系列 一周两篇持续更新中!
原创不易!!求三连!!
那一天,我被Redis主从架构支配的恐惧的更多相关文章
- 10.Redis 主从架构
作者:中华石杉 Redis 主从架构 单机的 redis,能够承载的 QPS 大概就在上万到几万不等.对于缓存来说,一般都是用来支撑读高并发的.因此架构做成主从(master-slave)架构,一主多 ...
- redis主从架构,分片集群详解
写在前面:这篇笔记有点长,如果你认真看完,收获会不少,如果你只是忘记了相关命令,请翻到末尾. redis的简单介绍: 一个提供多种数据类类型储存,整个系统都在内存中运行的, 定期通过异步的方式把数据刷 ...
- 采用redis 主从架构的原因
如果系统的QPS超过10W+,甚至是百万以上的访问,则光是Redis是不够的,但是Redis是整个大型缓存架构中,支撑高并发的架构非常重要的环节. 首先,你的缓存中间件.缓存系统,必须能够支撑起10w ...
- redis主从架构的搭建
本项目采用主从架构,一主两从一个哨兵.在x.x.x.69上部署主节点,在70上部署从节点1和哨兵节点,在71上部署从节点2. 准备: 1.首先上传redis文件到三台linux上,目录/home/sy ...
- Redis主从架构搭建和哨兵模式(四)
一主一从,往主节点去写,在从节点去读,可以读到,主从架构就搭建成功了 1.启用复制,部署slave node wget http://downloads.sourceforge.net/tcl/tcl ...
- Redis 主从架构搭建
引言 准备搭建的是主从架构( Master/Slave )中的一主两从模式:其中 Master 为 Redis 的主服务器,主要负责写操作,两个 Slave 为 Redis 的从服务器,主要负责读操作 ...
- redis主从架构宕机问题手动解决
1 主机宕机 1. 设置端口6379是主机,端口6380是从机,全部都正常启动 2. 验证在6379写入数据,在6380也能得到数据 3. 现在将6379主机停掉,模拟主机宕机 4. 由 ...
- redis主从架构及redis集群
https://redis.io/topics/cluster-spec Redis Cluster does not support multiple databases like the stan ...
- Redis主从架构核心原理
Redis-Cluster工作原理: redis集群内置了16384个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果 ...
随机推荐
- 题解 51nod 1597 有限背包计数问题
题目传送门 题目大意 给出 \(n\),第 \(i\) 个数有 \(i\) 个,问凑出 \(n\) 的方案数. \(n\le 10^5\) 思路 呜呜呜,傻掉了... 首先想到根号分治,分别考虑 \( ...
- 文本域textarea的一个小细节
文本域代码在编写时,最好写在一行上,就像: 如果没写在一行上,如: 那么就会在后续生成的页面上输入的时候就会产生一段空白无法删除: 这是写文本框的时候的一个小细节
- 【Java虚拟机8】自定义类加载器、类加载器命名空间、类的卸载
前言 学习类加载器就一定要自己实现一个类加载器,今天就从一个简单的自定义类加载器说起. 自定义类加载器 例1 一个简单的类加载器,从一个给定的二进制名字读取一个字节码文件的内容,然后生成对应的clas ...
- UML快速概述 - All you need to know about UML
UML 是统一建模语言的缩写,就像使用一组图表来可视化软件建模的蓝图(或设计计划).它不仅可以让您彻底评估整个概念,还可以确保团队中的每个人都在同一页面上. UML 图可以组织成两个不同的组. 结 ...
- BUAA软件工程个人作业-软件案例分析
BUAA个人博客作业-软件案例分析 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 软件案例分析 我在这个课程的目标是 学习开发软件的能力 这个作 ...
- js计算精确度丢失问题解决
(function () { var calc = { /* 函数,加法函数,用来得到精确的加法结果 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显.这个函数返回较为精 ...
- VS2013快捷键及技巧 / 智能插件
复制/剪切/删除整行代码 1)如果你想复制一整行代码,只需将光标移至该行,再使用组合键"Ctrl+C"来完成复制操作,而无需选择整行. 2)如果你想剪切一整行代码,只需将光标移至该 ...
- JAVA笔记10__Math类、Random类、Arrays类/日期操作类/对象比较器/对象的克隆/二叉树
/** * Math类.Random类.Arrays类:具体查JAVA手册...... */ public class Main { public static void main(String[] ...
- 中文NER的那些事儿4. 数据增强在NER的尝试
这一章我们不聊模型来聊聊数据,解决实际问题时90%的时间其实都是在和数据作斗争,于是无标注,弱标注,少标注,半标注对应的各类解决方案可谓是百花齐放.在第二章我们也尝试通过多目标对抗学习的方式引入额外的 ...
- SpirngBoot整合Mybatis Plus多数据源
导读 有一个这样子的需求,线上正在跑的业务,由于业务发展需要,需重新开发一套新系统,等新系统开发完成后,需要无缝对接切换,当初具体设计见草图. 添加依赖 <!--lombok--> < ...