粉丝3698获赞1.5万

今天我们来聊一道阿里二面的面试题, rocket 门口突然积压了一条消息,系统都报警了,你作为技术负责人,该怎么去解决这个问题?如果面试官这么问你,你的第一反应是不是加机器做横向扩展? 要是你真的这么回答,大概率会被面试官问得哑口无言。这其实是初级开发,很容易踩了坑。今天我们就把这件事拆透,从避开误区到落地解决方案,让你下次遇到这类问题,能清晰有条理的给出答案, 直接让面试官认可。我把详细积压处理的全流程啊避坑点和解决方案都拆透了,整理成了这份文档。我还整理了一份一百万次的面试题库,包括学习路线啊,简历模板以及啊公开试听课。 好,我们先来搞懂核心问题,为什么单纯加机器没用?这里必须记住 rockman 扣的一条核心规则就是在局群消费模式下,一个扣 在同一时间只能被同一个 consumer group 的 下一个消费者实力消费。简单来说,就是扣和 consumer 是 一对一的绑定关系。我给你算一笔账啊,你的 topic 用的是默认的配置,通常是四个扣, 现在有两台消费的机器,那每台机器分配两个扣,刚好还可以满负荷工作。这个时候如果你觉得消费速度不够,一口气控制到一百台,结果会怎么样? 只有前四台机器能分到扣,每台负责一个,剩下的九十六台机器根本就没活可干, cpu 占用率几乎为零,这完全是浪费资源。 那肯定会有人问啊,我直接去控制台,把扣的数量改为一百不就解决了吗?答案是不行。原因啊,很简单,一一跳,已经积压了。老消息啊,早就存在原来的四个扣里面了,你新扩容的一百个扣, 只能接受后续的新消解,解决不了已经积压的存量问题。这就相当于是给一口快干的脑井挖了口新井,脑井的水该干还是干,根本呢,解不了进口。好原理讲清楚了,那真正可行的解决方案是什么?大厂的思路是 空间换时间。我把这个方案叫做消息转发加临时扩容的搬运模式,分两步走,既简单又高效。第一步啊,先上线一个消息搬运的程序, 我们不用修改原来复杂的业务代码,修改业务代码耗时久,还容易出 bug。 专门写一个临时的 com 程序,这个程序他不处理任何的业务逻辑,不查数据库,不做业务计算,他就干一件事,把旧的 topic 里面积压的消息啊快速的读出来, 直接转发到一个新的临时的 topic 里。比如我们可以叫 topic temp, 正因为不带任何业务逻辑,这个搬运程序它的处理速度能接近系统的 i o 极限,用四台机器就能快速把原来四个扣里面的积压消息搬空。第二步就是在新的 topic 上实现真正的并行消费。 我们新建 topic 摊铺的时候啊,我们把扣的数量直接设置为一百,如果不够还可以再增加。 然后呢部首一百台运行业务逻辑的消费者机器,专门订阅这新的拖皮卡,那这一百个啊扣啊,就对应着一百台机器,一对应的每台机器都能分配到对应的任务,真正实现了并行消费,这才是能够提升消费速度的有效扩容。 但是啊,兄弟们要注意啊,这个方案他不是完美的,你如果想拿到高薪的 offer 啊,你必须主动说出这个方案它存在的三个潜在的风险,这其实就是区分架构师和开发的关键所在。 那第一个风险就是顺序消息的处理问题。如果你的消息有严格的顺序要求,比如创建订单支付订单完成,那绝对不能随便转发, 多先存啊,并发抖取旧的扣啊,再耐续写入新的托币口,很有可能就会导致下一系统先收到支付成功的消息,再收到订单创建的消息,直接造成业务逻辑的混乱。 对应的解决办法呢,其实也很简单,转发消息的时候哎,必须保留原来的 addin key, 比如订单号,确保哎同一个订单的同一个扣里面, 这样呢,就能保证消息的顺序不混乱。那第二个风险就是 brock io 爆炸单元程序啊,一边疯狂的读取旧消息,一边疯狂的写入新消息,这就会让 roker 们扣到 brock 的 词盘读写和 cpu 压力直接翻倍。 本来啊, brock 就 因为消息积压处于高负荷状态,再这么折腾啊,很可能就直接导致 brock 宕机 问题更严重。解决办法就是动手之前一定要先看监控数据,如果博克的 i o 使用率已经很高,出现告警,必须先扩容博克局群,缓解他的负担压力,再进行消息的搬运。 那第三个风险也是最容易忽略的,就是数据库能扛住吗?你要考验下游数据库的承载能力,你把消费速度提升一百倍,那也就意味着下游数据库 my second 要承受一百倍的并发查询压力。 如果消息积压的根源本来就是数据库处理速度慢,那这一百个并发请求过去,就相当于对自己的数据库进行一次压力攻击,很有可能直接导致数据库的宕机, 引发全站瘫痪的批评事故。那解决的办法就是扩容消费单之前, 我们先必须评估下游地币的承载能力,如果数据扩是整个链路的瓶颈,盲目加机器只会适得其反。 当然,还有一种比较特殊的情况,就是如果积压的是日制,买点这类非核心的数据,而且已经影响到核心业务的实时处理了。这个时候我们要懂得取舍 优先,保证核心业务的正常运行。最快的兜底方案就是优先止损,要么直接修改 com 码的消费微点,跳过一亿积压数据,要么把这些老消息全部导流到死性对面,等业务高峰期过去之后再慢慢的处理。 我们这么做的核心目标啊只有一个,先让系统恢复到实时处理状态,保住当下的业务。最后啊,再跟啊兄弟们强调一句啊,处理消息的积压只是紧急止血,真正重要的是事后的复盘优化。 我们要深入排查问题的根源,到底是数据库处理慢了,还是第三方接口超时导致消费卡住了,又或者是怠慢你存在死锁,影响了消费的效益。 我们不能啊,只做那个只会重启机器加机器的执行者,更要做能够看透本质,设计合理解决方案的架构师,这才是我们提升核心竞争力、拿高薪的关键。

今天来讲一下 ruki 的 mq 如何消费消息,消费消息的本质其实就是读数据。首先我们来看一下最重要的点,就是这个模式,一般的情况下我们都是用这个服务器推模式,因为它实时性高一点。 另外一种模式的话是客户单拉模式,他实时性要低一点。然后接下来我们看一下这个具体的这个步骤,步骤的话分这么几步,然后等一下我们直接结合单码,然后看一下这个步骤。 首先第一步是创建这个服务器推模式对象,这个是测试单码,可以看到这个是服务器推模式的这个消费者 就是基于服务器推模式来消费消息,消费数据。然后首先首先第一步的话就是看一下这个是创建这个服务器推模式对象就是创建这个对象,创建服务器推模式,这个对象就是本质,其实就是创建一 一个服气推模式的消费者,这个名字也包含了这个 poss, 就是推模式。然后第二步的话就是创建这个鉴定器,第二步的话就是创建这个鉴定器,这个是又一个这个鉴定器,然后创建这个鉴定器,创建这个鉴定器的目的是什么呢?创建这个鉴定器的作用是什么呢? 这个监听这个监听器的作用,监听器的目的就是消费收据,就是我实现的一个这个监听方法,实现的一个这个监听方法。 然后来消费收据就是如果有收据,如果有消息就会突发这个消费消息的这个方法,这个是鉴定器的这个消费消息的这个方法。然后这里的话我们就是具体的怎么处理这个消息的业务逻辑代码 啊?这里写的是实现读数据的方法,就是消费消息的方法,就是刚才这个鉴定器的这个消费消息的这个方法,总共 就是分这么几步。然后接下来我们再看一个点,就是每次拉多少条数据,注意一下,这里就是有两个配置参数,而且就是容易搞混淆。首先第一个参数,他的值是三十二,就是默认值是三十二, 这个是参数的名字,然后这个参数表示的是什么东西呢?就是我刚才的这个问题,就是每次拉多少条数据,就表示当前消费者每次拉三十二条数据,就是从这个福气从 broke 拉三十二条数据, 就这个意思。然后还有另外一个参数,他的指示一,就是默认指示一,然后这名字是这个名字,然后他是表示什么东西呢? 他是表示监听器的监听方法,他的入餐每次消费一条数据,我们直接来看看马就知道是什么意思了。就刚才那个一是对应的是这个值,就是我这个监听器的这个监听方法 的入餐,他的值是一,就是每次掉这个方法的时候,他消费了一条数据,这两个参数的话都是可以配置的,我们直接看一下 lucky mq 的圆码,看一下他的那个默认值是多少, 我们直接进去看一下。首先看一下这个,刚才说的就是那两个,那两个插座都是可以配置的,直接在这里配置就可以了,就是 cet 这些插座啊,都可以配置的, 我们直接点进去看一下,然后搜一下,可以搜到这个圆码,这个圆码这里的话就是每次拉三十二条数据,这个是默认值,然后还有一个参数,然后刚才鉴定器的鉴定方法 的入餐,他的值是一,默认值是一,也就是说这里入餐就是每次是这里,虽然这个是一个集合,但是他默认值是一,对于这里的这个参数的值,这个值的话我们可以 可配置的,就是如果刚才那个纸那个一配置成多条数据的话,就是这里的话就是多条数据。如果如果这里是多条数据的话,然后我们这里处理的话就要循环处理多条数据。好的,谢谢。

最近用到的最新版的 local m q, 五点三点三,然后在安装的过程中会有那个端口冲突,因为是最新的嘛,然后它的一些配置参数可能跟网上搜到的不一样,官网也没写那么细, 大家看一下这个配置文件,在 com 下面有个 i m q, 然后杠 prox, 然后修改这里面的端口就行了。还有一个就是我们如果说客户端然后去发送 mq 的 时候,你要配置它的公网 ip, 除非说你的硬件和 mq 如果说在同一台机器上面,你是可以 不用去配置,因为当时测试的时候我是在自己的本机测试,然后我的 mq 是 在云上面,所以说你要配置公网 ip, 不然的话也可能说发送的时候你老是发送失败,也就是要修个那个 block 跟 configure, 大家看一下,这样的话大家就少踩坑啊。

大家好,我是爱讲 java 的 king, 今天呢,我们给他们继续解读大厂高并发系统设计 rockin q 如何进行性能调优。我们知道 rockin q 呢是阿里用于双十一的一个高病发消息中间见,那么一般情况下面绝大部分同学呢,会认为 rockin q 它的并发是十万, 但其实如果你进行一个全方位的调优的话呢,若可能 q 的性能可以到八十万,九十万的一个并发,甚至接近一百万。那么我们来看一下若可能 q 如何进行性能调优。 如果你要把 rock and q 进行性能调料的话呢,你要站在多个维度,比如第一个维度要站在 g v m 的这个层面,首先的话呢,我们要去尽量的去减少 s t w, 去减少暂停,那么第一个方式呢,叫我把对应的监控给暂停呢,比如像 rocken q 里面它有一个 rock 抗缩呢,就是他一个监控后后端,那么这样的话呢,可以把这个监控后台给关了。然后的话呢,另外一般的公司在运动员方面也一些专门的监控组件啊,比如说撒 beast 啊,或者是其他的一些东西,对不对?我们也可以把它关了,你只是用最简单的这种适应命令进行监控就可以了, 这样的话呢,就可以去尽量的减少我们 g v m 的 s t w。 然后第二个点的话呢,可以去消除偏向锁。 大家如果知道啊,在 singknights gdk 一点六的版本之后,他就会有偏向锁,乐观锁,还有呢这种 无锁以及了重量级锁,所以呢,生根带子自断,它会有锁的一个状态的变化,但是在若肯克当中,它都是多线程,所以它的锁竞争呢比较激烈,所以一般我们可以 把偏向锁给取消掉了,因为呢你在多线的场景下面,偏向锁开启的话呢,对不对?有一定开销,同时的话要撤销,所以这个开销是没有必要的,所以的话呢,我们可以看到 在 g 啊,在 rockton q 的他的一个配置 g 元面的参数里面有一个叫做杠叉叉,然后呢减号,减号就是禁止 uzi bastar looking, 这个就是把我们的偏向锁给禁用啊,这是我们刚才所说的禁用偏向锁。 那除了金融偏向锁之外,第二个点的话呢,就是在 g 一元门层面,我们需要进行优化垃圾回收机制,一般来说推荐使用 g 一垃圾回收器, g 一垃圾回收器呢,一般把堆内存配大一点啊, 所以呢我带他们来看一下 g 一垃圾回收器一些相关的参数设定。首先画的话,首先的话呢看我们这个参数杠叉叉冒号加优特的 g e g c, 这就是使用 g 一垃圾回收器同时设定他的堆大小啊,一般来说呢,我们推荐可以把堆的这一个空间设置成 八个 g 啊,甚至呢可以设置成十六个 g, 更多的啊,如果你内存比较大的话呢,你可以把它设置成三十二个 g, 然后呢底下还有几个参数至关重要,比如 g 一 he pro ranges size, 把它设置成一十六张, 就是在这一里面他有一个分区,就是他会把内存呢,比如说八个 g 分成很多个区,每一个区的默认大小一般情况下面是两兆,但是呢如果你要做 的优化的话,建议把它配成一十六张,因为他分区的越小的话,其实他损耗的内存会越多,进行垃圾回收的这一个效率呢也相对来说会偏低,所以呢我们建议把它是大一点, 然后的话呢我们还有一些其他的参数,比如说 ge reserve percent 等于二十五, 这个呢就是你之一在管理老年代里面,你要预留百分之二十五的内存空间,确保你新生代,然后晋级到老年代里面,他有足够的空间, 一般在 g e m g d k 一点八的它的默认值是百分之十,所以呢我们需要把它调大一点,这样的话呢可以就是没有必要造成什么我新生代晋级的时候,我没有足够的空间可以进行释放好。然后还有一个参数,就是我们的 indetette, 然后 黑普啊,这个什么 person 的等于三十,这个参数是什么呢?就是当堆内存它的使用率达到百分之三十之后,我们就可以启动之一的并发垃圾回收,开始尝试回收一些垃圾对象, 一般来说这个默认值是百分之四十五,那为什么要把它调低呢?就是在很多情况下面啊,如果你让他百分之四十五触发的话呢,那一次垃圾回收他的耗时就会过长,所以呢我们可以适当的提高 gc 的一定频率,然后呢减少单次垃圾回收耗时过长的问题。 ok, 然后底下还有一系列的参数,这个呢我就不进行一个细讲了,这是 g v m 的一些参数设定,进行对应的调优。好,我们回来除了 g v m 层面之外的话呢,其实你如果要让 rockin q 有高效性 或者是有高性能的话,还要站在操作系统层面,首先的话呢,操作系统层面我们挨个来讲基本的参数啊,基本的参数呢,有几个点?第一个点这个叫做 of accommodating, 然后下划线 memory 等于一,这是什么意思呢?这个参数就是配置的,如果他配置为一,那么 我们操作系统的内核始终认为他有足够的内存,直到他用完为止,所以的话呢,他效率会比较低。如果你把这个参数配置为零的话, 那么当操作当我们的若肯去向用户去申请内存的时候,内核呢会去检查他到底有没有这么大的内存空间,所以呢,一般情况下面我们也不用去检查,每一次去申请内存,要去检查的话,性能相当的低。 ok, 如果你把它配置成二的话呢,就是内核禁止任何形式的 过量分配内存,这样的话也没有必要,所以这是我们讲的第一个参数,第二个参数呢,就是这个 swipe 零四等于十啊,这个十是什么意思呢?就是说当系统存在足足够内存的时候,这个时候一般推荐设置为十的话呢,可以去提高性能。 ok, 就是这里面呢,他涉及到一个交换空间,你如果把这个值设置为零的话呢,那内存不足的情况下,面对不对他会使用交换空间。 ok, 如果你把它设置为一的话呢,他会尽量很少的进行交换,如果设置为十的话呢,他就是以性能为优先 默认值了,这个值是六十,我们可以把它设置为十, ok, 然后的话呢,第三个就是 max max com, 这个是个什么东西啊?这个是定义的一个进程他能够拥有最多的一个内存区域 啊,默认值了,一般都是六五五三六,我们可以把它改大一点,就是让我们一个进程呢,可以拥有更多的这样的一个内存区域, ok, 然后还有一个啊厘米题,这个啊厘米题呢,就是文件打开数,因为若可米可它是一个多线程的,所以一般来说我们推荐把文件打开数 把它配高一点,不然的话呢,你同时启动的现成数就会受限制。 ok, 所以这是我们刚才讲的这一个啊,你比题就是一个,就是用户能够打开的这个最大文件数, ok, 然后除了这个基本参数之外,还有一块叫做 nic n i c, 是讲的网卡,我们知道啊,一个 read 的请求,你必须要通过网络通讯,所以呢必定会经过网卡,那么网卡怎么去调 u 呢?这个地方有个非常简单的东西叫做 buff 是什么了?润 buff 就是我们的一个缓冲区,因为大家知道啊,在很多情况下面,我们去进行网络通讯的话呢,他会有一个算法叫做滑动窗口算法,两边都会有缓冲,如果说你的润 buff 比较小的话呢,他会导致你写的时候丢包, 那么大家知道啊,如果你丢包了,业务量丢包了,是不是要重发?所以说业务量过大的话呢,你出现网络丢包的话,他的性能肯定会下降,所以呢我们一般来说会把这一个值改大一点点, 调整一下他的大小,因为他调大一点的话呢,丢包的情况就会有所缓解,所以呢,你在进行 rockin q 发送或者是消费的时候,他的效率要高一点。好,这是我们刚才讲的网卡,那么除了网卡之外,还有一个叫做空呢,空呢是内核,内核的话呢,我们可以让他做中断句核, 什么是中断句?合了?举个简单例子啊,就是你想一下,像我们的这个操作系统,操作系统的话呢,他是不是要去监控一个网卡?比如说我启动一个 soke 的监听,对不对?启动一个 sorry sock 了,我启动端口是八八八八, 那八八八八,那么在这种情况下面这个端口里面我去起了一个八八八八的这样的一个监听,如果有请求来了,我怎么知道这个请求 啊?来了呢?这个时候的话,我们就需要使用中断啊,中断的话呢,就可以去响应对应的请请求。当然啊,我举个例子可能让同学们可以清晰一点,比如说你是一位开发者, 对不对?开发者了,如果说有网络请求来了,他叫做中断,就就相当于是说有产品经理说你的写,你之前写的系统有 bug 啊,有需求要修改了,所以呢,我要给你发一个中断。但是要注意了,你不单纯只是处理 buck, 处理以前的这个需求变动啊,你的部门还会给你分配新的任务,所以的话呢,这个地方就会存在一个问题,你可能每天工作八小时,但是呢,你可能被 中断啊,中断了一百次,那你想一下啊,就是动不动,我工作了两分钟一次,中断来了,我要处理一下,然后呢,我把这一个中断处理完之后,我又过了五分钟中断又来了,那么这一下子的话,你会发现你每天的工作效率很低, 所以的话呢,我们需要把它做一个聚合,什么叫聚合呢?就是说我中断请求一个、两个、三个、四个,我不用每一个都去响应,我等你积累到五个或者积累到十个的时候,我 统一来处理。这就是相当于你跟产品经理说,你不要每收到任何的一个 bug, 或者是收到任何的一个需求,你就来找我, 你把任务积累到五个或者十个的时候,在一起来找我,我集中去响应你的中断,这样的话呢,工作效率会更高。所以呢,对于计算器的底层,对于 cpu, 对于我们的程序来说, 你可以多充半句和效率会更高, ok。 然后呢第二个的话呢,在内核里面,我们可以进行网卡对列的 cpu 绑定, 因为现在主流的网卡基本上他都是支持多队列的啊,因为你网络请求过来的时候要有队列来支持,对不对?那么这样的话呢,我们会把不同的队列分给不同的 cp 核心数来进行处理,这是一种优化的手段啊,那么这个时候我们可以让他进行对应的绑定,就是你不要说这一次你发到网络 请求这个合一,你给的是一个对应的 cpu, 对不对?然后呢这个请求又给了另外的 cpu, 这样的话呢,我们可以去让我们的网卡队列和我们的 cpu 进行绑定的话呢,效率相当来说会高一点。然后呢底下还有一个叫做关闭 lq banners 啊,这个呢其实是主流 cpu, 如果说你去关闭这个班的事的话呢,对你的性能相对来说也会有一定的提高。好,除此之外的话呢,还有一些网络对应的参数啊,比如说像这个 tcp 的 note 的量, 这个漏电的 dna 是什么呢?就是在很多情况下面啊,我们网络层啊,就是要去减少必,就是必须发的这一个封包的数量,对不对?所以的话呢,我们需要去使用这种算法对缓冲区啊,它进行一个自动连接,那么这个漏电 的话呢,可以很大程度上面去提高我们的一个响应。除此之外的话呢,缓冲区的调整也是非常有必要的啊,很多情况下面如果缓冲区调的太小的话,会容易丢包。 ok, 然后最后一个的话呢,就是我们要去调整这一个对列的大小,因为对列 在网络传输他,他的底层,他其实是会决定我们的一个性能啊,包括我们的 sork 的一个对联,我们尽量呢可以把它调大一点。 那么我们总结一下啊,如果说你要完成一个若肯的调优的话,你可以站在 g u m, 还有站在操作系统 g u m 呢,可以去减少 stop the word 的时间优化垃圾回收,站在操作系统有基本的参数调优,有网卡 nic 的调优,有内核很多细致参数的调优。 所以如果你能够站在一个全方位的参数上面进行调优的话,你的 roke me q 啊,可以干到八十万,甚至可以干到单击一百万, ok, 这就是 roke me 的一个全方位的性能调优。