前言
文本已收录至我的GitHub仓库,欢送Star:https://github.com/bin3923282...
种一棵树最好的工夫是十年前,其次是当初
Tips
面试指南系列,很多状况下不会去深挖细节,是小六六以被面试者的角色去回顾常识的一种形式,所以我默认大部分的货色,作为面试官的你,必定是懂的。
https://www.processon.com/vie...
下面的是脑图地址
叨絮
音讯队列,在互联网企业级开发是一个必不可少的中间件,明天来看看咱们的MQ吧
而后上面是后面的文章汇总
- 2021-Java后端工程师面试指南-(引言)
- 2021-Java后端工程师面试指南-(Java根底篇)
- 2021-Java后端工程师面试指南-(并发-多线程)
- 2021-Java后端工程师面试指南-(JVM)
- 2021-Java后端工程师面试指南-(MySQL)
- 2021-Java后端工程师面试指南-(Redis)
- 2021-Java后端工程师面试指南-(Elasticsearch)
小六六接触的MQ呢?也不算太多,我就具体说说咱们常常用的rabbitmq和rocketmq
说说什么是音讯队列
咱们能够把音讯队列看作是一个寄存音讯的容器,当咱们须要应用音讯的时候,间接从容器中取出音讯供本人应用即可。
音讯队列是分布式系统中重要的组件之一。应用音讯队列次要是为了通过异步解决进步零碎性能和削峰、升高零碎耦合性。
咱们晓得队列 Queue 是一种先进先出的数据结构,所以生产音讯时也是依照程序来生产的。
那你的零碎为啥要应用音讯队列
- 通过异步解决进步零碎性能(缩小响应所需工夫)
- 削峰/限流:先将短时间高并发产生的事务音讯存储在音讯队列中,而后后端服务再缓缓依据本人的能力去生产这些音讯,这样就防止间接把后端服务打垮掉。
- 升高零碎耦合性:应用音讯队列还能够升高零碎耦合性。咱们晓得如果模块之间不存在间接调用,那么新增模块或者批改模块就对其余模块影响较小,这样零碎的可扩展性无疑更好一些
那你说说引入音讯队列的优缺点是什么
长处:
- 解耦
- 削峰
- 异步数据散发
毛病
- 零碎可用性升高
- 零碎复杂度进步
- 一致性问题
说说你接触过的mq,说说他们的特点和应用场景呗
那你聊聊JMS和AMQP
JMS
JMS(JAVA Message Service,Java音讯服务)API是一个音讯服务的规范或者说是标准,容许应用程序组件基于JavaEE平台创立、发送、接管和读取音讯。它使分布式通信耦合度更低,音讯服务更加牢靠以及异步性。
ActiveMQ 就是基于 JMS 标准实现的。
AMQP
AMQP,即Advanced Message Queuing Protocol,一个提供对立音讯服务的应用层规范 高级音讯队列协定(二进制应用层协定),是应用层协定的一个凋谢规范,为面向音讯的中间件设计,兼容 JMS。基于此协定的客户端与消息中间件可传递音讯,并不受客户端/中间件同产品,不同的开发语言等条件的限度。
- AMQP 为音讯定义了线路层(wire-level protocol)的协定,而JMS所定义的是API标准。在 Java 体系中,多个client均能够通过JMS进行交互,不须要利用批改代码,然而其对跨平台的反对较差。而AMQP人造具备跨平台、跨语言个性。
- JMS 反对TextMessage、MapMessage 等简单的音讯类型;而 AMQP 仅反对 byte[] 音讯类型(简单的类型可序列化后发送)。
- 因为Exchange 提供的路由算法,AMQP能够提供多样化的路由形式来传递音讯到音讯队列,而 JMS 仅反对 队列 和 主题/订阅 形式两种。
如何保障音讯队列的高可用?
这个的话其实就是看你本人公司应用哪个队列你就答复哪个队列,小六六这边说rabbit 和rocket
RabbitMQ
RabbitMQ 有三种模式:单机模式、一般集群模式、镜像集群模式。
- 单机模式,就是 Demo 级别的,个别就是你本地启动了玩玩儿的????,没人生产用单机模式。
- 一般集群模式(无高可用性)这种形式的确很麻烦,也不怎么好,没做到所谓的分布式,就是个一般集群。因为这导致你要么消费者每次随机连贯一个实例而后拉取数据,要么固定连贯那个 queue 所在实例生产数据,前者有数据拉取的开销,后者导致单实例性能瓶颈。
- 镜像集群模式(高可用性)这种模式,才是所谓的 RabbitMQ 的高可用模式。跟一般集群模式不一样的是,在镜像集群模式下,你创立的 queue,无论元数据还是 queue 里的音讯都会存在于多个实例上,就是说,每个 RabbitMQ 节点都有这个 queue 的一个残缺镜像,蕴含 queue 的全副数据的意思。而后每次你写音讯到 queue 的时候,都会主动把音讯同步到多个实例的 queue 上。
RocketMQ
RocketMQ集群模式: 单Master模式 多Master模式 多Master多Slave模式(异步) 多Master多Slave模式(同步)
- 单Master模式:这种形式危险较大,一旦Broker重启或者宕机时,会导致整个服务不可用。不倡议线上环境应用,能够用于本地测试
多Master模式:一个集群无Slave,全是Master,例如2个Master或者3个Master,这种模式的优缺点如下:
- 长处:配置简略,单个Master宕机或重启保护对利用无影响,在磁盘配置为RAID10时,即便机器宕机不可复原状况下,因为RAID10磁盘非 常牢靠,音讯也不会丢(异步刷盘失落大量音讯,同步刷盘一条不丢),性能最高;
- 毛病:单台机器宕机期间,这台机器上未被生产的音讯在机器复原之前不可订阅,音讯实时性会受到影响。
多Master多Slave模式(异步):每个Master配置一个Slave,有多对Master-Slave,HA采纳异步复制形式,主备有短暂音讯提早(毫秒级),这种模式的优缺点如下:
- 长处:即便磁盘损坏,音讯失落的非常少,且音讯实时性不会受影响,同时Master宕机后,消费者依然能够从Slave生产,而且此过程对利用通明,不须要人工干预,性能同多Master模式简直一样;
- 毛病:Master宕机,磁盘损坏状况下会失落大量音讯。
多Master多Slave模式(同步):每个Master配置一个Slave,有多对Master-Slave,HA采纳同步双写形式,即只有主备都写胜利,才向利用返回胜利,这种模式的优缺点如下:
- 长处:数据与服务都无单点故障,Master宕机状况下,音讯无提早,服务可用性与数据可用性都十分高;
- 毛病:性能比异步复制模式略低(大概低10%左右),发送单个音讯的RT会略高,且目前版本在主节点宕机后,备机不能主动切换为主机。
说说rocketmq的各个组件呗
- Producer:音讯的发送者;举例:发信者
- Consumer:音讯接收者;举例:收信者
- Broker:暂存和传输音讯;举例:邮局
- NameServer:治理Broker;举例:各个邮局的管理机构
- Topic:辨别音讯的品种;一个发送者能够发送音讯给一个或者多个Topic;一个音讯的接收者能够订阅一个或者多个Topic音讯
- Message Queue:相当于是Topic的分区;用于并行发送和接管音讯
说说rocketmq组件的特地呗
- NameServer是一个简直无状态节点,可集群部署,节点之间无任何信息同步。意味着每个节点都蕴含全副的数据。
- Broker部署绝对简单,Broker分为Master与Slave,一个Master能够对应多个Slave,然而一个Slave只能对应一个Master,Master与Slave的对应关系通过指定雷同的BrokerName,不同的BrokerId来定义,BrokerId为0示意Master,非0示意Slave。Master也能够部署多个。每个Broker与NameServer集群中的所有节点建设长连贯,定时注册Topic信息到所有NameServer。
- Producer与NameServer集群中的其中一个节点(随机抉择)建设长连贯,定期从NameServer取Topic路由信息,并向提供Topic服务的Master建设长连贯,且定时向Master发送心跳。Producer齐全无状态,可集群部署。
- Consumer与NameServer集群中的其中一个节点(随机抉择)建设长连贯,定期从NameServer取Topic路由信息,并向提供Topic服务的Master、Slave建设长连贯,且定时向Master、Slave发送心跳。Consumer既能够从Master订阅音讯,也能够从Slave订阅音讯,订阅规定由Broker配置决定。
### 既然你说你用rocketmq,那么我问你当集群启动的时候它的工作流程是怎么样的
- 启动NameServer,NameServer起来后监听端口,期待Broker、Producer、Consumer连上来,相当于一个路由控制中心。
- Broker启动,跟所有的NameServer放弃长连贯,定时发送心跳包。心跳包中蕴含以后Broker信息(IP+端口等)以及存储所有Topic信息。注册胜利后,NameServer集群中就有Topic跟Broker的映射关系。
- 收发音讯前,先创立Topic,创立Topic时须要指定该Topic要存储在哪些Broker上,也能够在发送音讯时主动创立Topic。
- Producer发送音讯,启动时先跟NameServer集群中的其中一台建设长连贯,并从NameServer中获取以后发送的Topic存在哪些Broker上,轮询从队列列表中抉择一个队列,而后与队列所在的Broker建设长连贯从而向Broker发消息。
- Consumer跟Producer相似,跟其中一台NameServer建设长连贯,获取以后订阅Topic存在哪些Broker上,而后间接跟Broker建设连贯通道,开始生产音讯。
如何保障音讯不被反复生产?或者说,如何保障音讯生产的幂等性?
首先咱们来看看在音讯队列的各个组件中,有哪些组件会呈现不幂等
- 生产者已把音讯发送到mq,在mq给生产者返回ack的时候网络中断,故生产者未收到确定信息,生产者认为音讯未发送胜利,但理论状况是,mq已胜利接管到了音讯,在网络重连后,生产者会从新发送方才的音讯,造成mq接管了反复的音讯
- 消费者在生产mq中的音讯时,mq已把音讯发送给消费者,消费者在给mq返回ack时网络中断,故mq未收到确认信息,该条音讯会从新发给其余的消费者,或者在网络重连后再次发送给该消费者,但实际上该消费者已胜利生产了该条音讯,造成消费者生产了反复的音讯;
解决方案
- 第一个就是生产者,咱们必须保障咱们只有一个音讯发送到了队列中,能够通过一个惟一的id来保障,当然这种状况是十分小的
- 第二个就是消费者,也可利用mq的该id来判断,或者可按本人的规定生成一个全局惟一id,每次生产音讯时用该id先判断该音讯是否已生产过,至于实现形式有很多,redis 数据库等等都行
如何保障音讯的程序生产
- 生产者必须要将所有的音讯程序的写入到一个队列中。
- 而后消费者的话,就只能保障一个消费者,这样的话就能实现程序生产了,然而程序生产的害处就是咱们的吞吐量要降落
如何保障音讯的可靠性传输?或者说,如何解决音讯失落的问题?
数据的失落问题,可能呈现在生产者、MQ、消费者中,咱们从 RabbitMQ 和 RocketMQ 别离来剖析一下吧。
RabbitMQ
- 生产者弄丢了数据
生产者将数据发送到 RabbitMQ 的时候,可能数据就在半路给搞丢了,因为网络问题啥的,都有可能。
此时能够抉择用 RabbitMQ 提供的事务性能或者是confirm 机制 事务机制和 confirm 机制最大的不同在于,事务机制是同步的,你提交一个事务之后会阻塞在那儿,然而 confirm 机制是异步的,你发送个音讯之后就能够发送下一个音讯,而后那个音讯 RabbitMQ 接管了之后会异步回调你的一个接口告诉你这个音讯接管到了。
- RabbitMQ 弄丢了数据
就是 RabbitMQ 本人弄丢了数据,这个你必须开启 RabbitMQ 的长久化,就是音讯写入之后会长久化到磁盘,哪怕是 RabbitMQ 本人挂了,复原之后会主动读取之前存储的数据,个别数据不会丢。除非极其常见的是,RabbitMQ 还没长久化,本人就挂了,可能导致大量数据失落,然而这个概率较小。
- 生产端弄丢了数据
RabbitMQ 如果失落了数据,次要是因为你生产的时候,刚生产到,还没解决,后果过程挂了,比方重启了,那么就难堪了,RabbitMQ 认为你都生产了,这数据就丢了。
这个时候得用 RabbitMQ 提供的 ack 机制,简略来说,就是你必须敞开 RabbitMQ 的主动 ack,能够通过一个 api 来调用就行,而后每次你本人代码里确保解决完的时候,再在程序里 ack 一把。这样的话,如果你还没解决完,不就没有 ack 了?那 RabbitMQ 就认为你还没解决完,这个时候 RabbitMQ 会把这个生产调配给别的 consumer 去解决,音讯是不会丢的。
RocketMQ
能够从三个方面来剖析rocket的音讯可靠性
Producer端音讯失落
- producer端避免音讯发送失败,能够采纳同步阻塞式的发送(也就是发送同步音讯),同步的查看Brocker返回的状态是否长久化胜利,发送超时或者失败,则会默认重试2次,rocker抉择了确保音讯肯定发送胜利,但有可能产生反复投递
- 如果是异步发送音讯,会有一个回调接口,当brocker存储胜利或者失败的时候,也能够在这里依据返回状态来决定是否须要重试(当然这个是须要咱们本人来实现的)
Brocker端音讯失落
- rocketmq个别都是先把音讯写到PageCache中,而后再长久化到磁盘上,数据从pagecache刷新到磁盘有两种形式,同步和异步
- 同步刷盘形式:音讯写入内存的 PageCache后,立即告诉刷盘线程刷盘,而后期待刷盘实现,刷盘线程执行实现后唤醒期待的线程,返回音讯写胜利的状态。这种形式能够保证数据相对平安,然而吞吐量不大。
- 异步刷盘形式(默认):音讯写入到内存的 PageCache中,就立即给客户端返回写操作胜利,当 PageCache中的音讯积攒到肯定的量时,触发一次写操作,将 PageCache中的音讯写入到磁盘中。这种形式吞吐量大,性能高,然而 PageCache中的数据可能失落,不能保证数据相对的平安。
Cousmer端音讯失落
- cousmer端默认是音讯之后主动返回生产胜利确认ack,然而这时如果咱们的程序执行失败了,数据不就失落了吗?
- 所以咱们能够将主动提交(AutoCommit)生产响应,设置为在代码中手动提交,只有真正生产胜利之后再告诉brocker生产胜利,而后更新生产惟一offset或者删除brocker中的音讯
大量音讯在 mq 里积压了几个小时了还没解决此时应该怎么办
- 第一条,为啥会呈现音讯大量积压,是自身咱们的生产者的音讯产多了,还是咱们的消费者呈现问题了,先弄清楚起因先
- 第二 如果是咱们生产的音讯多了,那么咱们能够多加几个消费者去生产音讯
- 第三,如果说是咱们的消费者呈现了问题,那么我首先必定是要修复消费者的bug,然而有一点就是就算咱们修复了bug,然而要到生产的流程来说还要花几个小时能力生产完,这时候,咱们要零时写一个逻辑,把消费者的耗时逻辑间接确认,而后把音讯转到另外一个队列,另外一个队列用10背速度去生产,等转发实现之后,换成失常的生产逻辑,这样就能够尽快的使业务失去失常的应用了。
说说延时队列呗
延时队列,首先,它是一种队列,队列意味着外部的元素是有序的,元素出队和入队是有方向性的,元素从一端进入,从另一端取出。
其次,延时队列,最重要的个性就体现在它的延时属性上,跟一般的队列不一样的是,一般队列中的元素总是等着心愿被早点取出解决,而延时队列中的元素则是心愿被在指定工夫失去取出和解决,所以延时队列中的元素是都是带工夫属性的,通常来说是须要被解决的音讯或者工作。
简略来说,延时队列就是用来寄存须要在指定工夫被解决的元素的队列。
RabbitMQ中的一个高级个性——TTL(Time To Live),当咱们有一些非凡的场景,比方注册几天后,没有购买就给他们发优惠卷,这些经营伎俩,就能够用到这个延时队列了,在rabbitmq外面就是ttl+死信队列来实现的。
而后RocketMQ的延时队列的话用途就不大了,rocketmq实现的延时队列只反对特定的延时时间段,1s,5s,10s,...2h,不能反对任意时间段的延时
深刻聊聊RocketMQ呗,因为rabbitmq的源码不是Java,所以不好问,然而RocketMQ的源码还是要大抵理解理解
聊聊音讯的存储和发送
- 音讯存储
磁盘如果应用切当,磁盘的速度齐全能够匹配上网络 的数据传输速度。目前的高性能磁盘,程序写速度能够达到600MB/s, 超过了个别网卡的传输速度。然而磁盘随机写的速度只有大略100KB/s,和程序写的性能相差6000倍!因为有如此微小的速度差异,好的音讯队列零碎会比一般的音讯队列零碎速度快多个数量级。RocketMQ的音讯用程序写,保障了音讯存储的速度。
- 音讯发送
Linux操作系统分为【用户态】和【内核态】,文件操作、网络操作须要波及这两种状态的切换,免不了进行数据复制。
一台服务器 把本机磁盘文件的内容发送到客户端,个别分为两个步骤:
1)read;读取本地文件内容;
2)write;将读取的内容通过网络发送进来。
这两个看似简略的操作,理论进行了4 次数据复制,别离是:
- 从磁盘复制数据到内核态内存;
- 从内核态内存复 制到用户态内存;
- 而后从用户态 内存复制到网络驱动的内核态内存;
- 最初是从网络驱动的内核态内存复 制到网卡中进行传输。
通过应用mmap的形式,能够省去向用户态的内存复制,进步速度。这种机制在Java中是通过MappedByteBuffer实现的
RocketMQ充分利用了上述个性,也就是所谓的“零拷贝”技术,进步音讯存盘和网络发送的速度。
这里须要留神的是,采纳MappedByteBuffer这种内存映射的形式有几个限度,其中之一是一次只能映射1.5~2G 的文件至用户态的虚拟内存,这也是为何RocketMQ默认设置单个CommitLog日志数据文件为1G的起因了
聊聊分布式事务呗
如何解释分布式事务呢?事务大家都晓得吧?要么都执行要么都不执行 。在同一个零碎中咱们能够轻松地实现事务,然而在分布式架构中,咱们有很多服务是部署在不同零碎之间的,而不同服务之间又须要进行调用。比方此时我下订单而后减少积分,如果保障不了分布式事务的话,就会呈现A零碎下了订单,然而B零碎减少积分失败或者A零碎没有下订单,B零碎却减少了积分。
现在比拟常见的分布式事务实现有 2PC、TCC 和 事务最终一致性,个别咱们除了强一致性的场景,个别用的可靠消息最终一致性,那么对于RocketMQ 它是怎么实现的呢?
在 RocketMQ 中应用的是 事务音讯加上事务反查机制 来解决分布式事务问题的
在第一步发送的 half 音讯 ,它的意思是 在事务提交之前,对于消费者来说,这个音讯是不可见的 。
你能够试想一下,如果没有从第5步开始的 事务反查机制 ,如果呈现网路稳定第4步没有发送胜利,这样就会产生 MQ 不晓得是不是须要给消费者生产的问题,他就像一个无头苍蝇一样。在 RocketMQ 中就是应用的上述的事务反查来解决的
事务音讯发送及提交
- 发送音讯(half音讯)。
- 服务端响应音讯写入后果。
- 依据发送后果执行本地事务(如果写入失败,此时half音讯对业务不可见,本地逻辑不执行)。
- 依据本地事务状态执行Commit或者Rollback(Commit操作生成音讯索引,音讯对消费者可见)
事务弥补
- 对没有Commit/Rollback的事务音讯(pending状态的音讯),从服务端发动一次“回查”
- Producer收到回查音讯,查看回查音讯对应的本地事务的状态
依据本地事务状态,从新Commit或者Rollback
- 其中,弥补阶段用于解决音讯Commit或者Rollback产生超时或者失败的状况。
聊聊RocketMQ的底层存储机制
RocketMQ 是如何设计它的存储构造了。我首先想大家介绍 RocketMQ 音讯存储架构中的三大角色——CommitLog 、ConsumeQueue 和 IndexFile 。
- CommitLog: 音讯主体以及元数据的存储主体,存储 Producer 端写入的音讯主体内容,音讯内容不是定长的。单个文件大小默认1G ,文件名长度为20位,右边补零,残余为起始偏移量,比方00000000000000000000代表了第一个文件,起始偏移量为0,文件大小为1G=1073741824;当第一个文件写满了,第二个文件为00000000001073741824,起始偏移量为1073741824,以此类推。音讯次要是程序写入日志文件,当文件满了,写入下一个文件。
- ConsumeQueue: 音讯生产队列,引入的目标次要是进步音讯生产的性能,因为RocketMQ 是基于主题 Topic 的订阅模式,音讯生产是针对主题进行的,如果要遍历 commitlog 文件中依据 Topic 检索音讯是十分低效的。Consumer 即可依据 ConsumeQueue 来查找待生产的音讯。其中,ConsumeQueue(逻辑生产队列)作为生产音讯的索引,保留了指定 Topic 下的队列音讯在 CommitLog 中的起始物理偏移量 offset ,音讯大小 size 和音讯 Tag 的 HashCode 值。consumequeue 文件能够看成是基于 topic 的 commitlog 索引文件,故 consumequeue 文件夹的组织形式如下:topic/queue/file三层组织构造,具体存储门路为:$HOME/store/consumequeue/{topic}/{queueId}/{fileName}。同样 consumequeue 文件采取定长设计,每一个条目共20个字节,别离为8字节的 commitlog 物理偏移量、4字节的音讯长度、8字节tag hashcode,单个文件由30W个条目组成,能够像数组一样随机拜访每一个条目,每个 ConsumeQueue文件大小约5.72M;
- IndexFile: IndexFile(索引文件)提供了一种能够通过key或工夫区间来查问音讯的办法。
完结
接下来温习下ssm框架
日常求赞
好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是真粉。创作不易,各位的反对和认可,就是我创作的最大能源,咱们下篇文章见
微信 搜 "六脉神剑的程序人生" 回复888 有我找的许多的材料送给大家