(2)RabbitMQ架构设计与应用场景
1.什么是消息中间件?
消息是指应用间传输的数据。消息体包括文本字符串、Json、内嵌对象等。
消息中间件是基于队列模型实现异步和同步传输数据的。
作用:解耦,冗余(存储)、扩展性、削峰、可恢复性、顺序保证、缓冲、异步通信。通俗点来说就是支持支撑高并发、异步解耦、流量削峰、降低耦合度。
2. AMQP是什么?
AMQP(Advanced Message Queuing Protocol,高级消息队列协议)是一个进程间传递异步消息的网络协议。
RabbitMQ是遵从AMQP协议的,而RabbitMQ的模型架构又和AMQP的模型架构是一样的。
AMQP实体模型如下:

工作原理如下:
生产者(Publisher)将消息发送给交换器,交换器和队列绑定。当生产者发送消息时所携带的RoutingKey与绑定时的BindingKey相匹配时,消息即被存入相应的队列之中,消费者可以订阅相应的队列来获取消息。
3.RabbitMQ相关概念
RabbitMQ实体模型如下:

在了解完上图RabbitMQ模型后,现在让我们来看看RabbitMQ运转流程:
●生产者推送消息:
(1)生产者连接到RabbitMQ的Broker建立一个连接(Connection),开启一个信道(Channel)。
(2)生产者声明一个交换器,并设置相关属性,比如交换机类型、是否持久化等。
(3)生产者声明一个队列并设置相关属性,比如是否排他、是否持久化、是否自动删除等。
(4)生产者通过路由键将交换器和队列绑定起来。
(5)生产者发送消息至RabbitMQ的Broker,其中包含路由键、交换器等信息。
(6)相应的交换器根据接收到的路由键查找相匹配的队列。
(7)如果找到,则将从生产者发送过来的消息存入相应的队列中。
(8)如果没有找到,则根据生产者配置的属性选择丢弃还是回退给生产者。
(9)关闭信道。
(10)关闭连接。
●消费者接收消息:
(1)消费者连接到RabbitMQ的Broker,建立一个连接(Connection),开启一个信道(Channel)。
(2)消费者向RabbitMQ的Broker请求消费相应队列中的消息,可能会设置相应的回调函数,以及做些准备工作(推拉模式)。
(3)等待RabbitMQ的Broker回应并投递相应队列中的消息,消费者接收消息。
(4)消费者确认(ack)接收到的消息。
(5) RabbitMQ从队列中删除相应己经被确认的消息。
(6)关闭信道。
(7)关闭连接。
注:上述有两个概念可以了解下,分别是信道(Channel)与连接(Connection),我们知道无论是生产者还是消费者,都需要和RabbitMQ的Broker建立连接,这个连接就是一条TCP连接,也就是Connection的TCP连接建立起来,客户端紧接着可以创建一个AMQP信道(Channel),每个信道都会被指派一个唯一的ID。Channel是建立在Connection之上的虚拟连接,RabbitMQ处理的每条AMQP指令都是通过信道完成的。如图所示:
*这里大伙可能会有一个疑问,为什么Connection能完成Channel连接工作,还要引入Channel呢?
试想这样一个场景,一个应用程序中有很多个线程需要从RabbitMQ中消费消息或者生产消息,那么必然需要建立很多个Connection,也就是许多个TCP连接。然而对于操作系统而言,建立和销毁TCP连接是非常昂贵的开销,如果遇到使用高峰,性能瓶颈也随之显现。RabbitMQ采用类似NIO1(Non-blocking 1/0)的做法,选择TCP连接复用,不仅可以减少性能开销,同时也便于管理。
*NIO1,也称非阻塞(I/O),包含三大核心部分Channel(信道)、Buffer(缓冲区)和Selector(选择器)。NIO基于channel和Buffer进行操作,总是从信道读取数据到缓冲区中,或者从缓冲区写入到信道中。Selector用于监听多个信道的事件(比如连接打开,数据到达等)。因此,单线程可以监听多个数据的信道。NIO1中有个很有名的Reactor模式,有兴趣小伙伴可以去阅读下,这里就不详解了。
*每个线程分别把持一个信道,所以信道复用了Connection TCP连接。同时RabbitMQ可以确保每个线程的私密性,就像拥有独立的连接一样。当每个信道的流量不是很大时,复用单一的Connection可以在产生性能瓶颈的情况下有效地节TCP连接资源。但是当信道本身的流量很大时,这时候多个信道复用一个Connection就会产生性能瓶颈,进而使整体的流量被限制了。此时就需要开辟多Connection,将这些信道均摊到这些Connection中,至于这些相关的调优策略需要根据业务自身的实际情况进行调节。
下面让我们来了解下实体中每个角色模型。
●Producer(生产者):投递消息到服务端的一方。投递消息分为两部分:消息体(payload)和标签(label)。
◎消息体:一般是带有业务逻辑结构的数据,例如一个json数据。
◎标签:消息的标签是用来表述这条消息,例如一个交换器名称跟路由键。
●Broker(代理):MQ服务节点。也可以看作一个实例,或者一台RabbitMQ服务器。
●Exchange(交换器):生产者将消息投递到队列中,实际是将消息投递到交换器,由其路由到一个或者多个队列当中。如果路由不到,会返回给生产者或者丢弃。交换器包含路由键(RoutingKey)和绑定键(BindingKey),还有四种类型,后面会重点介绍。
◎路由键:生产者投递消息给交换器时会指定一个路由键,用作路由规则来决定消息的流向。
◎绑定键:交换器跟队列是通过一个绑定键关联的,这样Rabbitmq才能正确把消息投递到相关队列去。如图所示:
从上图可知道,交换器相当于投递包裹的邮箱,路由键当于填写在包裹上的地址,绑定键当于包裹目的地,当填写在包裹上地址和实际想要投递的地相匹配时,那么这个包裹才会被正确投递到目的地,最后这个目的地的“收件人”(队列)才可以保留这个包裹。如果填写的地址有错,邮递员不能正确投递到目的地,那么包裹可能会回退给“寄件人”(生产者),或者可能会被丢弃。其实在某些情形下路由键和绑定键可以看作同一个东西。
●Queue(队列):用于存储消息。遵循先进先出,后进后出原则。多个消费者可以订阅同一个队列,这时队列中的消息会被平均分摊(Round-Robin),即轮询给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。
4.为什么要用到MQ?
4.1传统Http请求缺点

●传统Http请求是基于请求与响应的模型下进行的,在高并发的情况下,客户端会发送大量的请求达到服务器端,这样有可能会导致我们服务器端要处理大量堆积请求,增加服务器压力。
●像Window IIS服务器(IIS线程池)处理每个请求都有自己独立的线程,如果超过最大线程数,IIS的w3wp进程不会再将http.sys的队列中的请求去线程池中调用线程处理,如果请求堆积过多的情况下,有可能会导致服务器崩溃。所以一般都会在nginx入口实现限流。
●http请求处理比较耗时的业务逻辑情况下,容易造成客户端(Client)一直等待,阻塞等待过程中会导致客户端超时发生重试策略,有可能会引发幂等性问题。
总结:综合以上Http请求缺点,如果接口是为Http协议的情况下,最好不要处理比较耗时的业务逻辑,耗时的业务逻辑应该单独交给多线程或者是mq去处理。
4.2MQ应用场景
结合上述总结可以知道,在处理Http请求比较耗时业务时,可以交给多线程或者是mq去处理,下面我们结合常见用户注册应用场景来解释这两者区别:
如上图所示,客户端发起一个注册用户请求,处理业务逻辑如下:
(1)InsertUser(插入用户信息),需要1秒处理时间。
(2)SendEmail(发送邮件),需要2秒处理时间。
(3)SendCoupons(发送优惠卷),需要3秒处理时间。
按照上述串行处理流程,该功能处理时间总共为6秒,这意味着用户需要等待6秒,这种用户体验是非常差的。下面再来看看多线程跟MQ如何处理这些业务逻辑。
●多线程处理
如上图所示,客户端发起一个注册用户请求到服务端后,插入用户信息同时开启一个线程处理发送邮件和优惠卷,当插入用户信息成功后立即响应状态给客户端,所以整个过程只花费1秒处理时间。
◎优点:适合小型项目,实现异步处理。
◎缺点:消耗服务器CPU资源,没有解耦。
●MQ处理
如上图所示,客户端发起一个注册用户请求到服务端后,插入用户信息同时往MQ投递一个消息处理发送邮件和优惠卷,当插入用户信息成功后立即响应给客户端,所以整个过程只花费1秒处理时间。
◎优点:适合中大型项目,实现异步处理,流量削峰、降低耦合度。
◎缺点:增加系统复杂度。
5.主流MQ区别对比
|
特性 |
ActiveMQ |
RabbitMQ |
RocketMQ |
Kafka |
|
开发语言 |
java |
erlang |
java |
scala |
|
单机吞吐量 |
万级 |
万级 |
10万级 |
10万级 |
|
时效性 |
ms级 |
us级 |
ms级 |
ms级以内 |
|
可用性 |
高(主从架构) |
高(主从架构) |
非常高(分布式架构) |
非常高(分布式架构) |
|
功能特性 |
成熟的产品,在很多公司得到应用,有较多的文档,各种协议支持较好。 |
基于erlang开发,所以并发能力很强,性能极其好,延时很低管理界面较丰富。 |
MQ功能比较完备,扩展性佳。 |
只支持主要的MQ功能,像一些消息查询,消息回溯等功能没有提供,毕竟是为大数据准备的,在大数据领域应用广。 |
参考文献:
RabbitMQ实战指南
(2)RabbitMQ架构设计与应用场景的更多相关文章
- TYPESDK手游聚合SDK服务端设计思路与架构之一:应用场景分析
TYPESDK 服务端设计思路与架构之一:应用场景分析 作为一个渠道SDK统一接入框架,TYPESDK从一开始,所面对的需求场景就是多款游戏,通过一个统一的SDK服务端,能够同时接入几十个甚至几百个各 ...
- 亿级流量场景下,大型架构设计实现【2】---storm篇
承接之前的博:亿级流量场景下,大型缓存架构设计实现 续写本博客: ****************** start: 接下来,我们是要讲解商品详情页缓存架构,缓存预热和解决方案,缓存预热可能导致整个系 ...
- 亿级流量场景下,大型缓存架构设计实现【1】---redis篇
*****************开篇介绍**************** -------------------------------------------------------------- ...
- 聊聊Zookeeper应用场景、架构设计、选主机制
Zookeeper作为一个分布式协调系统提供了一项基本服务:分布式锁服务,分布式锁是分布式协调技术实现的核心内容.像配置管理.任务分发.组服务.分布式消息队列.分布式通知/协调等,这些应用实际上都是基 ...
- 两年内从零到每月十亿 PV 的发展来谈 Pinterest 的架构设计(转)
原文:Scaling Pinterest - From 0 To 10s Of Billions Of Page Views A Month In Two Years 译文:两年内从零到每月十亿 PV ...
- EF6多线程与分库架构设计之Repository
1.项目背景 这里简单介绍一下项目需求背景,之前公司的项目基于EF++Repository+UnitOfWork的框架设计的,其中涉及到的技术有RabbitMq消息队列,Autofac依赖注入等常用的 ...
- EF6的多线程与分库架构设计实现
1.项目背景 这里简单介绍一下项目需求背景,之前公司的项目基于EF++Repository+UnitOfWork的框架设计的,其中涉及到的技术有RabbitMq消息队列,Autofac依赖注入等常用的 ...
- .net core实践系列之短信服务-架构设计
前言 上篇<.net core实践系列之短信服务-为什么选择.net core(开篇)>简单的介绍了(水了一篇).net core.这次针对短信服务的架构设计和技术栈的简析. 源码地址:h ...
- 架构设计:系统间通信(20)——MQ:消息协议(下)
(接上文<架构设计:系统间通信(19)--MQ:消息协议(上)>) 上篇文章中我们重点讨论了"协议"的重要性.并为各位读者介绍了Stomp协议和XMPP协议. 这两种协 ...
随机推荐
- cmake全面教程
1. 官网教程 2. 中文教程 3. Modern CMake
- The All-purpose Zero(hdu5773)
The All-purpose Zero Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Oth ...
- <数据结构>XDOJ314.完全二叉树的子树
问题与解答 问题描述 对一棵完全二叉树,采用自上而下.自左往右的方式从1开始编号,我们已知这个二叉树的最后一个结点是n,现在的问题是结点m所在的子树一共包括多少个结点? 输入格式 输入数据包括多行,每 ...
- win10系统微软账号登陆错误报错误码0x80190001
https://blog.csdn.net/u012878537/article/details/91353248 使用onenote同步的时候报出这样的错误. 知道问题出在了哪里,就容易解决了不是. ...
- Standalone集群搭建和Spark应用监控
注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6815920501530034696/ 承接上一篇文档<Spark词频前十的统计练习> Spark on ...
- .net core 和 WPF 开发升讯威在线客服系统:调用百度翻译接口实现实时自动翻译
业余时间用 .net core 写了一个在线客服系统.并在博客园写了一个系列的文章,写介绍这个开发过程. 我把这款业余时间写的小系统丢在网上,陆续有人找我要私有化版本,我都给了,毕竟软件业的初衷就是免 ...
- SYCOJ2197三角形游戏
题目-三角形游戏 (shiyancang.cn) 对于任意的一个数字,把他拆分为n个数字,使得其逐层和为该数字. 首先n很小,所以很可能是搜索.DFS,n回选择. #include<bits/s ...
- C# 开源一个基于 yarp 的 API 网关 Demo,支持绑定 Kubernetes Service
关于 Neting 刚开始的时候是打算使用微软官方的 Yarp 库,实现一个 API 网关,后面发现坑比较多,弄起来比较麻烦,就放弃了.目前写完了查看 Kubernetes Service 信息.创建 ...
- Rust学习(一)
为什么学习Rust 最近在看Linux相关新闻的时候,看到了Linux内核正在将Rust集成至内核内的消息,且越来越多的嵌入式开发可以使用Rust编程.以往笔者的技术栈只有 C语言 ,C++也只是浅尝 ...
- 【Java】java基础
文章目录 Java基础 1 注释.标识符.关键字 1.1 注释 1.2 关键字 1.3 标识符 1.4 数据类型 1.4.1 基本类型 1.4.2 引用类型 1.4.3 整数类型拓展 1.4.4 浮点 ...