大家好,今天我们来聊聊 reddit 的 高可用集训方案,主从复制哨兵模式以及 cluster 模式这三种啊,最简单的就是主从模式, 什么意思呢?主节点承担所有的读写服务,然后成节点呢?只是一个。呃,数据同步服务,它是异步同步, 主节点的数据做一个备份节点,相当于是。但是成节点呢,也可以对外提供读服务,但是它不能提供写的服务 啊,主从他们怎么同步呢?他是利用了,其实我们上一次已经聊过这个了,是利用了一个呃二 db 以及八分这种机制来做数据同步。 那主从模式他有什么优点呢?首先是从节点呢,也他是一个全量数据,他可以承担主节点,也当做读写服务来对外提供 好。第二个就是读写分离的一个优点,呃,主键点提供写服务,从键点呢,也可以提供读的服务,那它的缺点也很明显,它无法实现自动的故障转移,就是主键点出现故障以后,你需要应用,需要手动连接存减点 来实现,我们的,相当于是个高考用吧。也是。然后再稍微复杂一下,就是哨兵模式的基础上加了一个哨兵节点, 哨兵结点是他是一个独立的一个 reds 进程,哨兵结点呢,也需要一个领导者的一个角色,所以说呢,呃,就涉及到选举,一涉及到选举呢,就是需要一个基数个数的一个哨兵结点,也就是也就是最少也有三个哨兵结点。 那哨兵这单他什么作用呢?第一个是自动故障转移,就是他会监控监听所有的主接点、存接点以及其他哨兵接点,一旦发现主接点不可用,他会选从其他的存接点选举出新的哨,新的主接点, 然后通知把这个主接的通知给客户端,然后客户端连接新的主接点,从而完成一个自动的故障转移, 然后他也会在哨兵节点之间也会选选举哨兵的一个领导者吧角色。 哨兵这个一个工作机制是什么呢?我们客户端一般都是连接的,直接连接哨兵节点, 然后哨兵节点呢,告诉客户端当前的主节点是谁,然后客户端呢,会缓存上这个主节点的地址,以后连接中都使用连接这个主节点。一旦嗯出现一个自动故障转移以后,哨兵节点会通知客户端, 就是告诉客户端我新的主节点是哪里,然后同时客户端会更新这个主节点的地址, 这就是他的一个工作机制。他的优点呢,其实也就是主从复制的一个优点基础上又加了一个自动故障转移。但是缺点呢,和主从复制的缺点也其实很相似,一就是 主节点就是这个写的操作只能落到主节点上面,就是写这个节点是没法做扩展扩展的, 这就是哨兵模式。然后还有再往复杂一些,就是我们的 cluster 机群,这个是呃真正的意义上的一个分布式高可用机群, 它的机制是什么呢?就是呃所有的 release 节点都可以同时对外提供读写服务,它的它是把呃 release 所有数据分为幺六三八四个哈希槽,然后呢,每一个 主节点分别承担这些部分哈希槽的一个数据的读写,也就是说比如一份完整的 read 数据,我们会分布在不同的哈希槽上面,也就是最终就是会分布到不同的主节点上面, 也就是说我每个主节点并不是一个完整的 read 数据,它只是一部分,然后一个主节点呢?它它还有自己的存接点,一旦这个主节点 出现故障或者不可用的时候,会选举出新的从节点作为主节点,也就是完成了一个自动的故障转移。 他对他的一个工作机制是什么呢?就是我们客户端我可以连接到任意一个主节点, 当这个他的数据的读写不在读,其实只是读写的话,因为他是利用这个哈希算法,他直接会连接到对应的节点,但是读数据呢?如果这个数据不在当前这一节点的哈希槽负责的这个哈希槽里面, 他会返回一个客户端一个末尾的一个错误,同时呢把啊这个数据所在的主接点地址告诉给客户端,然后客户端再连接正确的主接点上面,这就是拿到具体数据,这就是一个客户端和 leis 机群的一个工作机制。 他的优点是什么?除了是这个主动复制和邵斌这个优点之外呢?他还有更高的就是他实现了一个写的扩展,就是我们所有的节点都可以承担读写的一个任务,同时他的所有的副本节点也可以承担读的压力, 就是它非常方便扩展。但是它也有一个缺点,就是如果在网络不稳定,出现网络分区大面积节点不可用的时候,整个基群它也是不可用。 其实对应的刚才那个邵斌当时呢漏说了一个它的缺点,就是它也会可能会因为网络分期的原因出现一个脑裂的问题。好,这就是 radis 的 三种基群高可用模式 啊。我们在实际项目中要根据他的,我们根据我们数据的一个数据量,并发量一个,以及 团队的运维能力来选择不同的基群。一般是对于中小型项目,我们使用那个少兵模式就可以了。对于复杂一些的互联网项目,一般都是生产环节都是使用 class 模式。好,那我们今天就聊聊这里知其然,知其所以然,拜拜。
粉丝126获赞562

今天测试环境炸锅了,开发说亚哥这代码我在本地连单机 race 跑得飞起,怎么一步数到测试环境用得及群批量,结果就报错了? cross slide keys 兄弟,单机和机群底层逻辑完全不同, class 是 分片的,数据分散在不同的机器上,你用的 m get 拍不烂撸啊。如果涉及多个 key, 那 例子发现这些 key 在 不同的节点上直接拒绝执行。怎么就必须用 hash tag 把 key 加个前缀,用花括号括起来, redes 会根据花括号里的内容计算位置,强行把它们捆绑在同一台机器上才能批量操作。听好了,在 class 模式下,要么你改 k 加上 hash tag 强行勾位,要么你改代码把它们 get 拆成循环 get, 别指望 redes 会自动帮你跨机器合并数据。

你说说看,怎么就约定成数?三亿级别的用户状态,还能快速查任意时间窗口的活跃用户数?我知道 vt 是 有两个特别省内存的工具,分别是 bitmap 和 help log log 具体执行就是键对应的 key 调命令操作,其他的我也记不太清了。 各位,刚才这位面试员的回答其实存在很多问题,并没有真正解决面试官提出的核心问题。接下来我来指出他的问题, 并且补充更正,帮大家理清这个问题的完整思路。首先,我先明确面试员的回答问题所在,面试员只知道有比特 map 和 hyperlog 这两个工具,但没说清关键信息,回答太表面。具体问题有四个。第一,他没说为什么不用 vivo 最普通的存储方式,其 是普通方式存三亿用户特别费内存,根本用不了。第二,他没说这两个工具具体怎么用,比喻怎么设置存储标识,用户 id 怎么对应,什么时候该用哪个。第三,面试官问的快速查任意时间段活跃用户数,他只需要调命令,没需要具体 怎么查。第四,他没说这两个工具的区别,也没说实际工作中怎么用,怎么拓展。回答不实用,体现不出对约定是真正理解,也解决不了实际问题。 接下来我们先把问题说简单点,核心就是用约定存一亿用户一年的登录状态要满足两个要求,一是能快速查单个用户某一天是否登录。二是能快速查任意时间段,比如一周 一个月有多少活跃用户。关键是约定是存数据靠内存,上亿用户不能用普通的方式,不然内存不够用, 所以必须选省内存的专用工具。这就是我们不选普通存储方式的原因,普通方式从一亿用户一天的状态,一年下来要上千 g, 根本不现实。 然后我们用大白话讲一下这两个核心工具的原理,不用记复杂概念,这两个工具都为了省内存,只是用法和精度不一样,对应不同需求。第一是 bitemap, 它不是单独的工具,是基于约定式普通区块改造的,核心就是用最省空间的方式存状态, 每一个用户的状态只占一个二进字位,要么是零不活跃,要么是一活跃,这样能最大程度省内存,而且它单个用户的状态统计活跃数都很快。第二个是 hack log log, 他的装满用来统计有多少人的工具,不用精准算,允许一点点误差,但误差很小,只有百分之零点八一,换来的是极致省内存。不管存一万还是一亿用户,他占用的内存空间都固定特别小,而且能快速合并多个时间段的数据,统计总活跃数。懂了原理,我们再讲具体怎么用,分两种情况,根据 据实际需求选就行,两种都能存三亿用户。查任意时间段活跃数,第一种情况需要精准统计,比如要查某个用户某天是否登录,或者要精准知道某个时间段有多少活跃用户,就 用比特 map。 用法很简单,按日期设置存储标识,比如二零二六、零三零六,就代表当天把用户 id 占等编号对应到比特 map 的 一个位置,用零或一表示活跃状态,一个标识就能存一亿用户当天的状态,它特别省内存,一 离用户一天的状态只占十几兆内存,一年下来也才几 g, 完全够用。查单个用户状态,直接按用户 id 找对应的位置,一秒就能查到。查某段时间的活跃数。比如一周就把这七天比特马克合并, 合并后显示为一的就是这一周至少活跃过一次的用户,再数一下一的数量,就是精准的活跃数。如果用户数太多,还能把用户分成几段存,或者进一步压缩内存,你此数据也能多达预置一级存保, 保证够用。第二种情况不需要精准统计,比如只需要知道当天单月有多少活跃用户,不用精确到个位数,也不用查单个用户状态,就用 hot log log。 用法更简单, 还是按日期设置存储标识,直接把当天活跃的用户 id 加进去,它会自动驱虫,不会重复统计同一个用户。它最厉害的就是省内存,不管存多少用户,都只占十 g kb。 一 亿用户一年的状态也才几兆。查某段时间的活跃数比 于一个月,就把这一个月的和 vloglog 数据合并,就能快速得到近视的活跃数,误差很小,完全不影响看整体数据。唯一要注意的是,它查不了单个用户的状态,只能统计总数。实际工作中,我们也可以混合用这两种工具,近期的数据用比特币存,方便查单个用户状态,精准统计 很久之前的历史数据,只用看整体数据,就用 hot log log 压缩存,省内存。另外把很久不用的历史数据存到硬盘里,进一步节省永久式的内存。最后我们总结下面试要点,帮大家理清回答思路。这个问题是永久式面试参考题, 重点不是让你尽命令,而是看你会不会根据实际需求学工具,懂原理和落地。标准的回答思路很简单, 说明普通的存储方式不能用,再讲比特 map 和 hyper log log 的 原理,然后分情况说怎么用,最后补充实际工作中怎么优化怎么拓展,这样可以让大家完整使用。谢谢观看,关注我,求知不迷路!

大家好,我是念雨归格,现在是三月五号,今天的话是周四,我们是自习时间,然后今天我是复习了一下前三天的八股知识, radis my c 呃, rocket m q 和 my c。 然后今天的话主要呃,我讲一下 radis 的 两种持久化机制,一个是 r d b, 另外一个是 a o f。 首先说一下 r d b 是 什么? r d b 的 话,它就是 呃生成相应的快照,把内存数据保存,就是生成一个二进置文件,然后保存时间点中的内存数据, 它有六六个过程,呃,六六个步骤,第一个步骤就是触发 r d b 的 条件或者是执行持久化命令,然后它就会在主县城进行 for work, 呃, for work 操作,创建一个紫禁城,然后紫禁城的话会 有时候有创建紫禁城的时候会堵塞主进程的事物,然后附近城和紫禁城他是同共同占占占有一块内存数据的,他的核心。那第三步就是他的核心机制就是写实复制,这个是 叫做 copy on waiter, 简称 c o w。 呃, c o w 的 话,它就是创建一个临时的 r d b 文件,然后根据根据这个 创建一个临时的 r d b 文件,然后把这个相应的数据写进去。然后第四步就是将共享中的所有数据都写到临时的 r d b 文件中。第五步的话就是子系统,调用内存中的 就是调用系统中的。呃, run the name, 从命名将临时文件正式命名为 r 音乐文件。 呃,在在这个过程中我先说一下写实复制,写实复制的话,它就是去会去把,就如果你的附文附进程,它不是进行读写操作吗?这时候它就会 就是有操作进来以后他就会把数据更新,数据更新的时候,这时候紫禁城会跟着附近城一块更新,因为他们相当于占的同一块引用的同一块数据源,然后他俩只是两个不同的指征,我个人是这么理解的。 然后 r d b 的 触发机制有很多种,一个是你自动触发不通的时间,不同的频繁次数触发,还有一个手动触发,然后还有一些其他的触发方式。然后 r d b 的 优点的话就是体积小,它恢复的比较快,因为二进置文件嘛,它占不了多大的内存 啊。然后是 a o f a o f 的 话,它是一种日制型的持久化机制,它就相当于你把每一个命令都写入日制,然后当你大脑不是什么大脑,电脑宕机的时候,去重新读取这个日制,然后执行所有的命令。行 a o f 的 话,它分为四个步骤,首先是客户端写这个命令,然后 a o f 缓存区就会把这个命令格式化为 a o f 文件,然后存入内存中的缓存区,然后缓存区会将这个系统,系统会调用 一个方法,然后将缓存区的这个呃文件就是这条数据写到磁盘里面,保持起舞化。然后第四步就是重启哦,重启的时候他就会去读这个文件,然后会进行一个恢复。 hello, 然后 a o f 它的好处就是什么?它的可能性比较高,但是它的性能就是它的呃性能啊,还是从呃,不管是性能啊还是什么速度都比较慢。 然后一般来讲 radis 的 持久化实际上是两种模式混合相比的,它不是单一的,它混合的话就既既保证了它的数据安全性,又让它的文件大小不是很小,而且它启动速度也稍微好一点。 ok, 今天就大概这么多,然后我讲一下最近的一个我的一个状态吧。我最近的状态是怎么讲?还在调整,我发现就是要达到我理想中那种每天都在认真学,然后都有很多的收获是不可能的。 就是我以前一直有一个完美主义,我就说会想的,哎,如果我好好学,我百分百每天都拿出所有的精力去学, 这段时间实践下来是不可能的,人不可能百分百每天都做好每一件事情,我觉得能做到百分之六七十都已经算是训练的很到位了。 然后今天不是自习吗?今天自习的时候我就有个想法,就是想到能不能放松一下去打会游戏什么的,当这个念头出现的时候我察觉到了,然后我抑制住了,因为,呃,马上要个备考,还有八股街,东西其实挺多的,每天的事情都处理不完, 然后就没有时间去。也不是说没有时间打游戏吧,而是说我我喜欢的游戏类型就是那种沉浸式的,就是喜欢进入那种相对应的上头的状态,也就是所谓的星流状态, 实际上是享受的是心流状态的这个感觉,而不是说游戏带来的。因为游戏他是即时性的多巴胺分泌吗?就你玩一会他的多巴胺分泌的就很很多,你像像学习啊,健身啊,他都是结果性的,你得坚持一段时间,然后最后 包括自律也是坚持这样一段时间才会有所收获,像那种特别高效能及时性呃,释放多巴胺快乐的也就只有游戏一些和一些其他的一些娱乐模式了。所以说 这个确实不容易。如果说要戒掉娱乐方式的话确实不容易, 有一个很好的方式就是怎么能短时间调整过来。就是是对于这种即时性的高娱乐活动,你可以通过那种不是特别上瘾的方式,比如说, 嗯,看书。看书应该不算吧?看书或者是进入一种学学习状态以后收获到的结果你可以把它转移出去,转移出去以后 他其实最主要的还是当你产生了想玩这个念头,你查发现、察觉到,然后把它遏制掉,这才是最最强的自控。而不是说 我想着,哎,我就玩一个小时。那绝对不可能,你一上你一玩两个小时我都玩一个小时。玩两个小时,玩两个小时。算了,一天一天都玩完了,就这样吧。 可对我来讲的话最好就是别坐,因为我没有那么强的自控力。 ok, 这就是我的一点经验,拜拜。

hello, 大家好,前面的话我们讲了, reddit 是 很多方面的应用,其实 reddit 还有一个需求叫持久化,下面两个小节的话,我们将介绍 reddit 的 两种持久化方式,一种是 rbd, 一 种是 lf。 那 么首先讲的是 rbd, 我 们 在前面讲做 keeper 的 时候其实也讲过一种,而且他的是快照。这个 rbd 的 话其实和那个也是比较类似的,就是相当于当前数据里面,比如说有一个 k, 那 么 a 等于 b, 那 么这个 rdb 里面存储的数据就是 a 等于 b, 那 个 rdb 也是睿智默认的词语的方式,通过生成数据快照的方式,将数内存中的数据保存到棋盘的二清字文件里面,默认的名字是这个, 那下面的话是它的一些特性,就是快照的机制,就是记录某一时刻的快照数据状态。这个快照和 k v 某 k v 梦里面的快照其实逻辑上也是比较类似的, 二进字拉进进来压缩文件体积都比较小,比如说我们一个一个 k, 假设是一 k 一 k, 那 么有一万个 k, 那 么这个打出来的话就会还会比这个更小一点, 那恢复的话速度很快,适合于大数据的场景,就是相当于我们这个崩溃的时候,我们再通过这个二进字文件把它恢复起来的时候,速度也也很快。 然后触发的方式呢?有两种,一种是手动触发,比如说我们这在瑞丽士的命令里面直接执行这个命令,它就同步组算,但是如果说你的数据量很大的话,那这个相当于它,就相当于我执行这个命令以后,它就 去保存这个操作,放在保存这个操作当中,它会堵塞其他命令,也是其他查询请求,读写请求的话,它就给你堵塞了,让你卡住了,然后这个的话 b x 六的话就相当于把这个放到后台去,然后它不会堵塞其他的业务请求,这是手动的触发在命令行里面,比如这这种方式。 然后还有种它是系统自动触发,这里面保存的是九百秒有一个 k 被修改,它就会自动保存一次快照,这三百秒有十个 k 被修改,然后六百秒有一万个 k 被修改,然后通过这种配置的话,就是将达到这个域值的时候,它就会自动触发一个快照, 这样子的话,我们如果说相就相当于我们如果没有手动触发的话,系统也会自动触发,这样子的话可以保证我们的数据量和真实的环境,不至于差太远。 那下面的话是他的一个工作流程,比如说他首先如果说执行了这个命令以后,首先会检查有没有正在执行的 操作,如果说有,那么他就会等,如果没有的话他就调用 fork 紫禁城,这个 fork 机制的话在很多就是跟另一个是内核相关的里面会涉及到比较多,其实你就把它理解为它里面一个负责干活的人专门来创建了一个紫禁城,然后基于紫禁城当前的内存生成一个副本, 然后这个就相当于我调用这个操作以后,这个到我完成之间,它数据也是有改变的,内部数据我们就不管了,我们只只 相当于只调用我们当前执行命令的,那相当于那瞬间的数据,然后写出临时文件,然后再提临时文件,写完以后再提完成旧的 r、 d、 b 文件,因为旧的本身你它是有一个默认文件的,就相当于保存一次也好,保存多次也好, 最终这里面存储的文件只有只有那一个文件,然后其他的客户端的话继续处理请求,这样子它就不会堵塞我们的业务请求。 然后这是一个配置的视力,这个 dr 的 话其实就是一个纯属的目录,这个在前面讲瑞丽斯在那个集群的时候说的是这个 dr 的 话,是指瑞丽斯启动命令所对应的当前目录,当然这个里面最好可能写绝对路径会更好一点, 然后这个是取的名字,你可以自自己改,你可以用他的,也可以不写,这个是可以默认的,相当于,然后这个就是刚才讲的那几个 策略,然后还有其他配置保存出错的时候停止写入,这个就相当于更好的可以保护数据的一致性嘛,还有起用压缩,起用教教练等等。 然后这个就是比如说我们这里面有一个实力,我们可以看一下这个时间保存了多久,对吧?我这只有四个 k, 我 看他上次保存的时间, 哎,这个 rad 师不是在其他上面,我看一下, 哎,这这,这个地方怎么这么奇怪?六三七九端口不是我本机的吗? 哦,这是 rad 师,我说这个查 etcd 干嘛呀?这最近更新到 etcd 了, 你可以看这个文件是 february, 是 一八号的两点二十的,就是我们刚刚启动,应该是今天刚刚启动的时间,然后我们在这里面连接上来,我们再执行一个 保存,这个是不分大小写的哈,这个命令在这我们再看一下这个时间它是不是更新成当前的时间了,对吧?所以说因为数据没有变化,所以这里面大小实际上是不会有变化的。 好,下面的话有优势,优势的话就是性能小,处理进程不及时,进程几乎不受影响,然后直接加载二进字,速度快,文件就是紧凑,节约空间嘛。兼容性好,不能版本的话基本都可以兼容。 那数据风险的话,就是因为我们这不论是你配的这这种或者是手工执行,那么他们中间都是有误差的,它的数据都会出现一定程度的丢失,但你这个 值你可以配的更小一点,让你丢失的时间会更少一点,这个根据具体的需求来,但数据量越大的情况下,你这个压本就是瑞迪士本身的压力也就会越来越大,因为经常在干活嘛,对吧? 然后还有就是 f 会堵塞的问题,内存越大,这个问题就会越明显,然后另外一种 a o f 的 话是日子最佳的,然后 文件的话就比较大,这个就是类似于 mac 的 并 note 我 写个请求,然后他里面就会相当于给我插入一条写的请求,然后如果针对一个给我大量的重重复写,那么他也会记住大量的重复的数据,这样子的话 数据量就比较大,对吧?如果说恢复的时候他也就很慢,因为他要一条一条的执行,如果有一条命令被执行一万次,那么他就要恢复一万次,那么最终得到的结果实际上只有一个, a 等于 b, 那 是这样的, 那这种的话,对数据完整性要求不高的缓存场景需要快速恢复,大数据的场景需要定期备份,或者说灾难恢复的场景可以用这种方式。好,这个的话就是 r、 b、 d 的 这种备份的方式,我们就简单介绍到这儿。

hello, 大家好,我们上个小节讲介绍了数据过期,那么我们今天的话来讲一个 read 式缓存,或者说数据跟数据过期相关的一个在生产环境比较容易出现的问题,一个它们的名字叫缓存血泵,缓存穿透,或者叫缓存击穿。 虽然说这个这几个操作的话,实际上跟锐志本身没有什么关系,它是相当于把我们请求正常的常规请求大量请求,因为锐志速度很快,就会放在前端缓存里面,而把后端的数据库关系数据库保护起来,这样子的话呢能够提升我们的性能。 而这这几个现象的话,就是就是缓存失效的时候,把所有的请求都打到后端数据库里面去了,最终把数据库给打爆了。好,这是这个这个问题的一个基基本情况,我们下面呢就来比较详细的介绍这三种情况。 然后第一种是缓存雪雪崩,就是说是大量的缓存在同一时间集体过去,或者说瑞丽斯实力荡基了,导致所有的请求,就以前所有请求大部分请求都被瑞丽斯拦截了,然后只有少量的请求会查询到后端的数据库, 但是如果说这缓存大量时间统一过期的话,所有的请求就会直接打到数据库,而数据库关于数据库没有那么大的人处理能力,它就会被打崩。那核心的原因就是过期的时间过于集中,比如说我们批量设置 e、 p、 k 的 过期时间,那么这个过期时间就是统一时间到期的 失效以后的话,所有请求就会打到后端,比如说电商大促的时候,给所有商品缓存二十四小时后,商品缓存同时失效,那这个时候 所以请求就会打到后端数据过去,或者说直接宕机,主动切换。典型印象就是所有的请求都打到后端数据过去,那数据库的 cpu 和 i o 的 话,连接数都会出现问题, 这样子就一周会导致数据库宕机,那这个时候后端数据过宕了,那么你的业务肯定就会出现请求失败,对吧?那解决方案呢?也有几个,第一个就是给过期的时间添加一个随机的值,不让他们在同一时间过期,这样子的话 我们就不会从所有的 k 都同时过去,然后我们的数据库能够接收到请求的话,就是相对比较固定的,不会出现大面积的爆发的请求过去。 然后的话就是给数据库本身也要做限制,比如说后端数据库配置限流,当超过请求值的时候,后端数据库就不响应了,直接给前端报一个错误出去。还有的话就是熔断一部分非核心的请求。然后还有就是增加本地缓存 请求,先查本地缓存,再查路由器,最后再查数据库,这样子的话相当于本地缓存会拦截一部分请求,然后路由器如果失效了,再到后端数据库的话,它请求数量会稍微少一点,不会所有请求直接就打到后端去了, 那这个的话是缓存穿透,就是客户端请求的缓存和数据库中都不存都不存在的数据,导致每次请求的话都会直达数据库,数据库反复查询不存在的 数据,为什么这数据库中不存在就会打到,因为一般的业务请求是这样设计的,就是说我们一个请求先查缓存,如果缓存没有,我们就查数据库,当数据库查到数据以后呢?那这个数据就会被缓存到瑞丽市里面,下次再来这个请求的话,他就不会再查数据库,他就只查缓存了。 然后如果缓存和数据库都不存在,那么就就没办法做到缓存,这样子,每次请求都会跳过瑞迪斯直接到达后台数据库,而后台数据库又不存在,然后就像那大量的请求,大量无效的请求请求过来, 就会导致数据库连接数暴增,或者说数据库查询性能就是就是他把非必要的请求,把数据库的性能都吃完了,那么正常业务请求就进不来了。就类似于我们以前讲的攻击,这个攻击就是像 我发大量的请求过来,反正这个请求是无效的,也没有有效的,都没有关系,反正我这个就是就不为了获取有效,我只是把其他正常的用户请求给占到,让其他正常用户进不来来达到这个目的。 那这个解决方案的话,就是如果将数据库查询到也没有数据的时候,将该键缓存到 read 里面, 这样子的话可以避免相同的键重复穿透。然后还有的话就是将数据库中的所有存的组键加到不溶的过滤器里面,当然这个不溶的过滤器里面是另外一个说法,我们这没有讲,暂时也不管它。 然后还有就是在业务层面增加合法性降件,就是我们比如说我们在 登录的,是吧?就举个简单例子,登录我们,比如说我的密码是要求的是设置到八位,那我们在前端验证的时候,我们就做一个验证,第一个是位数的验证,第二个是话相当于密码格式的验证,这样子的话我们可以拦截掉一部分请求。 还有还有更多的是 id, 就是 跟相当于跟密码相相关的方式来验证,就是方相当于在 在前端控制层面就不要把请求达到后端去,不是说相当于有一部分请求他在前端就被拦截过滤不合法,然后我们就不让他到后端去,然后只有合法的请求我们才到后端去,这样子的话可以减少攻击面。 然后第三种的话是缓存击穿,就是一个热点数据在某一时刻过期,而这个时候恰好有大量的请求访问 该键,那么所有的请求瞬间就穿透到数据库,导致数据库压力骤增。这个和缓存雪崩其实逻辑上是一样的,缓存雪崩的话只是说是有很多 k 同时过期,而缓存击穿的话是少部分过期就是这。而这个过期的话是热点数据,就说查询非常平板的那种过期,这样子的话 他就所有的请求这个时候同一高频发的请求都会打到后端去,然后这个而刚好过期了,数据过后也会承担不得不了这个压力而崩溃。 然后这个具体的措施的话就是热点数据设置不过期的时间,由后台的异步任务去更新。这个缓存的数据就相当于比如说我们这个详商品的详情, 如果说很多人来来查询,那我们这个商品详情就永远永远不过去,如果说我们这个商品详情确实有过期的需求,那我们就再请一个其他任务来更新这个缓存,不让它过期, 然后这就是还有一种就是复制锁,这个锁的话也是跟开发比较强相关的,就是换缓存失效的时候,不是所有的请求都去查数据库,只有一个请求通过锁去查,也相当于所有的请求只有一个人去会去查数据库,那么这个压力就小很多。 然后请求到数据库以后就马上更新,那么其他请求由于他没有去查数据库,他他被锁被锁锁住了,那就不会 到真实的后端去,然后这样下一个第一个获取锁的那个用户那个请求的话,就把缓存更新过来以后,然后后面的话请求就被拦截到瑞丁拦截到数据库,瑞丁是数据库里面去了,就不会走到后后面去,然后这三者有一个区别,就是缓存雪崩,那就是大量的键过期, 然后缓冲击穿的话就是不存在的缓冲键就是数据库里面是没有的。然后还有一个是缓冲击穿,就是热点数据过期了, 然后导致所有小球打的后段区出现了异常,这个就是这三个呢,是瑞迪斯在常见的运维比较高的并发症的情况下,可能会比较容易出现的问题,这理理解这几方面的问题的话,到时候你可以跟开发联调,设置更好配合的策略, 然后从而保证业务不崩溃,因为业务崩了,不论是谁的原因对吧?承担损失的可能就是从公司层面来说,是公司出问题了,对吧?不论是瑞迪斯有问题,还是说业务层面代码写的不好,种种这些方面,反正。

你以为加了 radisson 就 安全了吗?做封锁系统时, radisson 常被视为解决病发问题的银弹。大家普遍认为只要开启了 come 狗 watchdog 机制,锁就是绝对安全的。那高病发扣库存的实战中,我们发现,即便加了 radisson, 锁依然出现了超慢和脏数据覆盖。 经过深度复盘,罪魁祸首并非代码逻辑,而是 jvm 的 负极 c 机制,它能绕过 radisson 的 防线,直接击穿数据一致性。 今天我们就从底层视角还原这座事故的完整链路。首先需要理清 ready 和 come 狗的运行机制。在常规业务中,我们最担心的是业务执行过长导致锁过期。但如果业务线程因为死循环抵着 i o 堵塞,甚至死锁彻底停留在执行过程中,情况就会变得非常微妙。 already 呢? come 狗是基于 laten 的 event loop 现成独立运行的,这意味着即便业务逻辑已经完全卡死,则即便进城还存活, come 狗依然会中性地执行去其操作。这就形成了一种现成隔离的假象,业务现成已死,但所却被无限期持有。 这虽然导致的系统不可用,但至少数据没乱。真正致命的数据之新问题就发生在业务现成假死的场景,也就是负二 g c。 接下来,这是事故的核心原因。视频涉及的详细资料,我整理进了两百万字的 java 与 a 大 模型学习资料里面了,里面包含了等三十多个技术站与一百多个项目长期实战笔记,有不同工作年限同学的简历模板,以第一份 java 加 ai 三十天面试途径给机构钱,需要的话直接拿去。正常状态下, java 类的线上 a 持有锁并在运行以及符合预期, 一旦触发负二 g c j m 会进入 stop 为的状态。注意,这里的 stop 是 物理意义上的时间冻结,进城内的所有现成,包括负责续期的 come 狗都会瞬间失去响应,无法向外发送任何心跳。 当外部的 radion 服务器时间依然在流逝,当锁的 t d l 后进而续期信号已 stops 未到, radion 会判定锁过期并强制删除。此时分布式锁的后置性已经从服务端消失。这就在高倍法环境下撕开了一个缺口,现成逼趁虚而入, 获取了同一把锁,并成功修改了数据库的库存数据。当 g c 结束,现场一苏醒,指责的他是一个僵尸,进程力还停留在 stopword 之前,误以为自己仁慈有所,还会继续执行未完成的险入操作。直接覆盖了现存币的正确数据, 是指复制机制彻底失效,脏数据产生。单纯调整 release 的 超时时间无法解决这个问题,因为我们永远无法预判 gc 会卡顿多久。要解决这个问题,必须引入栅栏令牌机制,在数据库层做最终兜底。回到事故场景,当 client a 获取锁匙, 同步获得一个局域递增的托肯,假设为三三,因为他随后陷入 g c 沉税,这个托肯依然是他唯一的身份标识。后来者 client b 在 a 沉税期间获取了锁,他拿到了托肯,便是递增后的三四。 client b 正常完成业务,并将数据库中的版本更新的为三四。关键在于写入环节,我们不再直接更新数据,而是利用乐观锁思维在缩口中强制调用托肯版本 数箱后的克莱德试图用旧托肯三三去更新数据时,数据库会发现当前托肯已经是三四。由于不满足单调递增的条件,这条写入会被数据库直接拒绝,那这条收口被拒绝执行时,整个系统的逻辑闭环就完成了。 这其实也回答了我们最初的困惑,为什么加了锁还会错?因为在分布式系统里,我们无法控制 g c 停顿的时间,更可以通过版本来锁定顺序。

假如啊,现在我要用数据库来去做一个实现朋友圈的点赞功能,那我需要能够看到点赞的时间以及用户的 id 信息,你会怎么做?嗯,用 zset 去做吧。嗯, zset, 那 具体怎么做呢? key 存什么? y 存什么?呃, 啊,这个问题其实很简单啊,只要你用过 reddit, 你 就应该能答出来啊。用 reddit 去实现朋友圈的点赞呢?一般啊,有两种方式啊。第一种呢,就是使用哈希类型,我们可以用动态的 id 作为一个 key, 然后字段,也就是我们的 file, 然后作为一个用户 id 的 存储,然后值 value, 我 们可以从点赞的时间。 那么这样呢,就是结构非常简单,并且我能够去查询到某个动态,他的一个点赞用户列表也会很快,因为我是单独的一个字段,对不对?就是,呃,我会有很多的小字段来去查询,但缺点呢,也很明显啊,就他不支持我们按时间去排序。如果你想根据点赞时间去排序呢,可能会有点麻烦。 那第二种呢?呃,可能就是你讲的就是我们用 sort 有 序集合。如果你担心简历上的东西讲不出来,我已经把面试经常问到的一些技术站场景题都整理在两百万字的面试文档了,里面针对每个知识点都有很详细的解析思路, 只要你是我的粉丝,留言六六六就可以打包带走。那么依然用动态 id 作为一个 key, 然后把用户 id 作为一个 member, 然后把点赞时间戳作为一个 score, 就是 作为一个排序的字段。这样呢,有两个很明显的优势。第一个,它天然支持按时间排序,我们可以轻松地按时间正序或者说倒序来展示点赞的用户,而第二个它是自动驱虫的,同一个用户重复点赞不会产生一个重复数据 啊。综合来看呢,就是如果需要时间顺序展示点赞列表,我们尽量的就去用 set, 也就是我们刚刚讲的 z set。

大家好,我是大树。今天咱们聊一个面试必问、工作必踩坑的问题, readis 和 my sql 怎么保证数据一致? 很多同学一上来就被扒古文,先更缓存,再更数据库,或者先更数据库再更缓存。结果一上线,要么数据不对,要么缓存雪崩,要么脏数据满天飞。 我直接用最简单的话讲清楚,缓存和数据库本质是两套存储,永远不可能百分之一百实时一致,我们能做的只是保证最终一致。先看最容易错的方案,先更新 readis, 在更新 mc 库,这绝对是坑中坑。你改完缓存,数据库还没更新成功,这时候请求过来读到的就是假数据。万一数据库更新失败,缓存已经是新值,两边直接对不上。所以这个方案直接拉黑,永远别用。那正常业务用什么?先更新数据库,再删除缓存? 注意,是删除,不是更新。为什么删不更新?因为你更新缓存,万一后面没人读,等于拜拜,浪费一次写入。而且高病发下,你刚更新完,又有新请求,改数据库 照样乱套。所以正确思路是,数据变了,我直接把缓存删掉,下次有人读,再从数据库重新查回来塞进去。但这就完美了吗?并不是,极端场景下还是会不一致。县城 a 读缓存没命中, 去查 mc 扩老数据,这时候县城 b 把数据改了,删了缓存,然后县城 a 才把老数据塞回缓存,结果就出现数据库是新的,缓存是老的。这种情况概率极低,但确实存在。怎么解决?两个思路,第一, 给缓存加过期时间,这是兜底方案,就算脏了,最多脏几分钟,最终能一致。第二,亦不更新缓存,通过消息队列、 can、 now、 监听 vlog 等数据库确认写入成功,再去更新缓存,保证顺序不乱。接下来面试常问的双写一致最优方案是什么?业界成熟方案就两个, one cash, side pattern, 也就是我们刚才说的读读缓存,没有读库,写回缓存,写 更新数据库,删除缓存,简单稳定。绝大多数公司都用这个。二 can 到订阅 blog 加一步更新,适合数据特别敏感、一致性要求高的场景。数据库一变日制,马上被监听,自动同步到 readys, 不 用厌恶代码操心。最后我给你总结三句口诀, 背下来面试直接用,一、先更酷,后删缓存,别先动缓存。二、不追求最终一致。三、过期时间是进阶。

用复位做分布式锁的兄弟是不是发现了个问题,设置了锁超时三十秒钟,万一业务三十秒没跑完,锁不就过期被别人给抢了吗?其实复位早就想到了这个问题,给锁配了一个专属的 看门狗。今天我们就拆透这只狗,看看它到底咋不眠不休地看住你的锁。先说一说看门狗到底解决了啥问题,核心其实就是防业务没完,锁先没了。你给 radis 说锁 hold 住三十秒钟, 可业务复杂,超时没跑完,锁一过期,其他资源进来操作,共享资源直接出问题。他们狗就是干这个的,在你业务执行时,偷偷的给锁补 不断的续费,延长他的过期时间 t t l 直到你手动去释放锁为止。关键的一点是什么呢?这狗特认主,绝不乱干活。他们狗不是局一只,而是一把锁配一条狗,还严格绑定加锁的那个县城,你县城 a 加的锁狗就只认 a, 其他县城想来释放锁直接被拦,彻底防止锁位 不删。再看它的完整的工作流程,就是个自动心跳的任务,你成功解锁了之后,复位会在后台去启动一个定时任务,而这个任务默认十秒钟跑一次,每次都检查这个锁还在不在,还在不在,是不是我这个县城持有的。只要这个锁还在,是自己就跟 ready 发命令,把锁的过期时间重新的刷回三十秒, 只要你不手动去进行解锁,这十秒一次的续命。等到你业务做完了,调用 unlock 释放锁的同时,复位会 直接取消这个定时任务。把开门狗牵走。这几个重要特征一定要记牢,别用错了,第一个默认才生效,只有你没显示的设置键所超时,比如说写 lock 点 lock 的 时候,开门狗才会启动。要是你设置了,比如说 lock 点 lock 十秒钟,那么压根就没有开门狗,十秒之后 锁必然会过期。而且第二个就是它的时长是可配置的,看门狗默认续命后的 t t l 就 过期时间是三十秒,每十秒续一次,这个三十秒能自己改配置去进行调整的,知道吧?第三个,它是纯客户端的一个行为。什么叫纯客户端的行为呢?就是 看门狗的定时任务跑在你的应用进程里面,要是应用崩了,狗也直接没了,续命也停了,锁会在最后一次续期的三十秒之后自动过期,刚好能防止失锁。 特别贴心。用个超形象的比喻来总结一下,复位的看门狗就是你雇的专锁锁管家,你把锁交给他说帮我拿着,他就去忙业务去了,管家就会帮你掐着秒表,每十秒就把锁这样子的一个倒计时,啪拨毁三十秒钟,直到你回来喊解锁,他才停手 把锁给释放掉。有了这个管家,你再也不愁业务能不能在超时时间内做完。只要你的应用进程活着,锁就绝对不会因为超时而丢。你们的项目用复位锁 锁的时候,是用默认的开门狗模式,还是自己设置的固定超时呢?有没有因为配置不对或者客户端崩了,跟狗管家闹过锁的问题呢?评论区聊一聊你跟他打交道的实战的一个经验。

大家好,今天用三分钟时间带你吃透 radis 面试高频考点缓存雪帮不仅讲清楚真实场景,还把企业及解决方案一次性说,全面试工作都能用得上。 首先,什么是缓存雪帮?一句话总结,大量缓存同一时间失效,或 radis 直接荡机,导致所有请求瞬间打向数据库,数据库压力暴增,甚至直接被压垮。就像冬天突然雪帮,所有积雪一起滑下来,根本挡不住。 缓存血崩主要出现在这两个典型场景,第一种,大批量 t 同时过期,比如我们做商品详情页,为了方便,给所有缓存都设置了一小时过期,结果一小时一到上万个 t 同时失效, 瞬间几万请求冲到数据库,数据库直接卡死,整个服务不可用。第二种, radis 节点宕机或集群崩溃。比如服务器断电,网络故障, radis 卡死,整个缓存层直接失效,流量全部压到数据库,引发服务血崩。搞懂了场景, 我们直接上解决方案,都是企业真实在用的方案。第一,给过期时间加随机值,避免集体失效。不要给所有缓存设置相同的过期时间,在基础时间上加上一到五分钟的随机数,让缓存分散过期,从根源避免同时失效。 第二,搭建 radis 高可用集群,主从加哨兵或者 radis cluster, 防止单点故障,一台机器挂了,其他机器顶上,保证缓存服务不断付。第三, 开启缓存持久化, r d b 加 a o f 结合使用,一旦 read 重启,能快速恢复缓存数据,减少击穿风险。第四,接口限流降级,垄断保护数据库,即使缓存失效,也不让所有请求过去,超过预值直接限流或返回默认数据,避免数据库被打包。第五, 搭建多级缓存,本地缓存加分布式缓存, read, 挂了还能查本地缓存,分担数据库压力。 最后总结一句话,缓存血帮就是大量缓存同时失效或宕机压垮数据库解决核心就是打散过期时间,保证 radis 高可用,限流降级多级缓存都抵。