粉丝4.7万获赞30.6万

十分钟掌握 release 雪崩击穿穿透!哈喽,大家好,我是徐树,那相信大家最近呢需要跳槽面试对吧?那徐树老师呢,准备给大家去更新一些高频的面试题来给大家呢助助力。好吧,那今天呢,就来给大家讲一讲关于 release 的击穿雪崩穿透, 那这个呢,也是我们在开发高频发应用当中呢缓存会遇到的几个问题,也是面试当中呢经常会被问到的。 当然面试官他可能不会直接问你,你给我介绍一下 reds 的机床旋风穿透,他有可能会这么来问你, ok, 你在项目开发的时候用到了 reds 对吧?那你给我介绍一下,你在开发的时候有没有遇到关于 reds 的什么问题呢? 那你就可以给他介绍一下这几个问题以及呢你是怎么解决的?那徐树老师呢,会给大家结合代码的一个实战,以及呢把这个图给大家讲理论,我相信大家肯定是能够 掌握这几个问题是怎么回事以及怎么解决的。关于这个问题的详细文字版,我已经整理了一份八十万字的抓娃秘书大全笔记,放在视频的最后面,坚持看完一定对你有帮助。 ok, 那我们都知道啊, release 它主要的作用呢,是给数据库做挡箭牌的,对吧?减轻数据库的一个压力, 那在我们的正常的一个流程当中,我们的 reds 他会怎么去用呢?在这里呢,我给大家提供了一段我以前开发一个物流系统的一这样的一段尾代码,那我们正常的一个请求进来呢,我们会去调用这样的一个业务方法,对吧?根据发货单号,然后去查询物流信息, 那在这里呢?呃,我们不希望他去查询数据库,因为物流信息的查询接口,他的并发量会非常的大,或者说请求量呢,会非常的大。那这个时候呢,我们会先去缓存当中,在这里呢,我是通过 supreme data radius 去缓存当中呢,去查 查找看他是否存在,如果缓存当中有的话,我们会直接返回,对不对?那如果缓存没有的话,我们会去数据库当中进行查询,那数据库如果他有的话,我们会将数据库当中查询到的数据呢,给他设置到 red 三中,以及呢设置过期时间,对吧? 那么下次再去调用这个应用方法的时候,就能够从缓存当中查询到了,对不对?然后如果数据库也没有的话,我们通常呢会返回空,或者说掏出一个异常,那么 这是我们正常的使用 release 这样的一个流程。那大家看完这段代码你觉得有没有问题呢?那很多同学可能会觉得没毛病啊,对不对?那从逻辑上面来说,这段段啊确实没有一点毛病。但是如果我们要应对高并发这样的一个场景的话,假如说我们在 缓存当中,他的某一个 k 啊,之前非常的冷门,突然呢变成了爆款,大家有没有遇到过这种场景啊?就比如说我们之前疫情,对吧?一些口罩啊,一些这样的香水啊,突然就变成了爆款,对不对?之前呢,他一直是冷门,但是针对冷门商品呢,我们通常会给他设置过期时间, 但是这种热门商品是我们始料不及的,那这个时候呢,他会在突然的一段时间砍售着很大的一个并发量,但是这个 k 呢,他有可能就这么巧突然失效了,那这个 大的一个并发量他会怎么样?直接击穿我们的 reds 来到数据库,那么间接的呢,对我们的数据库造成一个非常大的一个压力,那么后续呢,还会将查询到的数据很多的县城啊,这里很多的县城将数据库查到的数据呢,给他设置到 reds 当中,也会造成一个没必要的一个性能的浪, 对吧?其实我们只要存一次就够了,所以说针对这样的一个问题,我们怎么解决呢?那其实我在这里给大家提供了几个解决方案。首先我们可以给这些数据呢设置成永不过期。 有同学可能会说,老师你把所有的 redis 都设置成永不过期,那我们的 redis 存储也不够用啊,对不对?那你可以这么来做啊,你可以把一些个能够预料到的热门商品呢设置成永不过期,然后把冷门商品设置成定时过期。 当然有的人又会说了,你像我们刚刚说的这种突然变成爆款的商品,我们始料不及啊,对不对?那这个时候呢,你可以写一个 的算法,就比如说他的这个访问量突然积增到某一个数量的时候,那你可以呢去给他修改过期时间为永不过期,对不对?可以通过这样的 一个思路来进行解决。那么另外一个思路呢,就是可以给他加锁来进行排队,也就是说呢,你过期我让你过期,但是这么大的一个并发量,我只让他一个进来,那么后面的其他的这些县城啊, 我让他在后面给我排着,你给我稍稍等一等,那么等我们的第一个县城进来,把这 个数据库的数据查到之后,给他放到 red 三中之后呢,你后面排队的这个县城才能进来,那么再去查 red 四就能够查到了,大概是这样的一个思路, 那么大家可以来看一下,这段尾代码我们怎么解决呢?其实就是在我们之前的这个代码里面啊,给他加了一个同步锁,好吧,那么这样的话,我们就能够保证当大病发的请求过来,如果他从 v d 三中的数据每 没有查到,也就是等于闹的话,我们给他加一个同步锁,那么这个时候就只有一个县城他能够进来,其他的这些县城你阻塞在外面,那么第一个县城进来之后呢?去这个缓存当中再去查一遍没有,对不对?那这个为什么要再查一遍呢?我待会再来说,好吧。 然后呢,在这里我们去让他数据库里面查询,那么将数据库里面查到的给他放到 red 三中,这也是我们之前一个正常流程的一个逻辑,对吧? ok, 那第一个线程将数据库当中的数据给他放到 release 之后呢?后面的线程他的锁就释放了,对不对?那么他再进来的时候,是不是会请求这一段代码 是不是就能够从 red 三中拿到数据了,对吧?那这里我们会发现,我们从 red 三中去检索这个数据呢,检索了两遍,那这个代码呢?其实就叫做双重检 检查锁,好吧,用这个双重检查锁呢,我们就可以解决这个缓存击穿的问题。当然有同学可能会说,老师,你这里不应该用分布式锁吗?干嘛用同步锁?确实,用分布式锁也是可以的,但是用这个同步锁,用这个进程锁其实也可以啊。你想一下,你的 应用可能会进行集群,你想一下你会集群多少?我就说十台吧,对不对?我就说十台。那么你用同步锁的话,最多也就是十个线程会击穿 redis, 然后来到数据库,对吧?那么这十个请求我数据库还扛不住吗? 所以说,徐树老师一项建议的是,大道至简,不要为了技术而技术。当然,你这里用这个,嗯,分部锁肯定是更完美的,对吧?但是有的同学呢,可能对分部锁不太了解,那如果想,呃,后续去听徐树老师讲解分部 锁呢,可以给徐老师点一点赞,或者在公屏上面的扣一波六。那徐老师如果看到了你们的反馈呢?我后续会更新一些关于分部锁的一些个内容。 ok, 那么这是一个点,为什么使用同步锁?好吧,这里使用同步锁呢是没有问题的。还有一个点呢,就是有同学可能会说,老师你这里使用了这个锁的话,不会使我们的这个请求性能降低吗?对不对? 那我难道以后每次请求进来,我所有的请求都变成了这个换行吗?这样不会是影响我的一个性能吗? 你要知道,我们注意看上面的这两句,正常假如说我的 redis 没有过期的话,他是不是从 redis 中拿到数据就直接走这个 s 就直接返回了呀?所以说我们百分之九十以上的这个产品呢,基本会走这两句业务逻辑 接待吗?就能够解决,对不对?只有在这个 red 突然过期了,他才会变成创行,也就是会变成我们的这个锁,对不对? 然后呢,第一个进来,后面的阻塞在外,后面的再去第二次检查就能够拿到这个数据, ok, 那么通过这种方式就能够完美的解全我们的黄盾击穿, ok, 那我们 再来看一下另外一个问题啊,那缓存雪崩是咋回事呢?他跟我们之前的击穿相比啊,击穿是某一个热点的 k 失效了,那缓存雪崩呢?他是缓存当中的这些 k 呢集中的过期了, 那么这样就会导致什么样的?假如我的系统并发量高,那么这些请求他都会击穿我的这个 redis, 从而呢打到我的数据库。你想一下,这么庞大的一个请求,这么多的一个 redis 的数据集中 过去了,全部打到我的数据库,我数据库能扛住吗?所以说我的这个数据库呢,有可能就会挂掉,那么数据库挂掉了,有可能呢就会导致我整个应用都不可用,从而呢导致我系统的一个血崩,这就是所谓的一个缓存血崩, 那么缓存血功的主要原因我该说了,就是因为缓存的集中过期,这是一个原因,好吧,那么第二个原因呢?是缓存有可能服务器挂掉了, 估计挂掉了,那么我里面的缓存都不行了,肯定就直接呢打到我手机库,所以说呢,这两种情况都会导致缓存血红,进而呢造成我系统的血红, 这种情况怎么解决呢?很简单,只需要在我们之前击穿的这个解决方案上面呢,给他随加一个随机失效时间,当然这只是针对第一个问题,也就是集中失效的一个 解决方案。你不是集中失效吗?我不让你集中失效呗,对不对?我只需要给你加上随机的这样的一个失效时间,不就搞定了吗?对不对?非常的简单啊。那么还有一种解决方案,主主要呢是针对这个淡季了,淡季了,没办法,你只能提前 给 redis 做好集群,做好这个,呃,烧冰模式对不对?挂掉了,另外一个补上, 呃,然后还有一种情况下呢,就是我们这个服务器断电了,对不对?那这种时候呢,你就得提前做好栽备,对吧?做好多机房,一个机房挂掉了,马上切换到另外一个地方的机房, 这都是属于呃, release 在之前就要做好的一些高可用的,呃部署, ok, 这针对我们的缓存血功。那最后一个问题呢,就是缓存穿透了, 那缓存穿透呢?其实很好理解啊,就是请求的数据呢? red 三中没有,那这个时候呢,请求数据库,那数据库呢?也没有这种现象,我们就称之为缓存的穿透。那有同学就会说,哎,老师,这种现象不是很正常吗?因为你数据都没有啊,对不对?确实啊, 假如说真的是用户按照我们程序所设计的这种方式去请求,那么都没有的话,确实很正常,但是如果大量的请求 release 跟买菜口都没有的话,那很可能就是用户的一个恶意的功绩了。 那他有可能呢,就会去比如说请求一些没有的 id, 一些复数,或者说非常大的一些 id, 他呢伪造大量的请求去攻击我们的应用,那这个时候呢,我们的系统可能就会支撑不住,然后呢挂掉,所以说这种情况非常的严重,对不对? 那我们要怎么去解决这个问题呢?其实也很简单,我们呢可以采用参数教验的方式,就比如说如果你是一些复数啊,或者说一些无效的参数啊,我就给你过滤掉。当然这种方式呢,没有办法完全的杜绝啊, 就比如说他去请求一些比较大的 id, 多大 id 才算大呢,对不对?或者说他请求的某一个 id 正好我数据都没有,那这种我们也没有办法完全的去杜绝,对不对?所以还有一种方式呢,我们可以怎么样呢?缓存空对象, 我们只需要在我们之前缓存机窗缓存血崩的基础上呢,将数据库查到的数据,我不管你有没有返回的数据,从数据库查到的数据啊,我不管你有没有,我都给你存到 red 当中去,对吧?之前呢,我们会 判断,如果这个数据他不等于呢我们才缓存到 rene 三中,那现在呢,我不管他有没有,我都给他缓存,但是记得啊,设置一个失效时间,因为就比如说 当前九九九这个 id, 他可能当前这个数据没有,但是他有可能过一段时间又添加了,对不对?所以说记得要设置过期的时间,当然你也可以设置一个随机的过期时间,又既能防雪崩,对吧?啊?然后呢又能防我们的穿透, ok, 好吧,可以缓存空对象,这种方式呢,也是最简单的,还是我那句话,大道至简,好吧,最简单的才是最有效的,那还有一种方式呢,就是使用布龙过滤器,那布龙过滤器我估计很多同学可能不知道怎么回事对不对?我在这里呢就不展开的去讲这个布龙过滤器是什么 东西了啊?那假如说同学们有兴趣听,可以在我的公屏上面呢打一波六六六好不好?然后呢点一波赞,那徐老师看到你们诉求呢,会在后续呢更新关于不容过滤器的一些内容。 ok, 那不如物理器简单来说,说白了他就是一种数据结构,这种数据结构呢,比我们以往用的 lisa 啊, set map 啊等等这些数据结构更加的高效,并且呢占用空间更少。 所以我们可以比如说把一些用户请求的不存在的 id 呢,给他放到不容过滤器当中,那么在请求的时候,我们先来到不容过滤器,如果当前请求的用户 id 是比如说负一,哎,来到不容过滤器找一遍 没有,那么去数据库找一遍,那么也没有给他缓存一个空的到波龙过滤器里面,然后呢下次用户再找的话,波龙 物理器里面就有了,直接返回空,那么这种是称之为黑名单的方式。什么是黑名单呢?黑名单就是我数据库没有的数据放到步入物理器, 那还有一种就是白名单,把这些数据库有的数据呢,给它放到不能过滤器,直接用户请求过来,如果不能过滤器有的话才能执行后续的操作,如果不能过滤器没有直接返回, 好吧,大概是一种这样的方式,那么就可以解决我们的缓存穿透。 ok, 那徐老师给大家讲了这几种方式,缓存穿透,缓存血崩,缓存击穿,那很多同学可能 记不住,对吧?其实很容易记啊,缓存击穿,其实就是你把它理解成一身防弹衣,好吧? redis, 你把它理解成防弹衣,买 cycle 呢?你理解成身体击穿呢?就说白了只是击穿了 redis, 好吧啊,并没有击穿你的身体,那么雪崩呢,就是 是直接把你给打死了好吧,整个系统都不可用,也就是大量的 reds 集中过期,或者说直接断机了,这是血崩。然后,然后呢,是我们的这个穿透,穿透呢,就是 防弹衣给你击穿了,数据库也给你击穿了,这种我们就叫做穿透, ok, 那么不同的问题呢? 还有不同的解决吗?我们希望能够记住,好吧,然后呢,你也可以把它融入到你现有的项目经验当中,把它作为你在开发当中遇到的一些问题,然后是怎么解决的?回答给面试官去听, ok, nice。

说到 release 呢,呃,面试官经常会问啊,你在哪些场景下会用到这个 release? 那么今天呢,我就用社交平台为例啊,给大家详细的分析一下啊,我们在社交平台下面有哪些地方用到 release, 以及用这些 release 以后有哪些好处? 我们都知道社交平台最重要的就是人啊,以人为主线的社交网络呢,那么就会包含很多的个人信息啊,除了我们常见的静态数据,比如说这个姓名啊,性别啊,昵称啊,毕业院校啊,城市啊等等,还有很多动态的数据, 比如说活跃的状态呀,好友啊啊,还有粉丝啊等等。那么第一个毫无疑问啊,我们可以用这个瑞丽森来缓存数据,那么频繁的数据访问啊,主页访问,好友的访问啊,都会产生很大的 io, 这是 之后呢,像个人信息这些基本的数据呢,就可以换存在我们的威利斯中。那么还有一些推荐的飞的流啊,比如说同城好友推荐啊,热门话题的推荐, 那么这些带有个性化的推荐的数据呢,就需要提前做一些这个匹配计算啊,然后呢把结果放在我们的缓存中,这样呢,需要调用的时候呢,就可以以很快的速度从缓存中捞取啊,不需要再做复查的运算。 这在大数据里面呢,有一个典型的话术啊,叫做空间化时间啊,在瑞丽词中呢,也同样适用。 那么第二个应用呢,就是数据结构方面的应用了啊,比如说我们利用 vsat 啊,来做这个排行榜,那么 vsat 呢,是为了一个比较常用的数据结构啊,我们可以直接进行排序啊,比如说我们可以用它来做这个人气排行榜啊,啊,根据点赞量啊, 它的防温量,对吧,我们可以直接做个排序哦,比起我们传统的存我们关系性数据库啊,比如说外设口哦,再去排序,再去捞取,那就省了很多的代码脚本的这个工作啊,在查询上呢,效率也更加的高效。 那么第三个呢应用呢,可以用来做这个激素器啊,比如说像个人主页浏览量啊,对吧,浏览数呢,一般是要求事实的啊,这个时候呢,每一次的浏览啊,播放啊,都需要做个加一的动作, 那么如果并发量很大啊,对于传统的观音型数据库来说呢,它的性能呢是一个挑战,那么瑞丽丝的天然是支持这个技术功能的,而且技术的性能呢也非常的好, 可以说是技术器系统的重要选择。那么第四个应用呢,可以用来做主库啊,比如说用户主页的点赞,那么状态的点赞呢,会涉及到频繁的读写啊,这个时候呢,我们可以先把 这部分数据呢放在缓存中,然后呢在数据库不忙的时候啊,通过一步的方式啊,再把这个数据呢刷到我们的数据库中,这样的话呢,就能够大大的提高数据库的性能啊,交互的响应呢,也会更加的及时,这个就是典型的读多写多的这样的一个应用场景。 以上呢就是我总结的啊,在社交平台里面啊,用的比较多的场景啊,我们可以做缓存啊,做排行榜,做接收器啊,甚至是做主库啊,大家如果有瑞丽丝在社交平台的其他应用场景啊,欢迎大家在评论区帮我补充,谢谢。

哈喽,大家好,我是大肚肚周瑜,威力士有哪些数据结构?分别有哪些典型的应用场景?好,我们来看。首先威力士中间呢,基本的数据结构有,字符串,哈西表,列表集合,有序集合。 对了,本视频的文档我已经整理好了,并且与往期内容一起汇总成了二零二三年最新家网面试文档,放在了视频的最后面,坚持看完一定对你有帮助。好,那我们继续。当然他这里指的都是我们 呃 value 的值的一个数据的结构啊,因为我们 release 它肯定是有 key value 的结构,对不对?那么我们这里指的就是 value, 它可以有哪些内容类型?好,所以呢,如果说,哎,你是字符串,那么说白了是一种最简单的数据结构了,它可以缓存某个简单的字符串,而且呢,也可以去缓存比较复杂的 字符串,反正你是字符串,那么就可以缓存。那么呃,通常情况下面,比如说我们可以去利用这种结构去实现计数器哎,然后 searching, 共享 searching 的一个 呃,就是是,就是一个 id 嘛,对不对?然后呢,包括我们的分布式 id 等等啊,所以这是用字符串我们可以去做到的事情。然后哈西表就可以通常用来存储一些对象啊,对,属性啊,就是相当于一个 k y 六的一个东西,然后呢,列表我们通常可以既可以把它当做账来使用,也可以把它当做对列 来使用啊,那么像一些微信公众号呀,一些微博等消息的牛呀,都可以通过列表来缓存,然后集合就和列表内饰,只不过呢,集合是, 嗯不能重复的啊,那么他还有一些交集、病集和差集的一些操作,从而可以实现一些我和某人共同关注,关注的人,包括朋友圈点赞的 一些功能等等。啊,有序集合,有序集合和集合的区别就是有序,对,那么我们可以针对这个数据结构里面的一些元素啊,去设置一些顺序,那么就可以很好的来实现一些排行榜的功能。所以呢,这是 redis 这个数数据结构,它所对应的一些常用的一些应用场景。

大家好,那今天呢,咱们来聊一聊面试中经常被问到的问题啊,就是如何利用 redis 来实现分布式锁啊,那么我们应该如何如何去很好的回答这道题呢啊,今天呢,我给大家一步一步的讲明白啊,相信你,嗯,考完之后呢,一定会收获不小的啊。 那我们都知道 redis 这个执行指令是原子执行的,也就是同一时刻只能执行单一指令啊,所以我们可以充分利用这个特性啊,来实现我们的封饰锁啊。 那接下来呢,咱们来看一看方案一啊,那就是用这个 set n x 命令啊,那这个指令的意思是说,当这个 k 那不存在的时候呢,才能设置这个 t y 六成功啊,那再加上这个 redis 单线程执行指令的特性呢?所以说只有 一个请求能够设置成功,那其他请求呢?都是设置失败了,那设置成功呢,就抢到了锁, ok, 那咱们来先看一看这个方案一的流程图啊, 那当多个县城都到达这个我的这个业务处理方法的时候呢,那其实多个并发县城都去 rights 之内去申请所了,那也就是执行这个 set next 命令,那其实 由于 redis 是单线程这个执行命令的,所以只会有一个线程会优先的去执行,那这里呢,咱们假设这个 线程 a, 那执行成功了,那说明当前线程 a 获得了锁,那其他线程获取锁就失败了,那其实就是满足了这个锁的互制性啊,那其他线程执行赛的 nx 命令,那都会失败,那其实是可 可以进行这个重试啊,或者是等待的,嗯,那也可以这个呃快速的失败,直接返回结果啊,那县城 a 执行自己的业务,嗯,之后呢,其实就可以删除所,那也就是释放所了,那后续其他县城呢?能够继续这个抢占所,那也就继续执行这个 set x 命令。那因为线程 a 已经删除了锁啊,所以又有其他线线程呢,可以抢占得到锁了。 ok, 那流程咱们这个分析完了啊,咱们再看一看这个代码是 怎么实现的啊?这里呢,我有一段尾代码,那咱们来看一下啊,那这里呢,我先通过这个,呃, set nx 命令呢,设置这个 lock 的值为一二三,那如果设置成功呢,则表示加速成功啊,接着呢,他会执行这个业务逻辑。那最后呢,我在这个 friendly 的这个代码框内呢,删除了这个锁啊,也就是释放锁,那如果这个 set n x, 那返回 false 呢?那说明就是加锁失败了。嗯,我们可能会这个需要重试呀,或者是快速的失败返回啊。 ok, 那这个方案说完了呢,大家可以想想这个方案,嗯,有什么问题呢?那其实呢,这个方案呢,是有这个很大的问题呢,那假如在第一步我 set nx, 我加锁成功之后,也就是在底粒的释放锁之前, 服务器挡机了,那后面释放锁操作是没有执行的啊,那么其实其他的县城此时就永远无法获取到 lock 这把锁了啊,此时就形成了死锁,因为这个锁在 reaches 内会一直存在啊,主要是因为我们在 set nx 这个指令的时候,并不能设置这个锁的国际时间啊。那我们应该如何解决这个问题呢?咱们来看一下这个改进后的方案啊,也就是 方二,那这里呢?呃,我在里面这个获取锁成功呢,之后呢,我接着用这个 xp 命令,然后这个设置了这个锁的过期时间啊,那此时这个锁在 redis 内呢,就有了这个过期的时间,那即使这个在业务呃 执行的时候,那服务出现这个档机或者其他原因,这个程序异常退出了,那锁也会在过期时间到达时候呢,自动删除啊。 ok, 那此时的方案呢?看似这个完美的解决了夫妻异常呀,或者说这个程序异常退出造成这个所谓释放的问题啊, 但是呢,还是有其他的问题呢,那咱们继续来看代码啊,那其中啊,这个 我通过这个 set n s 去设置这把锁,就是抢占这把锁,那如果这抢占锁成功呢?接着我又通过这 x here 这个命令呢,设置这个锁的估计时间啊,那其实这两个指令呢,是在扣断执行的,也就是分两次这个 网络的 io, 那请求到 redis 服务器内去执行这个命令,那如果在这两个步骤之间,你的服务器依仗退出,或者说你的服务依仗退出,服务器当机了, 那么其实在这个过期时间还是没有设置成功呢,也就说这个 lock 这把锁的过期时间还是没有设成功的,还是有一样的问题,锁这个永远不过期,那可能还是会出现死锁。 ok, 那咱们继续来这个改进方案啊,那其实我们可以将这个 set n x 和这个 xp 嗯,这两条指令啊,进行原字的执行,也就是将 set n x 和 expear 通过一次网络 io 发送给 redis, 那一次性的在 redis 服务端内,那执行完成,那中间是不能够穿插其他指形的, 那我们应该如何去做呢?这里呢,由于 redis 是支持这个在 redis 内原子的执行撸画脚本的,所以呢,咱们可以将这两个步骤 写一段这个撸啊脚本,然后将撸啊脚本发送给 redis 服务端,让 redis 服务端内原子的执行这段撸啊脚本就可以了。 ok, 那下面呢,咱们来看一下这个撸啊脚本的编写啊,那其实就是 redis call, 那第一个参数呢,就是你要执行的这个 reddis 的指令,也就是 reddis 的命令,那后面呢,就是你的 key 和 value 相关的参数,那具体的使用呢?大家可以参考这个 reddis 的 官网进行查阅啊,其实是很简单的,那咱们来先来说这个代码吧,那这里呢,我先判断这个赛德 nx 是否设置成功啊,那如果是返回的是一,那就设置成功。那接着呢,我会调用这个 这个 expear 这条指令,那设置这个 k 的过期时间,那 如果啊设置过一些成功了,那么我就返回这个一,如果设置过一时间失败了,那么我就会返回这个零,那如果第一步这个 redis 点 call 赛德 nx 执行失败了,那我也会返回这个零。 ok, 嗯,这样呢,两条指令,嗯就可以源自的在副端内进行执行了。那有的小伙伴可能会想呢,那如果 expear 指令执行失败了,那散的 n s 还是执行了? 其实这样的就是如果你的语法是没有错误的,那 redis 是可以保证你的这两条直径都会这个源自的成功的执行完毕的。那其实 redis 为了保证自己简单高效快速啊,并没有实现这个版本的回滚的操作啊。 ok, 那其实上述的这段撸啊脚本呢,还是比较麻烦的啊,那 red 后期呢,给咱们提供了一个 set 指令的扩展参数啊。 呃,用于原子的执行 set n x 和 x p r 这两条制令啊,那咱们来看一下这两条制令啊,那其中这个 p x 和 n x 那是代表的是这个国际时间啊,他只是一个单位不同的而已,那一个是毫秒,一个是秒,那后面的最后的 n x 呢,表示的就是 k 不存在的时候才能够 set 成功,那也就能保证只有一个扣端请求才能获得所,那其他扣端请求只能 等待其他释放所才能够去获取所啊。 ok, 那下面呢,是 set 指定这个扩展参数的流程图案,那流程图内呢?其实我是将这个获取所的方式修改为了 set 这个 nx ex 方式啊,这样就能保证 k 和这个设置过之一时间呢,是是源自性的操作了。那这里我设置的国际时间是十秒啊。 ok, 那这个方案讲完了呢?嗯,其实这个方案还是有很大的问题呢,咱们继续看问题吧。 那问题一呢,就是锁释放了,嗯,业务还没有执行完啊,就是假设,咱们来看一个呃,场景啊,那假设线程 a 获取所成功,嗯,一直在这个执行他这个临界区的代码,也就是他的业务代码一直在执行那,但是十秒钟过去了,他还没有执行完,但是这时候锁 已经过期了,因为你设置的超时间是十秒钟,此时呢,现成 b 又请求过来了,显然现成现成 b 呢,是可以获得这个锁的成功的,那也开始执行这个邻居的代码,那么出现的问题就是,邻居这代码现在已经不是严格的 串形执行的了,那这就是问题所爱所在啊。那第二个问题呢,就是所被别的县城误删了啊,那假设县城 a 执行完去 释放锁,但是他不知道当前的锁可能已经是其他县城持有的了。那咱们这里再说一个场景啊,因为之前的县城 a 去释放锁之前啊,执行的业务代码的时间超过了十秒钟,那锁已经过期了,对吧?那此时这个 锁就释放了,那接着呢,现成币重新占有了锁,执行自己的业务逻辑代码, 那么此时县城 a 这个业务执行完了,开始释放自己的锁,那么他其实就是把县城 b 的锁给释放掉了,但是县城 b 临界区的业务代码可能还没有执行完呢, 这就是问题,就是所被别的县城误删了。 ok, 那么咱们来继续改进啊。那咱们先来看这个问题二啊,所被别的县城 误删的这种情况啊,嗯,咱们来看一下如何解决啊,就是咱们在设置这个 set nxex 呢,除了设置这个 锁的过期时间,还要设置一个与当前县城关联的唯一编号啊,你可以用这个 u i d 来实现啊。那主动删除锁的时候呢,其实是要判断这个编号是否与你当时设置的 这个编号也就 uid 是一致的,那如果一致,那则认为是自己设置锁,当然就可以进行相应的删除了。 ok, 那下面呢,咱们来看一下呃,这个流程图的一段伪代码啊,首先呢,我生成了一个 u i d, 那接着呢,我通过这个呃 set 的扩展命令啊,设置 log 对应的职位这个 u i d, 然后 n x, e x, 然后设置的国际时间为十五秒来保证这个原子性,通过这个 side n x, e x 来保证原子性,那如果加速成功,那么执行 业务逻辑,那最后呢,我通过这个 get 指令来获取 lock 对应的值,那如果我获取 lock 这个值和这个 uid 是相等的,那么接着呢,我就进行这个 delete 操作,也就进行删除来释放自己的锁。嗯, 这样是不看似就解决了问题呢,那其实这个代码还是有问题的,那判断是不是当前的 线程加的锁和释放锁这两个步骤呢?其实他不是一个原子操作,而是分两次网络 io 的请求到达 redis 负端进行执行的。咱们来考虑下面的情况啊,就是 如果现成 a 启动并设置锁成功了,那接着执行这个业务代码,那执行业务代码完成之后呢,查询对应的 uuid, 也就这个锁对应的 uuid。 查询之后呢,此时 cbo 让现成 a 挂起了,那么 接着这个十五秒就过去了,那现成 a 的锁过期了,那接着现成 b 启动了,那现成 b 就会设置锁成功,开始执行 自己的这个业务代码,那同时 cpu 让县城 a 恢复了,那么就会继续执行这个删除所的操作。由于之前我已经判断 他是我的锁了,对吧?那此时删除的锁是谁的锁?其实是已经是现成 b 的锁了,那锁删错了,所以我们要保证现成 a 执行获取这个锁的对比 以及到删除所必须是原字形的操作,那中间是不能穿插任何指令的,所以呢,我们要将这个过程编写成撸啊脚本,发送到 readys 段的服务段去执行,那就会原字性的执行,那中间就不会打断了。 那下边呢,就是我改进后的这个流程图啊,在看到这里的红框框呢,这里呢会执行一段这个乱脚本来保证这个操作的原子性啊,那至于这个乱脚本的代码,其实很简单啊,这里我就不再奥数了。 ok, 那咱们来,嗯,最后呢,再来看一看这个锁过期,对吧?过期已经释放了,但是业务还没有执行完,那这个问题呢,应该如何去解决啊?那有些小伙伴呢,可能认为,那咱们稍微把这个过期时间设置长一些不就可以了吗?那其 这个是不准确的啊。嗯,其实我们可以设想一下,是否可以在这个获取所的县城啊,他获取成功之后,开启一个定时的守护县城,那每隔一段时间去检查这个所在 redits 内 是否还存在,那存在呢?咱们就这个对锁的国际时间进行延长,我再调一下 inspare, 对吧?对锁进行这个 过期时间的延长呢?防止这个所这个过期的提前释放呢?那其实这种方案呢,也是这个开源框架 redison 的解决方案呢,咱们来再来看一下这个改进后的流程图案,也就是方案六, 只要县城一加锁成功,就会启动一个叫做 watch dog 看门狗,它是一个后台的守护县城啊,会每隔十秒钟检查一下锁是否存在啊,那如果县城还持有锁,那么就会不断 的延长锁这个 k 的生存时间啊。 ok, 那这样呢,这个锁的过期释放业务还没有执行完的问题就解决了,那检查这个时间的间隔呢?肯定是不能太长啊,如果比锁的失效时间还长,那锁都没了,那检查就 没有意义了啊。 ok, 那这个就是用 redis 来实现,嗯,分布式所的一个整个的一个方案啊, 从方案一到方案六啊,怎么进行一个改进啊?那其实上述 redis 分布式锁还是有一些问题的啊,问题出现在哪呢?其实我们的 redis 在线上呢,大多数都是主从或者集群这个架构部署的啊,那再进行这个分布式锁, 呃,实现的时候呢,你的锁的写入呢,会优先写入到这个 redis, master 实力呢,那此时会这个 e 步复制给这个对应的 slave 实力那但这过程中呢,一旦你的 master 发生了宕机啊,也就是说这个锁还没有来得及同步到其他的 slave, 也就是背上面去,那此时呢,这个 reddis 进行了主背切换,那 slave 呢?变为了 新的 master, 那接着就会导致呢,新的客户端来尝试枷锁的时候呢,并在新的 master 上完成了枷锁,而老的客户端也以为自己 成功的加了锁,那此时就导致多个客户端对一个风式锁完成了枷锁, 那这时系统在业务的语音上呢,一定会出现,嗯,一定的问题啊,那导致这个各种脏数据的产生啊,所以这就是这个 regis classer 或者是 master slave 架构的主从异部。呃,复制,那导致 regis 分布式锁,呃,最大的缺陷啊,就是在 master 当机的时候,那可能会导致多个客户端同时完成加锁,加锁成功啊。呃,所以说最后我来说一下我的个人观点啊。那本来呢,咱们是想用这个分布式锁来保证这个共享 资源或者你的业务,对吧?执行的串性化的来保证这个数据并发带来的数据安全问题 来保证,最后来保证这个数据的一致性。所以说,呃,咱们的分布制锁呢,应该是一个 c p 模型的,但 redis 本身呢,是一个 a p 模型,它并不是一个 c p 的。那所以利用 redis 来实现 风事所呢?个人感觉就是,嗯,有一种误区啊。那同时也欢迎大家在评论区来讨论啊。

今天呢,就跟大家讲解一下 redis 的缓存机窗缓存血崩,缓存穿透究竟是怎么一回事,并且呢我们该如何解决这几个问题? 那么首先呢,我们就需要知道 redis 和卖收口之间的一个关系,我们呢不能把他们俩呢看成是一个竞争对手的关系,而是呢要看成是兄弟呢,就整整齐齐的兄弟关系。那么正常而言,当用户发起请求的时候,是不是呢会先来到我们这个 redis 里面呢来查询数据, redis 里面没有呢,才会来到我们卖收口呢来查询数据, 查到数据之后呢,也会先更新我们这个 redis 里面,再将数据进行一个返回,也就是说呢,如果说我们需要来找我们的卖收口的一个麻烦, 是不是呢,我们就需要先通过他的好兄弟 redis 这一关,但是呢, redis 他会因为一些内部或者是外部的原因呢,就会出现一些无效把关的场景,那怎么理解呢?我们就先看第一个场景, redis 的缓存击穿,那么 redis 的缓存击穿怎么理解?那么也就是说呢,在高并发的访问下,那么一个热点数据呢,它正在扛住我们的高变发的场景,那这个时候呢,我们这一个热点 k 呢,它就突然过期了,也就是失效了, 这个时候大量的请求是不是就直接绕过了我们这个 reds, 来到了我们这个卖收口端来访问数据,那么这样呢,我们这一个数据库的压力是不是就出现一个巨增,他的一个效率呢也急剧下降, 而且呢很有可能我们这个卖手口是不是会出现一个崩溃,也就是我们这个断掉,那么整个系统呢,是不是就会出现无法使用的情况?那么针对于我们缓存机穿的这种场景,我们该如何解决呢?那么第一个方案呢就是我们设置一个合理的有效时间, 那么缓存器装他是一个热点数据呢,他就突然失效了,那么是不是我们可以针对热点数据呢设置一个合理的过 时间,甚至呢我们针对这个热点数据呢直接设置一个永不过期,这样我们是不是就可以避免因为我们这个热点数据呢他正在扛高并发的时候突然失效。那么就有小伙伴可能会想到,如果说我们一个冷门的商品,他在售卖的时候,他突然申请为了一个热门的数据, 那比如说我们之前疫情的时候,是不是我们的一个口罩或者是酒精这一些,那么我们该如何处理呢?那么这种场景呢?其实我们也可以增加一个脚本, 也就增加一个自动任务,对不对?我们来监控我们的这些商品呢,他的一个访问量,或者是呢销售量, 当他达到了一定的预值之后,那么我们的这一个自动任务呢,就将我们这一个热点数据呢延长他的一个有效时间,或者是呢直接设置为一个永不过期,那么这样是不是就可以避免我们这一个缓存期窗的场景?第二个方案呢,其实就是 使用我们这个护厕所,他其实就是避免尤其极端场景下,我们没有及时的更新或者是延长我们这个热点数据的他的一个有效时间,最终呢就出现了我们这个缓存击穿,那么这个时候呢,我们就可以使用我们这个护厕所,护厕所呢他就保证了我们的一个机器是不是只有一个线程 可以来到我们这个麦收口端呢来查询数据。那么即使你有多个机器是不是麦收口了,他也是可以支撑这一个访问量的, 这也就是第一种缓冲击穿的场景和他的一些解决方案。那接下来呢,我们再看一下第二个场景,也就是缓存血崩, 相对于我们的缓存机穿,它是热点数据失效导致的卖收口,他的一个压力剧增,那么缓存血崩呢,出现了大规模的缓存失效,或者是呢缓存档机,这样呢我们的 ready 是同样的,他是不是就放过了很多的请求,直接达到了我们这一个卖收口端,导致了卖 收口他的一个压力呢就剧增,从而呢他的性能下降,最终呢就可能出现一个崩溃的场景。而且呢如果说是我们的大规模的一个热点数据进行失效的话,是不是卖收口呢,他就压根就撑不了,直接呢就断掉了。 相对于我们这个缓存旋风呢,它其实呢也可以使用我们这个缓存机窗的一些解决方案。第一个呢就我们设置一个合理的有效时间,那么呢我们将同时失效,我们改成一个随机,是不是比如说我们三个 k, 那么第一个 k 是五分钟,第二个 k 呢是十分钟,第三个 k 呢是十五分钟, 他们是不是就是一个接连失效的,并不是同时失效,这样我们是不是也可以减少我们麦师傅在瞬间他的一个访问量,而且呢他也是可以设置一些永不过期,对不对?不过呢这是比较极端的场景,大家呢只要设置一个合理的时间呢都可以,第二个呢我们也可以使用护厕所,如果 说极端情况下呢,我们确实是出现了缓存血崩,那么最终呢,我们达到 mysocal 来查数据的这个请求量呢,并没有实际请求那么多,因为呢是不是还有大量的进程呢?他都是在等待中的,因此。


大家好,我是爱讲 java 的 king, 今天我们继续来解读大厂高并发系统设计。什么是 radis 的哨兵机制啊?之前我们讲的 radis 的主同复制,但是主同复制下面呢,有一种情况就是如果你玩主同复制的话,你会发现很多情况下面有可能你的主,你的 mass 的节点棒极了, 对不对?主节点因为出现故障了,他不能提供服务了,那么这个时候我们是不是要把从节点把它升为主节点,同时的话呢,我们还要通知我们的应用,通知我们的这一个程序,对不对?告诉我,你这个主节点他的地址已经变化了, 所以对很多的应用场景当中,我们一般来说处理这种方式都是手动的,当然这种手动的方式是没有办法接受的,因为你的系统呢,不可能说人容你在这里面进行操作,比如说五分钟,十分钟,半个小时。所以瑞迪斯呢,从二点八的 这个版本开始,他就提供了一个叫塞特内亚的哨兵机制,那么这个哨兵机制首先是什么呢? ok, 告诉同学们一下啊,这个哨兵机制就是如果你完成的是一个主同复制的模式,那么一旦他的主节点出现了故障, 不可达了,那么这个时候的话呢,我们通过哨兵可以去完成故障的检测,同时的话呢,可以完成主从的一个切换,同时的话还可以通知对应的应用,从而实现真正的高可用。 所以说呢,瑞丽斯的这一个 santa 那样哨兵机制,他可以自动完成故障的发现以及故障的转移,同时通知你的应用程序,从而真正意义上面实现高可用。 那么这一个哨兵机制呢,他其实是依赖于这一个塞特纳的这个节点,塞特纳是个什么东西呢?他也是个瑞迪斯,只是说他是一个 特殊的节点,这个节点呢,一般情况下面你要完成哨兵机制的话呢,至少要部署三个,并且是一个基数个的三个的节节点啊,并且推荐这些塞纳纳的节点,比如说塞纳纳一 三代二三,他不能部署在一台夫妻上面,这是为了确保他的高可用。如果你确保你如果部署在一台夫妻上面,那三台都挂了, 那么首先我们来看一下啊,在我这张图当中呢,我有三台三台那样服务器,然后与此同时我们有一个瑞迪斯的主从架构,有一台 master, 有两台斯莱沃一和斯莱沃二,然后的话呢,他们中间进行了复制,那么 sata 那样他的作用就是去监控 啊,他监控我们的主,监控我们的从,甚至呢,他还会监控我们相互之间的这个三层那样节点。 那么如果你要去彻底了解哨兵机制的话呢,你需要了解几种状态,比如主观下线。什么叫主观下线呢?其实就是你启动了一个塞纳纳,比如我们就站在塞纳纳啊这个阶段来看,你只要启动了他, 那么他大概会每隔一秒钟就对里面的主节点,从节点还有其他的三分内样节点去发送拼的命令,每隔一秒钟啊,发送拼的命令,做心跳检测,就是这些节点如果说超过了一个我们设定的时间 啊,比如说这个时间设置成二十秒,他没有响应的话,那么这个时候我们就会要判定这个节点就是失败的,这个节点就不可达了,所以这种行为我们把它称之为主观下线啊。从这个字面意思上面来说,他的判断就是主观的判断的,他因为 他主,他判断的时候可能存在一定的误判性,因为有可能是你这一台机器本来就不可达了,对不对?所以主观下线呢?他只能作为一个粗略的判断,他不准确,他不能作为什么故障转移的一个准确判断条件。 所以的话呢,在这个点我们还要引入其他的判断,比如一个叫做客观下线,我们刚才知道站在一个三的那二的节点,我们会发现这个主节点 mast 他主观下线了,但这个时候呢?不准确,那怎么办呢? 那这个时候我们的三特纳就会去通知其他的三特纳三特纳二,通知三特纳一,通知三特纳三,对不对?然后问他啊,你去判断一下我问的 mass 的节点,他到底是不是可答的,对不对?如果说判断的时候,我们得出的结果发现他 超过了一个客观,也就是啊,客观下线的这个数量达到了一定的前提,对不对?比如说我们刚才所说的,他如果发现,哎,我们的 mac 的节点也下降了,也下,也也没拼不到了,这个时候他数量超过了一个指定的值,比如超过了三 啊,这个纸是可以设定的,那么我们就认为这个主节点确实有问题,那这个时候该怎么办呢?这个时候我们就会要对这个节点做一个客观的下线, 因为这样得出的结论是非常明显的,就是大部分的 stnyl 节点认为你的主界面已经下线了,所以呢,大家都同意了,所以这个判断呢,就是客观的,好判断是客观的,之后我们就要做故障的转移,但是做故障的转移并不是所有的 style 节点都要参与,他只需要去 找一个,所以这里面呢,他就涉及到一个算法,叫做 raff 的算法, raff 的算法呢,他会去选举出中间的一个塞特纳服务器,比如确定是塞特纳塞对不对?他来干嘛?他来做故障的一个转移, ok, 好,一台三能量服气,做故障转。那么做这个故障转移他有什么步骤呢?首先我们选举出的这个领导者的这一个三能量,他首先会有一个重节点的一个列表 对不对?那从前的列表里面他要去确定到底是哪一个是主,所以呢,他有一个选择方案,选择方案呢,具体按照以下的优先顺序,第一个, 首先从从节点列表里面选一个作为主节点,选择方法是首先过滤到过滤掉不健康的,什么叫不健康呢?主观下线的断线的五秒钟没有 回复过我的对不对?或者是与主节点我失联,超过我们的一个参数乘以十秒的, ok, 这个呢叫做不健康,好,这是我们刚才所说的第一个过滤掉啊,然后的话还有那些没有回复聘的这些消息的节点。 然后第二个干嘛?去选择里面一个配置参数叫做 star war 啊,他们的一个优先级别最高的总结点 啊,这是我们的第二个逻辑对不对?如果说你确实也选不出怎么办?那选择复制最完整的节点,就是我们的从节点当中,那总有一个复制的最多的,所以呢,选择你最完美, 数据最多的这个节点,可以把它当做一个主节点,如果确实还是选不出的话呢,里面还有一个软 id, 那么选那个软 id 最小的节点当做他的一个主节点,所以这就是我们的 刚才所讲的选举的规则。好,选举规则之外,做完之后的话呢,我们就需要做故障的转移,其实故障的转移呢比较简单,第一步,把这个东西选完之后,那么进入第二步 第二步的话怎么办?选出的是 slove 一对不对?所以的话呢,这个地方你就要去解除重节点的身份,你原来是一个 slove 节点,我要把你变成新的 mase 节点, ok, 所以这是第二步。然后的话,第三步,我们之前的这个 slave 二认为这个主节点是这个 master 对不对?所以这个地方呢, slave r 它要变成我们刚才选出的这个 master 的新的总结点,所以要进行 第三步操作, ok, 做完第三步操作之后,同样的话呢,如果我们的 mass 的节点对不对?你经常对他关注的话,发现他故障恢复了,如如果 原来的主界点也恢复了,这个时候呢,他也会变成一个新的从界点,所以这是第四部啊,如果说没有恢复,那这个呢,就不用管。最后的话呢,当然还要通知我们的应用程序告诉我们的这个扎瓦程序告诉我们的啊,不是 k 神,哎,我们的新的这一个主界点,原来在这个 ip 地址上面 去通知下他,所以这样的话呢,就完成了一个哨兵机制,所以你可以看到啊,哨兵机制的话呢,他是一种监控机制,他可以实现故障的自动发现,也可以实现我们主节点的一个选举,同时还可以完成故障的转移。 ok, 同学们对瑞丽子的哨兵机智有没有理解?理解透的话可以给 k 老师一键三连。

red is 全称为 remote dictionary server, 是一种开源的内存数据库。它主要用于缓存和存储数据,也提供快速的数据访问能力。它也是一种高性能兼职存储系统,广泛用于各种应用程序和系统中。我们分别来说一下 red is 的特点和主要用途。 首先来说一下 reddis 的主要特点。特点一,内存数据库 reddis 的数据存储是基于内存的,这使得它非常快速,适合用作高吞吐量和低延迟的数据存储系统。特点二,键值存储 reddis 采用键值兑 t 八六的方式存储数据,你可以使用一个唯一的键来检索相应的值,这使得它非常适合用于缓存和简单的数据存储需求。特点三,持久性 redis 支持数据持久化,这意味着它可以将内存中的数据保存到磁盘上,以便再重 启后恢复数据。 red is 提供了多种持久性选项,包括快照、 snapshot 和追加文件 append only file 方式。特点四,数据结构 red is 支持多种数据结构,独自服穿列表集合、有序集合、哈西表等。这使得它不仅仅用于缓存,还可以用于更复杂的数据处理任务。 点五,发布订阅模式 redis 支持发布订阅 pops up 模式,允许应用程序之间实现消息通信以及实时事件处理。特点六,事务支持 redis 支持事务,你可以一次性执行多个命令,保证这些命令的原子性。了解完特点,我们再来了解下 redis 的主要用途。主要用途一, 分布式缓存 red is 可以用作分布式缓存,以加速访问数据的速度。它可以用于存储热门数据,减轻后端数据库的负载。主要用途二,对列系统 red is 常被用作消息对列、处理任务对列等,通过列表数据结构进行实现。主要用途三,实时计数器和排行榜 readys 可以用于实时计数器记录应用程序中的点击次数、点赞次数等,也可以生成排行榜数据。主要用途四, 缓存穿透保护 reddis 可以用于缓存穿透保护,通过在缓存中设置空值或者不容过滤器来减轻对数据库的不必要请求。总之, reddis 是一个多用途的数据存储系统, 特别适用于需要高性能、低延迟数据存储和缓存的应用程序。它在 vip 应用、实时分析、对列处理、绘画、存储等各种场景中都有广泛的应用,你了解了吗?

一个工作了五年的小伙伴来私信我啊,他说他去京东面试,前面项目部分和应用技术部分回答都挺好的, 可是面试官看我这么厉害,就开始在问题上加码,不断问我技术的原理,前面我都能一一应对,直到 遇到一个绝杀题,啊。维利斯内存淘汰算法和原理是什么?虽然啊,他说最后拿到了一个月薪三十 k 的 over, 但是比较遗憾在这个问题上没有回答好。好吧,对这个问题,我们来看看普通人和高手的回答。普通人的回答, 呃,瑞迪斯里面的内存淘汰算法,呃,我想一下啊,就是啊,我,我应该是瑞迪斯里面他有一个叫 i r u 的一个算法, 这个算法是就是,嗯,他会随机去取一些 key, 然后就是去判断啊这个 key 的一个访问频率,嗯,如果这个 key 他不经常访问的话呢,就, 就是就会把它淘汰掉,嗯,大概,对,大概属于这样一个,对,是的,嗯, 高手的回答, radis 里面的内存淘汰策略呢?是指啊,当内存的使用率达到了 max memory 的上限的时候,他的一种内存释放的一个行为。 radis 里面提供了很多种内存的淘汰算法,归纳起来呢,主要有四种,第一种是随机啊,随机移除某个 k。 第二种是 ttl 算法,就是在设置了过期时间的键里面呢,去找到更早过期时间的 k 进行有限移除。 第三个是 lru 算法,去移除最近很少使用的 key。 第四个是 lfu 算法,那么他跟 liu 的算法是类似的, liu 呢,是一种比较常见的内存淘汰算法,在雷迪斯里面,他会维护一个大小为十六的候选池, 而这个候选池里面的数据呢,会根据时间进行排序,然后呢,每一次随机抽取五个 k 放到这个候选池里面,当候选池满了以后,访问的时间间隔最大的 k 就会从候选池里面取出来淘汰掉。 通过这一个设计呢,就可以把真实的最少访问的 k 从内存里面淘汰。但是啊,这样的一种 liu 算法还是会存在一个问题,假如一个 k 很长时间没有访问,但是最近一次偶然被访问到,那么 liu 就会认为这是一个热点, k 不会被淘汰。所以在瑞迪斯四里面增加了一个 l fu 的算法,相比于 lru, lfu 呢,去增加了访问频率这样一个纬度来统计数据的热点情况。 lfu 的主要设计是使用了两个双向列表去形成一个二维的双向列表,一个是用来保存访问频率,另一个是用来保存访问频率相同的所有的元素。 当添加元素的时候啊,访问频次默认为一,于是找到相同频次的节点,然后添加到相同的频率节点对应的双向列表的头部。 当元素被访问的时候呢,就会增加对应 k 的访问频率,并且把当前访问的节点移动到下一个频次的节点。 当然啊,有可能会出现某个数据前期的访问次数很多,然后后续就一直不使用了。如果单纯按照这样的一个访问频次来进行淘汰的话,那么这个 k 就很难被淘汰掉。所以啊,在 l f u 的算法里面去通过了使用频率和上次访问时间来标记数据的这样一个热度,如果某个数据有毒和写,那么就增加访问的频率,如果一段时间内这个数据没有读写,那么就减少访问频率。所以啊,通过 l f u 算法改进之后,就可以真正达到非热点数据的淘汰。 当然 lfu 也有缺点,相比 liu 算法呢, lfu 增加了访问频次的一个维护以及实现的复杂度要比 liu 更高。以上就是我对这个问题的理解。 l r u 的算法使用场景还是挺多的啊,不过主要还是应用在内存管理上,比如 myc 口里面的八发破也用到了 l r u 算法,不过呢,它的实线有一点不一样,设计了冷热数据分离这样一个结构。那么在业务场景中呢, l r u 算法还可以用来解决 top ten 的一个问题,或者 在 im 类的场景中缓存最近的聊天记录等等,不能发现啊。我们去面对一个业务需求来提出技术解决方案的时候,实际上可以从很多技术的底层设计思想和各个中心建里面的设计思想去借鉴,这也是我认为为什么技术基础会决定技术人的职业高度的原因。 好的,本期人的普通人 vs 高手的面试系列的视频就到这结束了,喜欢的朋友记得点赞和收藏。另外呢,有任何技术问题记得私信我,我会在第一时间回复。我是麦克,一个工作了十四年的家务程序员,咱们下期再见。

喂,那我们来看 redis 专题的第一个问题,为什么要用 redis? 这个面试题来自拼多多啊,对应的薪资是二十 k, 对应的岗位是中级开发。 要回答这样的一个问题,我们实际上可以从 redis 的三个特性跟面试官去聊,第一个特性就是他的高性能,第二个高可靠,第三个高可拓展。 然后面说完可能会问,哪一些地方体现出来的他的高性能,哪一些又体现出来他的高可靠,哪一些又体现了高可拓展呢?那高性能主要包括了县城 线程模型、数据结构持久化以及网络框架。高可靠主要包括主重复制以及哨片机制。高可拓展主要包括数据分片以及复杂均衡。那为了呃让大家更好的去记住这三大特性,我在这里呢也给大家去画了一个 项目的流程图,比较直观的去记忆这样的一个点。首先我们可以在这里看到客户端发起一个请求到我们的服务端, 那我们理论上呢,是直接去查询数据库,对吧?直接到 d b 上去查关于这个问题的详细文字版,我已经整理了一份八十万字的专行秘书大全笔记,放在视频的最后面,坚持看完一定对你有帮助。那我这里写的是 mythog 数据库,但是大家知道直接跟 d b 磁盘去交互,一般都是毫秒级别能拿到能达到这个并发一千 啊,甚至再多一点点就已经非常不错了,对不对?那如果这个并发量还要持续的去增加怎么办呢?我们实际上可以在我们项目启动的时候给这个数据同步到我们的 release 缓存, 那这个同步啊,我们可以在启动的时候全量的一个数据,也可以是热点的一个数据做一个同步啊。然后我们如果 有数据更新的时候,也可以再呃,再去把更新的数据再给他去做一次同步,对不对?那我们这个加大缓存之后,他的并发量立马就上升了,达到十万级别。如果有一些觉得这个并发还是不够,怎么办呢?哎,这个性能还是没有达到我的要求,怎么办呢? 那这里讲的是并发啊,这个这个点主要是提高了他的一个查询的性能,对不对?那我们刚才讲到了三个特性,还有哪一些地方没有在这体现出来呢?就是我们的主丛啊,以及我们的哨兵骑士。 那这一些点就可以确保他的高可靠啊,高性能有了,高并发有了,高可靠也有了,对不对?那我们怎么样去确保高可靠?就是主虫的一个复制,如果某一台这样的一个 release 放弃了,挂掉了,没关系,我们有主虫,哎,我们有哨兵集市,可以把这个 群另外一台给他激活起来啊。我这里呢,也给大家去看一下我们这边的一个呃,给大家准备好的这样的一个专题的一个笔记啊, 像这个笔记呢?呃,有很多,我在这里啊,今天给大家讲的。呃,如果大家有需要,可以一键三连在下方留言,拿到这样的一个笔记,好不好?呃,所有的都可以分享给大家。你看上面这些应用场景,我们后面会有这样的一个题啊,然后这刚才讲到了,主要是这有三个特性。 ok, 那我们第一个面试题就给大家简单分享到这里,主要是记住三个特性,高性能、高可靠、高可拓展。