本文主要是介绍从消息中间件看分布式系统的多种套路,Java开发者必看,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
# 基础知识
RabbitMQ是一个开源的消息代理和队列服务器,用来通过普通协议在完全不同的应用之间共享数据,它是使用`Erlang`语言来编写的,并且是基于`AMQP`协议的;
**RabbitMQ高性能的原因**
* Erlang语言在交换机的交互方面性能优秀的(`Erlang`语言最初在于交换机领域的架构模式,这样使得RabbitMQ在Broker之间进行数据交互的性能是非常优秀的)
* Erlang有着和原生`Socket`一样的延迟
## AMQP协议
**什么是AMQP高级消息队列协议**
AMQP(Advanced Message Queueing Protocol)定义:具有现代特征的二进制协议。是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计
AMQP协议模型:
![](http://www.www.zyiz.net/i/li/?n=2&i=images/20210630/1625053571203481.jpg)
Publisher 推送消息前先与Server建立连接,找到`Virtual host`,然后将消息推送至Exchange交换机。而交换机与`Message Queue`有绑定关系(一个交换机相当于一个独立的虚拟机,而这个虚拟机内的各种独立的应用就相当于一个Queue,这个Queue与交换机绑定),`Consumer`通过绑定的对队列,而交换机也绑定了队列。发送者将消息发送给交换机,这样就能完成消息的推送了
**整体架构图**
![](http://www.www.zyiz.net/i/li/?n=2&i=images/20210630/1625053572110098.jpg)
## 基本概念
**Broker**
消息队列服务进程,接收客户端的连接,实现AMQP实体服务。
**Connection**
连接,应用程序与`Broker`的网络连接。
**Producer**
消息生产者,即生产方客户端,生产方客户端将消息发送到MQ。
**Consumer**
消息消费者,即消费方客户端,接收MQ转发的消息。
**Channel**
网络信道,几乎所有的操作都在`Channel`中进行,Channel是进行消息读写的通道。客户端可建立多个Channel,每个Channel代表一个会话任务
**Message**
消息,服务器和应用程序之间传送的数据,由`Properties`和Body组成。Properties可以对消息进行修饰,比如消息的优先级、延迟等高级特性;Body则就是消息体内容。
**Virtual Host**
虚拟地址,用于进行逻辑隔离,最上层的消息路由。一个Virtual Host里面可以有若干个Exchange和Queue,同一个`Virtual Host`里面不能有相同名称的Exchange或Queue
**Exchange**
交换机,接收消息,根据路由键转发消息到绑定的队列。
![](http://www.www.zyiz.net/i/li/?n=2&i=images/20210630/1625053573669039.jpg)
> 常见的有4种不同的交换机类型:
* 直连交换机:Direct exchange
* 扇形交换机:Fanout exchange
* 主题交换机:Topic exchange
* 首部交换机:Headers exchange
> 扇形交换机
扇形交换机是最基本的交换机类型,扇形交换机会把能接收到的消息全部发送给绑定在自己身上的队列。因为广播不需要思考,所以扇形交换机处理消息的速度也是所有的交换机类型里面最快的
![](http://www.www.zyiz.net/i/li/?n=2&i=images/20210630/1625053573271122.jpg)
> 直连交换机
直连交换机是一种带路由功能的交换机,一个队列会和一个交换机绑定,除此之外再绑定一个`routing_key`,当消息被发送的时候,需要指定一个`binding_key`,这个消息被送达交换机的时候,就会被这个交换机送到指定的队列里面去。同样的一个`binding_key`也是支持应用到多个队列中的
这样当一个交换机绑定多个队列,就会被送到对应的队列去处理
![](http://www.www.zyiz.net/i/li/?n=2&i=images/20210630/1625053574638210.jpg)
适用场景:有优先级的任务,根据任务的优先级把消息发送到对应的队列,这样可以指派更多的资源去处理高优先级的队列
> 主题交换机
直连交换机的`routing_key`方案非常简单,如果我们希望一条消息发送给多个队列,那么这个交换机需要绑定上非常多的`routing_key`,假设每个交换机上都绑定一堆的`routing_key`连接到各个队列上。那么消息的管理就会异常地困难。
所以`RabbitMQ`提供了一种主题交换机,发送到主题交换机上的消息需要携带指定规则的`routing_key`,主题交换机会根据这个规则将数据发送到对应的(多个)队列上。
主题交换机的`routing_key`需要有一定的规则,交换机和队列的`binding_key`需要采用`*.#.*.....`的格式,每个部分用`.`分开,其中:
* `*`表示一个单词
* `#`表示任意数量(零个或多个)单词
当一个队列的绑定键为`#`的时候,这个队列将会无视消息的路由键,接收所有的消息
![](http://www.www.zyiz.net/i/li/?n=2&i=images/20210630/1625053574936848.jpg)
> 首部交换机
首部交换机是忽略`routing_key`的一种路由方式。路由器和交换机路由的规则是通过`Headers`信息来交换的,这个有点像`HTTP`的`Headers`。
将一个交换机声明成首部交换机,绑定一个队列的时候,定义一个`Hash`的数据结构,消息发送的时候,会携带一组hash数据结构的信息,当`Hash`的内容匹配上的时候,消息就会被写入队列。
绑定交换机和队列的时候,Hash结构中要求携带一个键`x-match`,这个键的Value可以是any或者all,这代表消息携带的Hash是需要全部匹配(all),还是仅匹配一个键(any)就可以了
相比直连交换机,首部交换机的优势是匹配的规则不被限定为字符串
* any: 只要在发布消息时携带的有一对键值对headers满足队列定义的多个参数`arguments`的其中一个就能匹配上,注意这里是键值对的完全匹配,只匹配到键了,值却不一样是不行的;
* all:在发布消息时携带的所有`Entry`必须和绑定在队列上的所有Entry完全匹配
![](http://www.www.zyiz.net/i/li/?n=2&i=images/20210630/1625053575178474.jpg)
**Binding**
Exchange和Queue之间的虚拟连接,Exchange在与多个Message Queue发生Binding后会生成一张路由表,路由表中存储着`Message Queue`所需消息的限制条件即Binding Key。当Exchange收到Message时会解析其Header得到Routing Key,Exchange根据Routing Key与Exchange Type将Message路由到Message Queue。Binding Key由Consumer在`Binding Exchange`与Message Queue时指定,而Routing Key由Producer发送Message时指定,两者的匹配方式由Exchange Type决定
**Routing Key**
一个路由规则,虚拟机可用它来确定如何路由一个特定消息。
**Queue**
也称为`Message Queue`,消息队列,保存消息并将它们转发给消费者。
**消息发布流程:**
1. 生产者和Broker建立TCP连接。
2. 生产者和`Broker`建立通道。
3. 生产者通过通道消息发送给Broker,由Exchange将消息进行转发。
4. Exchange将消息转发到指定的Queue(队列)
**消息接收流程:**
1. 消费者和Broker建立TCP连接 。
2. 消费者和`Broker`建立通道。
3. 消费者监听指定的Queue(队列)
4. 当有消息到达Queue时Broker默认将消息推送给消费者。
5. 消费者接收到消息。
**消息流转过程**
生产者生产出Message并投递到`Exchange`上
一个Exchange可以绑定多个`Message Queue`,它根据路由策略(`routing key`)路由到指定的队列,最后由消费端去监听队列
## 工作模式
**队列模式:**
对于任务过重或任务较多情况使用工作队列可以提高任务处理的速度。
1、一条消息只会被一个消费者接收;
2、rabbitmq采用轮询的方式将消息是平均发送给消费者的;
3、消费者在处理完某条消息后,才会收到下一条消息。
**发布订阅模式:**
1、每个消费者监听自己的队列。
2、生产者将消息发给`broker`,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息
对应交换机中的`fanout`类型
**路由模式:**
1、每个消费者监听自己的队列,并且设置routingkey。
2、生产者将消息发给交换机,由交换机根据`routingkey`来转发消息到指定的队列。
对应交换机中的`direct`类型
**通配符模式:**
对应交换机中的`topics`类型
**Header转发器模式:**
对应交换机中的`header`类型
**远程过程调用模式:**
RPC即客户端远程调用服务端的方法,使用MQ可以实现RPC的异步调用,基于Direct交换机实现,流程如下:
1. 客户端即是生产者就是消费者,向`RPC`请求队列发送RPC调用消息,同时监听RPC响应队列。
2. 服务端监听RPC请求队列的消息,收到消息后执行服务端的方法,得到方法返回的结果。
3. 服务端将RPC方法的结果发送到`RPC`响应队列。
4. 客户端(RPC调用方)监听RPC响应队列,接收到RPC调用结果。
## 最后
分享一套我整理的面试干货,这份文档结合了我多年的面试官经验,站在面试官的角度来告诉你,面试官提的那些问题他最想听到你给他的回答是什么,分享出来帮助那些对前途感到迷茫的朋友。
#### 面试经验技巧篇
* 经验技巧1 如何巧妙地回答面试官的问题
* 经验技巧2 如何回答技术性的问题
* 经验技巧3 如何回答非技术性问题
* 经验技巧4 如何回答快速估算类问题
* 经验技巧5 如何回答算法设计问题
* 经验技巧6 如何回答系统设计题
* 经验技巧7 如何解决求职中的时间冲突问题
* 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
* 经验技巧9 在被企业拒绝后是否可以再申请
* 经验技巧10 如何应对自己不会回答的问题
* 经验技巧11 如何应对面试官的“激将法”语言
* 经验技巧12 如何处理与面试官持不同观点这个问题
* 经验技巧13 什么是职场暗语
![](http://www.www.zyiz.net/i/li/?n=2&i=images/20210630/1625053575826383.jpg)
#### 面试真题篇
* 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
* 真题详解2 某知名社交平台软件工程师笔试题
* 真题详解3 某知名安全软件服务提供商软件工程师笔试题
* 真题详解4 某知名互联网金融企业软件工程师笔试题
* 真题详解5 某知名搜索引擎提供商软件工程师笔试题
* 真题详解6 某初创公司软件工程师笔试题
* 真题详解7 某知名游戏软件开发公司软件工程师笔试题
* 真题详解8 某知名电子商务公司软件工程师笔试题
* 真题详解9 某顶级生活消费类网站软件工程师笔试题
* 真题详解10 某知名门户网站软件工程师笔试题
* 真题详解11 某知名互联网金融企业软件工程师笔试题
* 真题详解12 国内某知名网络设备提供商软件工程师笔试题
* 真题详解13 国内某顶级手机制造商软件工程师笔试题
* 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
* 真题详解15 某著名社交类上市公司软件工程师笔试题
* 真题详解16 某知名互联网公司软件工程师笔试题
* 真题详解17 某知名网络安全公司校园招聘技术类笔试题
* 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题
![](http://www.www.zyiz.net/i/li/?n=2&i=images/20210630/1625053575899173.jpg)
> 需要这份文档的朋友可以[点击蓝色传送门](https://docs.qq.com/doc/DSmxTbFJ1cmN1R2dB)即可免费获取!
资料整理不易,点个关注再走吧
这篇关于从消息中间件看分布式系统的多种套路,Java开发者必看的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!