面试官问我Redis集群,我真的是
面试官:聊下Redis的分片集群,先聊 Redis Cluster好咯?
面试官:Redis Cluser是Redis 3.x才有的官方集群方案,这块你了解多少?
候选者:嗯,要不还是从基础讲起呗?
候选者:在前面聊Redis的时候,提到的Redis都是「单实例」存储所有的数据。
候选者:1. 主从模式下实现读写分离的架构,可以让多个从服务器承载「读流量」,但面对「写流量」时,始终是只有主服务器在抗。
候选者:2. 「纵向扩展」升级Redis服务器硬件能力,但升级至一定程度下,就不划算了。
候选者:纵向扩展意味着「大内存」,Redis持久化时的"成本"会加大(Redis做RDB持久化,是全量的,fork子进程时有可能由于使用内存过大,导致主线程阻塞时间过长)
候选者:所以,「单实例」是有瓶颈的

候选者:「纵向扩展」不行,就「横向扩展」呗。
候选者:用多个Redis实例来组成一个集群,按照一定的规则把数据「分发」到不同的Redis实例上。当集群所有的Redis实例的数据加起来,那这份数据就是全的
候选者:其实就是「分布式」的概念(:只不过,在Redis里,好像叫「分片集群」的人比较多?

候选者:从前面就得知了,要「分布式存储」,就肯定避免不了对数据进行「分发」(也是路由的意思)
候选者:从Redis Cluster讲起吧,它的「路由」是做在客户端的(SDK已经集成了路由转发的功能)
候选者:Redis Cluster对数据的分发的逻辑中,涉及到「哈希槽」(Hash Solt)的概念
候选者:Redis Cluster默认一个集群有16384个哈希槽,这些哈希槽会分配到不同的Redis实例中

候选者:至于怎么「瓜分」,可以直接均分,也可以「手动」设置每个Redis实例的哈希槽,全由我们来决定
候选者:重要的是,我们要把这16384个都得瓜分完,不能有剩余!
候选者:当客户端有数据进行写入的时候,首先会对key按照CRC16算法计算出16bit的值(可以理解为就是做hash),然后得到的值对16384进行取模
候选者:取模之后,自然就得到其中一个哈希槽,然后就可以将数据插入到分配至该哈希槽的Redis实例中
面试官:那问题就来了,现在客户端通过hash算法算出了哈希槽的位置,那客户端怎么知道这个哈希槽在哪台Redis实例上呢?
候选者:是这样的,在集群的中每个Redis实例都会向其他实例「传播」自己所负责的哈希槽有哪些。这样一来,每台Redis实例就可以记录着「所有哈希槽与实例」的关系了(:
候选者:有了这个映射关系以后,客户端也会「缓存」一份到自己的本地上,那自然客户端就知道去哪个Redis实例上操作了

面试官:那我又有问题了,在集群里也可以新增或者删除Redis实例啊,这个怎么整?
候选者:当集群删除或者新增Redis实例时,那总会有某Redis实例所负责的哈希槽关系会发生变化
候选者:发生变化的信息会通过消息发送至整个集群中,所有的Redis实例都会知道该变化,然后更新自己所保存的映射关系
候选者:但这时候,客户端其实是不感知的(:
候选者:所以,当客户端请求时某Key时,还是会请求到「原来」的Redis实例上。而原来的Redis实例会返回「moved」命令,告诉客户端应该要去新的Redis实例上去请求啦
候选者:客户端接收到「moved」命令之后,就知道去新的Redis实例请求了,并且更新「缓存哈希槽与实例之间的映射关系」
候选者:总结起来就是:数据迁移完毕后被响应,客户端会收到「moved」命令,并且会更新本地缓存

面试官:那数据还没完全迁移完呢?
候选者:如果数据还没完全迁移完,那这时候会返回客户端「ask」命令。也是让客户端去请求新的Redis实例,但客户端这时候不会更新本地缓存
面试官:了解了
面试官:说白了就是,如果集群Redis实例存在变动,由于Redis实例之间会「通讯」
面试官:所以等到客户端请求时,Redis实例总会知道客户端所要请求的数据在哪个Redis实例上
面试官:如果已经迁移完毕了,那就返回「move」命令告诉客户端应该去找哪个Redis实例要数据,并且客户端应该更新自己的缓存(映射关系)
面试官:如果正在迁移中,那就返回「ack」命令告诉客户端应该去找哪个Redis实例要数据
候选者:不愧是你...
面试官:那你知道为什么哈希槽是16384个吗?
候选者:嗯,这个。是这样的,Redis实例之间「通讯」会相互交换「槽信息」,那如果槽过多(意味着网络包会变大),网络包变大,那是不是就意味着会「过度占用」网络的带宽
候选者:另外一块是,Redis作者认为集群在一般情况下是不会超过1000个实例
候选者:那就取了16384个,即可以将数据合理打散至Redis集群中的不同实例,又不会在交换数据时导致带宽占用过多

面试官:了解了
面试官:那你知道为什么对数据进行分区在Redis中用的是「哈希槽」这种方式吗?而不是一致性哈希算法
候选者:在我理解下,一致性哈希算法就是有个「哈希环」,当客户端请求时,会对Key进行hash,确定在哈希环上的位置,然后顺时针往后找,找到的第一个真实节点
候选者:一致性哈希算法比「传统固定取模」的好处就是:如果集群中需要新增或删除某实例,只会影响一小部分的数据
候选者:但如果在集群中新增或者删除实例,在一致性哈希算法下,就得知道是「哪一部分数据」受到影响了,需要进行对受影响的数据进行迁移
面试官:嗯...
候选者:而哈希槽的方式,我们通过上面已经可以发现:在集群中的每个实例都能拿到槽位相关的信息
候选者:当客户端对key进行hash运算之后,如果发现请求的实例没有相关的数据,实例会返回「重定向」命令告诉客户端应该去哪儿请求
候选者:集群的扩容、缩容都是以「哈希槽」作为基本单位进行操作,总的来说就是「实现」会更加简单(简洁,高效,有弹性)。过程大概就是把部分槽进行重新分配,然后迁移槽中的数据即可,不会影响到集群中某个实例的所有数据。

面试官:那你了解「服务端 路由」的大致原理吗?
候选者:嗯,服务端路由一般指的就是,有个代理层专门对接客户端的请求,然后再转发到Redis集群进行处理
候选者:上次最后面试的时候,也提到了,现在比较流行的是Codis
候选者:它与Redis Cluster最大的区别就是,Redis Cluster是直连Redis实例的,而Codis则客户端直连Proxy,再由Proxy进行分发到不同的Redis实例进行处理

候选者:在Codis对Key路由的方案跟Redis Cluster很类似,Codis初始化出1024个哈希槽,然后分配到不同的Redis服务器中
候选者:哈希槽与Redis实例的映射关系由Zookeeper进行存储和管理,Proxy会通过Codis DashBoard得到最新的映射关系,并缓存在本地上
面试官:那如果我要扩容Codis Redis实例的流程是怎么样的?
候选者:简单来说就是:把新的Redis实例加入到集群中,然后把部分数据迁移到新的实例上
候选者:大概的过程就是:1.「原实例」某一个Solt的部分数据发送给「目标实例」。2.「目标实例」收到数据后,给「原实例」返回ack。3.「原实例」收到ack之后,在本地删除掉刚刚给「目标实例」的数据。4.不断循环1、2、3步骤,直至整个solt迁移完毕
候选者:Codis也是支持「异步迁移」的,针对上面的步骤2,「原实例」发送数据后,不等待「目标实例」返回ack,就继续接收客户端的请求。
候选者:未迁移完的数据标记为「只读」,不会影响到数据的一致性。如果对迁移中的数据存在「写操作」,那会让客户端进行「重试」,最后会写到「目标实例」上

候选者:还有就是,针对 bigkey,异步迁移采用了「拆分指令」的方式进行迁移,比如有个set元素有10000个,那「原实例」可能就发送10000条命令给「目标实例」,而不是一整个bigkey一次性迁移(因为大对象容易造成阻塞)
面试官:了解了。

本文总结:
分片集群诞生理由:写性能在高并发下会遇到瓶颈&&无法无限地纵向扩展(不划算)
分片集群:需要解决「数据路由」和「数据迁移」的问题
Redis Cluster数据路由:
- Redis Cluster默认一个集群有16384个哈希槽,哈希槽会被分配到Redis集群中的实例中
- Redis集群的实例会相互「通讯」,交互自己所负责哈希槽信息(最终每个实例都有完整的映射关系)
- 当客户端请求时,使用CRC16算法算出Hash值并模以16384,自然就能得到哈希槽进而得到所对应的Redis实例位置
为什么16384个哈希槽:16384个既能让Redis实例分配到的数据相对均匀,又不会影响Redis实例之间交互槽信息产生严重的网络性能开销问题
Redis Cluster 为什么使用哈希槽,而非一致性哈希算法:哈希槽实现相对简单高效,每次扩缩容只需要动对应Solt(槽)的数据,一般不会动整个Redis实例
Codis数据路由:默认分配1024个哈希槽,映射相关信息会被保存至Zookeeper集群。Proxy会缓存一份至本地,Redis集群实例发生变化时,DashBoard更新Zookeeper和Proxy的映射信息
Redis Cluster和Codis数据迁移:Redis Cluster支持同步迁移,Codis支持同步迁移&&异步迁移
- 把新的Redis实例加入到集群中,然后把部分数据迁移到新的实例上(在线)

欢迎关注我的微信公众号【Java3y】来聊聊Java面试,对线面试官系列持续更新中!

【对线面试官-移动端】系列 一周两篇持续更新中!
【对线面试官-电脑端】系列 一周两篇持续更新中!
原创不易!!求三连!!
面试官问我Redis集群,我真的是的更多相关文章
- 面试官问我redis数据类型,我回答了8种
面试官:小明呀,redis 有几种数据结构呀? 小明:8 种 面试官:那你说一下分别是什么? 小明:raw,int,ht,zipmap,linkedlist,ziplist,intset,skipli ...
- 面试官问,Redis 是单线程还是多线程?我懵了
我们平时看到介绍 Redis 的文章,都会说 Redis 是单线程的.但是我们学习的时候,比如 Redis 的 bgsave 命令,它的作用是在后台异步保存当前数据库的数据到磁盘,那既然是异步了,肯定 ...
- 【原创】那些年用过的Redis集群架构(含面试解析)
引言 今天是2019年2月12号,也就是大年初八,我接到了高中同学刘有码面试失利的消息. 他面试的时候,身份是某知名公司的小码农一枚,却因为不懂自己生产上Redis是如何部署的,导致面试失败! 人间惨 ...
- 突破Java面试-Redis集群模式的原理
1 面试题 Redis集群模式的工作原理说一下?在集群模式下,key是如何寻址的?寻址都有哪些算法?了解一致性hash吗? 2 考点分析 Redis不断在发展-Redis cluster集群模式,可以 ...
- 【转】那些年用过的Redis集群架构(含面试解析)
引言 今天是2019年2月12号,也就是大年初八,我接到了高中同学刘有码面试失利的消息. 他面试的时候,身份是某知名公司的小码农一枚,却因为不懂自己生产上Redis是如何部署的,导致面试失败! 人间惨 ...
- 面试官问我,Redis分布式锁如何续期?懵了。
前言 上一篇[面试官问我,使用Dubbo有没有遇到一些坑?我笑了.]之后,又有一位粉丝和我说在面试过程中被虐了.鉴于这位粉丝是之前肥朝的粉丝,而且周一又要开启新一轮的面试,为了回馈他长期以来的支持,所 ...
- 女朋友面试回来抱怨说会redis,面试官问了一堆redis
Redis 优缺点及特点 什么是Redis?简述它的优缺点? Redis本质上是一个Key-Value类型的内存数据库,类似MemoryCache,整个数据库统统加载在内存当中进行操作,定期通过异步操 ...
- 《吊打面试官》系列-Redis基础
你知道的越多,你不知道的越多 点赞再看,养成习惯 前言 Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行360°的刁难.作为一个在互联 ...
- 《吊打面试官》系列-Redis哨兵、持久化、主从、手撕LRU
你知道的越多,你不知道的越多 点赞再看,养成习惯 前言 Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行360°的刁难.作为一个在互联 ...
随机推荐
- 使用Stargate访问K8ssandra,Springboot整合Cassandra
1 简介 之前我们在文章<K8ssandra入门-详细记录在Linux上部署K8ssandra到Kubernetes>成功地在Ubuntu上安装了K8ssandra,现在我们来看看如何访问 ...
- gcc、g++、gdb安装
Windows安装 有闲工夫在Windows上安装g++/gcc/gdb,还不如装个虚拟机安装Linux,在Linux上安装 但是我还是要讲的 首先,需要安装MinGW,MinGW,是Minimali ...
- 阿里云服务器上在docker部署jenkins
1.查询jenkins:docker search jenkins 2.拉取jenkins镜像 docker pull jenkins/jenkins:lts 3.新建jenkins的工作目录: mk ...
- 微信小程序中路由跳转
一.是什么 微信小程序拥有web网页和Application共同的特征,我们的页面都不是孤立存在的,而是通过和其他页面进行交互,来共同完成系统的功能 在微信小程序中,每个页面可以看成是一个pageMo ...
- UE4蓝图AI角色制作(七)之追逐玩家
15.追逐玩家 现在我们的AI无法做出任何决策,它总是执行相同的决策.我们先把感知系统中的相关信息提供给AI,让AI知道如何做出决策,然后我们会修改行为树.我们首先需要创建新的黑板键,这样我们就能在行 ...
- Python设置Excel样式
前面已经详细讲解过使用Python对Excel表格进行读.写操作,本文主要讲解下使用Python设置Excel表格的样式. 深入学习请参考openpyxl官方文档: https://openpyxl. ...
- 【UE4 C++ 基础知识】<7> 容器——TSet
概述 TSet是一种快速容器类,(通常)用于在排序不重要的情况下存储唯一元素. TSet 类似于 TMap 和 TMultiMap,但有一个重要区别:TSet 是通过对元素求值的可覆盖函数,使用数据值 ...
- 【UE4 设计模式】享元模式 Flyweight Pattern
概述 描述 运用共享技术有效地支持大量细粒度对象的复用.系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用. 由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻 ...
- [Java]Sevlet
0 前言 对于Java程序员而言,Web服务器(如Tomcat)是后端开发绕不过去的坎.简单来看,浏览器发送HTTP请求给服务器,服务器处理后发送HTTP响应给浏览器. Web服务器负责对请求进行处理 ...
- LeetCode:并查集
并查集 这部分主要是学习了 labuladong 公众号中对于并查集的讲解,文章链接如下: Union-Find 并查集算法详解 Union-Find 算法怎么应用? 概述 并查集用于解决图论中「动态 ...