《吊打面试官》系列-Redis哨兵、持久化、主从、手撕LRU

你知道的越多,你不知道的越多java

点赞再看,养成习惯node

前言

Redis在互联网技术存储方面使用如此普遍,几乎全部的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行360°的刁难。做为一个在互联网公司面一次拿一次offer的面霸(请容许我使用一下夸张的修辞手法),战胜了无数竞争对手,每次都只能看到无数落寞的身影失望的离开,略感愧疚,在一个寂寞难耐的夜晚,我痛定思痛,决定开始写《吊打面试官》系列,但愿能帮助各位读者之后面试势如破竹,对面试官进行360°的反击,吊打问你的面试官,让一同面试的同僚瞠目结舌,疯狂收割大厂Offergit

絮叨

写这期其实比较纠结,我以前的写的比较通俗易懂,一是我都知道这些点,二是以前我在所在的电商公司对雪崩,击穿啥的还算有场景去接触。可是线上的Redis集群我实际操做经验不多,总不能在公司线上环境实践那些操做吧,因此最后看了下官网,还有一些资料(文章后面我都会贴出来),强行怼了这么篇出来。github

最近双十一小忙,周末双十一值班目测没时间写,那我是暖男呀,我不能鸽啊,就有了这一篇,下一篇迟到大家不要喷我哈,并且下一篇仍是Redis的终章仍是得构思下,不熟悉的知识点我怕漏洞多,特地让之前的大牛同事看了下,因此有啥不对的地方你们及时留言Diss我,写这篇是真的难,诺下面就是我本人某天凌晨两点的拍的视频,多动症的仔。面试

(手机上动图可能太大加载失败,点进去这里能够看看这个图redis

以前说过系列第二篇到300赞我就发第三篇算法

咋样没骗大家吧,就很枯竭,不BB了,开搞。sql

不点个赞对不起我,此次不要白嫖我!数据库


正文

上几期《吊打面试官》还没看的小伙伴能够回顾一下(明明就写了两期说的好像不少同样)!后端

你们都知道一个技术的引入方便了开发,解决了各类问题,可是也会带来对应的问题,技术是把双刃剑嘛,集群的引入也会带来不少问题,如:集群的高可用怎么保证,数据怎么同步等等,咱们话很少说,有请下一位受害者为咱们展现。

面试开始

三个大腹便便,穿着格子衬衣的中年男子,拿着三个尽是划痕的mac向你走来,看着快秃顶的头发,心想着确定是尼玛顶级架构师吧!并且仍是三个,可是还好我看过敖丙写的《吊打面试官》系列,腹有诗书气自华,根本虚都不虚好伐。

小伙子你好,以前问过了你基础知识以及一些缓存的常见几个大问题了,那你能跟我聊聊为啥Redis那么快么?

哦,帅气迷人的面试官您好,咱们能够先看一下关系型数据库跟Redis本质上的区别。

Redis采用的是基于内存的采用的是单进程单线程模型的 KV 数据库,由C语言编写,官方提供的数据是能够达到100000+的QPS(每秒内查询次数)

  • 彻底基于内存,绝大部分请求是纯粹的内存操做,很是快速。它的,数据存在内存中,相似于HashMapHashMap的优点就是查找和操做的时间复杂度都是O(1);

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

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

  • 使用多路I/O复用模型,非阻塞IO;

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

我能够问一下啥是上下文切换么?

我能够打个比方么:我记得有过一个小伙伴微信问过我上下文切换是啥,为啥可能会线程不安全,我是这么说的,就比如你看一本英文书,你看到第十页发现有个单词不会读,你加了个书签,而后去查字典,过了一会你又回来继续从书签那里读,ok到目前为止没啥问题。

若是是你一我的读确定没啥问题,可是你去查的时候,别的小伙伴好奇你在看啥他就翻了一下你的书,而后溜了,哦豁,你再看的时候就发现书不是你看的那一页了。不知道到这里为止我有没有解释清楚,以及为啥会线程不安全,就是由于你一我的怎么看都没事,可是人多了换来换去的操做一本书数据就乱了。可能个人解释很粗糙,可是道理应该是同样的。

那他是单线程的,咱们如今服务器都是多核的,那不是很浪费?

是的他是单线程的,可是,咱们能够经过在单机开多个Redis实例嘛。

既然提到了单机会有瓶颈,那大家是怎么解决这个瓶颈的?

咱们用到了集群的部署方式也就是Redis cluster,而且是主从同步读写分离,相似Mysql的主从同步,Redis cluster 支撑 N 个 Redis master node,每一个master node均可以挂载多个 slave node

这样整个 Redis 就能够横向扩容了。若是你要支撑更大数据量的缓存,那就横向扩容更多的 master 节点,每一个 master 节点就能存放更多的数据了。

哦?那问题就来了,他们之间是怎么进行数据交互的?以及Redis是怎么进行持久化的?Redis数据都在内存中,一断电或者重启不就木有了嘛?

是的,持久化的话是Redis高可用中比较重要的一个环节,由于Redis数据在内存的特性,持久化必须得有,我了解到的持久化是有两种方式的。

  • RDB:RDB 持久化机制,是对 Redis 中的数据执行周期性的持久化。
  • AOF:AOF 机制对每条写入命令做为日志,以 append-only 的模式写入一个日志文件中,由于这个模式是只追加的方式,因此没有任何磁盘寻址的开销,因此很快,有点像Mysql中的binlog

两种方式均可以把Redis内存中的数据持久化到磁盘上,而后再将这些数据备份到别的地方去,RDB更适合作冷备AOF更适合作热备,好比我杭州的某电商公司有这两个数据,我备份一份到我杭州的节点,再备份一个到上海的,就算发生没法避免的天然灾害,也不会两个地方都一块儿挂吧,这灾备也就是异地容灾,地球毁灭他没办法。

tip:两种机制所有开启的时候,Redis在重启的时候会默认使用AOF去从新构建数据,由于AOF的数据是比RDB更完整的。

那这两种机制各自优缺点是啥?

我先说RDB

优势:

他会生成多个数据文件,每一个数据文件分别都表明了某一时刻Redis里面的数据,这种方式,有没有以为很适合作冷备,完整的数据运维设置定时任务,定时同步到远端的服务器,好比阿里的云服务,这样一旦线上挂了,你想恢复多少分钟以前的数据,就去远端拷贝一份以前的数据就行了。

RDBRedis的性能影响很是小,是由于在同步数据的时候他只是fork了一个子进程去作持久化的,并且他在数据恢复的时候速度比AOF来的快。

缺点:

RDB都是快照文件,都是默认五分钟甚至更久的时间才会生成一次,这意味着你此次同步到下次同步这中间五分钟的数据都极可能所有丢失掉。AOF则最多丢一秒的数据,数据完整性上高下立判。

还有就是RDB在生成数据快照的时候,若是文件很大,客户端可能会暂停几毫秒甚至几秒,你公司在作秒杀的时候他恰好在这个时候fork了一个子进程去生成一个大快照,哦豁,出大问题。

咱们再来讲说AOF

优势:

上面提到了,RDB五分钟一次生成快照,可是AOF是一秒一次去经过一个后台的线程fsync操做,那最多丢这一秒的数据。

AOF在对日志文件进行操做的时候是以append-only的方式去写的,他只是追加的方式写数据,天然就少了不少磁盘寻址的开销了,写入性能惊人,文件也不容易破损。

AOF的日志是经过一个叫很是可读的方式记录的,这样的特性就适合作灾难性数据误删除的紧急恢复了,好比公司的实习生经过flushall清空了全部的数据,只要这个时候后台重写还没发生,你立刻拷贝一份AOF日志文件,把最后一条flushall命令删了就完事了。

tip:我说的命令大家别真去线上系统操做啊,想试去本身买的服务器上装个Redis试,别到时候来讲,敖丙真是个渣男,害我把服务器搞崩了,Redis官网上的命令都去看看,不要乱试!!!

缺点:

同样的数据,AOF文件比RDB还要大。

AOF开启后,Redis支持写的QPS会比RDB支持写的要低,他不是每秒都要去异步刷新一第二天志嘛fsync,固然即便这样性能仍是很高,我记得ElasticSearch也是这样的,异步刷新缓存区的数据去持久化,为啥这么作呢,不直接来一条怼一条呢,那我会告诉你这样性能可能低到没办法用的,你们能够思考下为啥哟。

那二者怎么选择?

小孩子才作选择,我全都要,你单独用RDB你会丢失不少数据,你单独用AOF,你数据恢复没RDB来的快,真出何时第一时间用RDB恢复,而后AOF作数据补全,真香!冷备热备一块儿上,才是互联网时代一个高健壮性系统的王道。

看不出来年纪轻轻有点东西的呀,对了我听你提到了高可用,Redis还有其余保证集群高可用的方式么?

!!!晕 本身给本身埋个坑(实际上是明早就准备好了,故意抛出这个词等他问,就怕他不问)。

伪装思考一会(不要过久,省得觉得你真的不会),哦我想起来了,还有哨兵集群sentinel

哨兵必须用三个实例去保证本身的健壮性的,哨兵+主从并不能保证数据不丢失,可是能够保证集群的高可用

为啥必需要三个实例呢?咱们先看看两个哨兵会咋样。

master宕机了 s1和s2两个哨兵只要有一个认为你宕机了就切换了,而且会选举出一个哨兵去执行故障,可是这个时候也须要大多数哨兵都是运行的。

那这样有啥问题呢?M1宕机了,S1没挂那实际上是OK的,可是整个机器都挂了呢?哨兵就只剩下S2个裸屌了,没有哨兵去容许故障转移了,虽然另一个机器上还有R1,可是故障转移就是不执行。

经典的哨兵集群是这样的:

M1所在的机器挂了,哨兵还有两个,两我的一看他不是挂了嘛,那咱们就选举一个出来执行故障转移不就行了。

暖男我,小的总结下哨兵组件的主要功能:

  • 集群监控:负责监控 Redis master 和 slave 进程是否正常工做。

  • 消息通知:若是某个 Redis 实例有故障,那么哨兵负责发送消息做为报警通知给管理员。

  • 故障转移:若是 master node 挂掉了,会自动转移到 slave node 上。

  • 配置中心:若是故障转移发生了,通知 client 客户端新的 master 地址。

我记得你还提到了主从同步,能说一下主从之间的数据怎么同步的么?

面试官您的记性可真是一级棒呢,我都要忘了你还记得,我特么谢谢你,提到这个,就跟我前面提到的数据持久化的RDBAOF有着比密切的关系了。

我先说下为啥要用主从这样的架构模式,前面提到了单机QPS是有上限的,并且Redis的特性就是必须支撑读高并发的,那你一台机器又读又写,这谁顶得住啊,不当人啊!可是你让这个master机器去写,数据同步给别的slave机器,他们都拿去读,分发掉大量的请求那是否是好不少,并且扩容的时候还能够轻松实现水平扩容。

回归正题,他们数据怎么同步的呢?

你启动一台slave 的时候,他会发送一个psync命令给master ,若是是这个slave第一次链接到master,他会触发一个全量复制。master就会启动一个线程,生成RDB快照,还会把新的写请求都缓存在内存中,RDB文件生成后,master会将这个RDB发送给slave的,slave拿到以后作的第一件事情就是写进本地的磁盘,而后加载进内存,而后master会把内存里面缓存的那些新命名都发给slave。

数据传输的时候断网了或者服务器挂了怎么办啊?

传输过程当中有什么网络问题啥的,会自动重连的,而且链接以后会把缺乏的数据补上的。

你们须要记得的就是,RDB快照的数据生成的时候,缓存区也必须同时开始接受新请求,否则你旧的数据过去了,你在同步期间的增量数据咋办?是吧?

那说了这么多你能说一下他的内存淘汰机制么,来手写一下LRU代码?

手写LRU?你是否是想直接跳起来讲一句:Are U F**k Kidding me?

这个问题是我在蚂蚁金服三面的时候亲身被问过的问题,不知道你们有没有被怼到过这个问题。

Redis的过时策略,是有按期删除+惰性删除两种。

按期好理解,默认100s就随机抽一些设置了过时时间的key,去检查是否过时,过时了就删了。

为啥不扫描所有设置了过时时间的key呢?

假如Redis里面全部的key都有过时时间,都扫描一遍?那太恐怖了,并且咱们线上基本上也都是会设置必定的过时时间的。全扫描跟你去查数据库不带where条件不走索引全表扫描同样,100s一次,Redis累都累死了。

若是一直没随机到不少key,里面不就存在大量的无效key了?

好问题,惰性删除,见名知意,惰性嘛,我不主动删,我懒,我等你来查询了我看看你过时没,过时就删了还不给你返回,没过时该怎么样就怎么样。

最后就是若是的若是,按期没删,我也没查询,那可咋整?

内存淘汰机制

官网上给到的内存淘汰机制是如下几个:

  • noeviction:返回错误当内存限制达到而且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)

  • allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。

  • volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过时集合的键,使得新添加的数据有空间存放。

  • allkeys-random: 回收随机的键使得新添加的数据有空间存放。

  • volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过时集合的键。

  • volatile-ttl: 回收在过时集合的键,而且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

    若是没有键知足回收的前提条件的话,策略volatile-lru, volatile-random以及volatile-ttl就和noeviction 差很少了。

至于LRU我也简单提一下,手写实在是太长了,你们能够去Redis官网看看,我把近视LUR效果给你们看看

tip:Redis为何不使用真实的LRU实现是由于这须要太多的内存。不过近似的LRU算法对于应用而言应该是等价的。使用真实的LRU算法与近似的算法能够经过下面的图像对比。

LRU comparison
LRU comparison

你能够看到三种点在图片中, 造成了三种带.

  • 浅灰色带是已经被回收的对象。
  • 灰色带是没有被回收的对象。
  • 绿色带是被添加的对象。
  • LRU实现的理论中,咱们但愿的是,在旧键中的第一半将会过时。RedisLRU算法则是几率的过时旧的键。

你能够看到,在都是五个采样的时候Redis 3.0比Redis 2.8要好,Redis2.8中在最后一次访问之间的大多数的对象依然保留着。使用10个采样大小的Redis 3.0的近似值已经很是接近理论的性能。

注意LRU只是个预测键将如何被访问的模型。另外,若是你的数据访问模式很是接近幂定律,大部分的访问将集中在一个键的集合中,LRU的近似算法将处理得很好。

其实在你们熟悉的LinkedHashMap中也实现了Lru算法的,实现以下:

当容量超过100时,开始执行LRU策略:将最近最少未使用的 TimeoutInfoHolder 对象 evict 掉。

真实面试中会让你写LUR算法,你可别搞原始的那个,那真TM多,写不完的,你要么怼上面这个,要么怼下面这个,找一个数据结构实现下Java版本的LRU仍是比较容易的,知道啥原理就行了。

面试结束

小伙子,你确实有点东西,HRBP会联系你的,请务必保持你的手机畅通好么?

好的谢谢面试官,面试官真好,我还想再面几回,噗此。

能回答得这么全面这么细节仍是忍不住点赞

(暗示点赞,每次都看了不点赞,大家想白嫖我么?大家好坏喲,不过我好喜欢)

总结

好了,咱们玩归玩,闹归闹,别拿面试开玩笑,我这么写是为了节目效果,你们面试请认真对待。

这一期是这期没前面好理解了对吧,我就在本身的服务器上启动了,而后再去官网看看命令一顿瞎操做的,查阅了部分资料,这里给你们推荐几本经典的Redis入门的书籍和我参考的资料。

不出意外的话这是Redis的倒数第二期,最后一期不知道写啥还没想好,我得好好想一想,加上最近不是双十一嘛得加加班,你看看开头的我,多可怜,那还不点个赞?买个服务器?不肯定下一期多久出,想早点看到更新的小伙伴能够去公众号催更,公众号提早一到两天更新。

实用推荐

对了,顺带推荐下近期很超值云服务器,初学者或者大牛均可以买来学习,搭建项目啊,服务器的各类操做呀啥的,你总不能拿公司服务器练手吧,rm-rf一用全部人都会叫你大牛的,用个人连接买最低80多一年,200三年,买了找我我返10元更便宜了,真香啊,说实话真香,这个钱不就是白*嘛,我直接用用老妈的号怼了个三年的。还有四天!!!

(服务器搭建装MysqlTomcat啥的在公众号我转载我基友Java3y的文章《手把手教你使用云服务器》中有)!

连接购买 经过个人连接购买,新用户专享价,若是不是新用户的能够用家里人的帐号购买,还有最后三天了,如今买的人去公众号加我微信返10元。

二维码购买

END

好了各位,以上就是这篇文章的所有内容了,能看到这里的人呀,都是人才,我后面会每周都更新几篇《吊打面试官》系列和Java技术栈相关的文章。若是你有什么想知道的,也能够留言给我,我一有时间就会写出来,咱们共同进步。

很是感谢靓仔/靓女您能看到这里,若是这个文章写得还不错,以为敖丙有点东西 求点赞 求关注 求分享 求留言 (对我很是有用)各位的支持和承认,就是我创做的最大动力,咱们下篇文章见!

敖丙 | 文 【原创】


每周都会持续更新《吊打面试官》系列能够关注个人公众号第一时间阅读和催更,公众号比博客提早一到两天更新,也能够在公众号回复【人才】加入人才交流群,里面都是人才长得好看说话还好听,进去就像回家了同样,就业和工做上有什么问题也能够直接滴滴我,我也是个新人,不过不影响咱们一块儿进步。

相关文章
相关标签/搜索