背景

RabbitMQ现在用的也比较多,但是没有过去那么多啦。现在很多的流行或者常用技术或者思路都是从过去的思路中演变而来的。了解一些过去的技术,对有些人来说可能会产生众里寻他千百度的顿悟,加深对技术的理解,更好的应用于工作中去。

本篇整体采用从浅到深的逻辑结构来描述。

入门部分

什么是MQ

MQ全称是Message Queue,消息的队列。因为是队列,所以遵循FIFO先进先出原则。因为存放的是消息,所以是一种跨进程的通信机制。

为什么使用MQ

流量削峰

这个跟很火的小吃店门口的排队原理是一样的。实时调用就好像是大家蜂拥而至,如果系统处理能力不够,就会让店家手忙脚乱,说不定会在冰激凌上浇上可乐。排队能保证有条不紊,代价是整体处理速度会慢些。

异步处理

当A调用B,B可能要花很长一段时间来完成。这时候一般有三种方式来异步处理。A调用B,B返回A说收到调用请求了。同步请求已经完成,但B的执行才刚开始。这时候,第一种方式是A每隔一段时间来查询一次,看B是否执行完,这是拉的方式;第二种方式是A提供一个回调地址,B执行完之后回调A,这是推的方式;第三种就是使用MQ,A使用MQ给B发消息,B处理完再回一个消息,好处是上面提到的同时可以流量削峰。

应用解耦

MQ实现了逻辑解耦+物理解耦。逻辑上,将请求和结果处理分开了;物理上,系统只用与MQ通信。听起来,MQ要优雅很多,但是上面提到异步处理的三种方式的前两种,现在也多很常见。那是因为MQ是有代价的,那就是需要一套MQ设施。做开放平台,用户之间的唯一设施就是互联网,这时候更依赖双方的协议约定,所以前两种异步处理方式不会被MQ取代。

MQ的分类

ActiveMQ是早期的MQ,倚老卖老一下,我那个年代用过,目前优势已经不太明显了。

Kafka号称是大数据的杀手锏,以百万级TPS吞吐量名声大噪。时效是ms级别,分布式的可用性高。消费者采用拉的方式获取消息,消息有序,通过控制可以保证消息仅被消费一次。但是单机超过64个分区,load会明显飙高;实时性取决于轮询时间间隔,关键是有可能丢消息,不适合订单业务中使用。

RocketMQ是国货,用Java语言实现,在设计时参考了Kafka,单机吞吐量达到十万级别,分布式架构可用性高,消息可以0丢失,扩展性高。但是支持的客户端成熟的也就是Java,核心代码没有实现JMS,迁移需要修改大量代码。

RabbitMQ是erlang开发的,吞吐量达到万级别,稳定、健壮、跨平台,支持多种语言,企业间通信中常用。

JMS支持

RabbitMQ不支持JMS协议。这个很好理解。因为JMS是Java消息服务,提供了消息传递的Java标准API。而RabbitMQ是Erlang写的,对Java的支持会弱一些。但是RabiitMQ实现了AMQP标准协议。AMQP只是统一了数据交换的标准格式,与语言无关。

核心部分

核心概念

所有的MQ都由生产者、消费者和broker(队列)三部分组成。但是不同的实现,根据核心思想不同,内部结构也各有特色。

比如银行系统中常用的跨银行间通信的MQ,相当于两组MQ拼起来的。

普通MQ

跨企业MQ

这样做的好处是任何一端网络出现问题,都可以暂存消息,等待网络恢复,不丢失消息。消息的重试放在broker端,减少了应用端的复杂度。为什么这里举例时提到银行间使用呢,因为使用这种模式的MQ,最重要的是有钱。因为想达到理想效果,要拉专线,并使用高配机器。

RabbitMQ和Kafka是一样的

再回来考虑普通MQ的场景,如果这个MQ是RabbitMQ。组件细化一下是这样:

这张图上来看,其实RabbitMQ和Kafka是一样的。来看Kafka的:

表面上来看,RabbitMQ的服务器(Broker)端由Exchange和Queue两部分组成。Exchange是交换机,交换机是做路由的。Kafka生产者发到Broker也需要路由啊,来决定路由到哪个Partition(也就是队列)中去。只不过Kafka的路由模式很固定,就是先找到哪个topic,然后使用负载均衡的策略找到一个Partition来投递消息。Kafka是用了逻辑概念topic简化了exchange路由,所以Kafka的路由功能也很单一。

表面上,RabbitMQ的生产者和消费者与服务端都是Channel信道来相连。Channel是复用连接来进行通信的,Kafka也是需要的,只是它内部帮我们把这些与核心功能关系不大的都自己内置实现了。而RabbitMQ暴露给用户,提供了更高的灵活性。

上面的两段如果我没有讲明白,也没有关系。只要知道更年轻的Kafka没有Exchange和Channel的概念是类似于采取了约定大于配置的方式提供的服务。

核心功能

RabbitMQ的核心实际上就是AMQP的核心:MessageQueue、Exchange和Binding。

MessageQueue就是消息队列,一个队列里的一条消息,也就是同一个message ID对应的消息,不管有多少个消费者来分摊压力,也只能被消费一次。消息队列和消费者之间有ack机制,消息一旦确认安全送达,RabbitMQ服务端就可以安全删除消息了。

Binding是MessageQueue与Exchange之间的连接,Exchange只能给Binding的MessageQueue发送消息。

Exchange有四种类型:fanout、topic、direct和header。本质上就是有一堆MessageQueue,一个消息是要被复制几份,发到哪几个Binding的消息队列去。Exchange给定了规则:fanout是对每个消息队列复制一份发送;direct意思是只发指定的一份,不复制;topic是发送通配符匹配的几份;header可以指定一些其他的过滤条件发送。消息从生产者发送到exchange之后也有ack机制来保证消息的可靠传输。

Kafka只有topic的概念。这是因为Kafka的设计上消息只用存一份,通过游标,发送后不立即删除消息。多个消费者组可以互不影响的消费。这是Kafka的一大改进。

内部原理

大家面试时有没有被问过:Kafka怎么保证消息能且仅能收到一次?这是个埋坑题,是与面试官斗智斗勇的开始。什么幂等、事务、流式EOS呀,其实呢,Kafka本身是不保证仅且仅收到一次的,所以这些实现方法都不优雅。

RabbitMQ通过AMQP事务机制,还有上面已经提过的ack也就是confirm两种可选方式保证消息被收到。

但是最为优雅的实现是IBM的Websphere MQ。因为这是收费的,所以研究的人不多。它通过消息序列号保证消息不丢失、不重传。

通道为每条消息的传送分配一个序列号,它会自动累积增值。消息序列号由发送通道分配,是通道的一个永久属性,每当发送一条消息,消息序列号就加一。通道的相关属性SEQWRAP标识序号的最大值,缺省为999,999,999。序列号越界后自动归零,从头开始。

正常情况下,通道两端的消息序列号或者相等或相差为一。双方对前面的某一条或一批消息是否发送成功理解不一致。在解决了不确定的消息后,可以用MQSC命令通过重置消息序号将双方调整到一致。一旦连接断开后,通道重连时双方会将消息序号同步。

推荐阅读

常用逻辑结构

实战并发-使用分布式缓存和有限状态机

应用角度看kafka的术语和功能

稳定性五件套-限流的原理和实现

RabbitMQ设计原理解析的更多相关文章

  1. Spring IOC设计原理解析:本文乃学习整理参考而来

    Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. I ...

  2. 图解kafka - 设计原理解析

    什么是消息队列? 简单来说,消息队列是存放消息的容器.客户端可以将消息发送到消息服务器,也可以从消息服务器获取消息. 问题导读: ********* 为什么需要消息系统? kafka架构? kafka ...

  3. Spring技术内幕——深入解析Spring架构与设计原理(一)IOC实现原理

    IOC的基础 下面我们从IOC/AOP开始,它们是Spring平台实现的核心部分:虽然,我们一开始大多只是在这个层面上,做一些配置和外部特性的使用工作,但对这两个核心模块工作原理和运作机制的理解,对深 ...

  4. html5设计原理(转)

    转自:   http://www.cn-cuckoo.com/2010/10/21/the-design-of-html5-2151.html 今天我想跟大家谈一谈HTML5的设计.主要分两个方面:一 ...

  5. Android中插件开发篇之----应用换肤原理解析

    一.前言 今天又到周末了,感觉时间过的很快呀.又要写blog了.那么今天就来看看应用的换肤原理解析.在之前的一篇博客中我说道了Android中的插件开发篇的基础:类加载器的相关知识.没看过的同学可以转 ...

  6. Volley 实现原理解析(转)

    Volley 实现原理解析 转自:http://blog.csdn.net/fengqiaoyebo2008/article/details/42963915 1. 功能介绍 1.1. Volley ...

  7. 学习HTML5必读之《HTML5设计原理》

    引子:很久前看过的一遍受益匪浅的文章,今天再次转过来,希望对学习HTML5的朋友有所帮助. 今天我想跟大家谈一谈HTML5的设计.主要分两个方面:一方面,当然了,就是HTML5.我可以站在这儿只讲HT ...

  8. 分布式文件系统FastDFS设计原理

    原文地址: http://blog.chinaunix.net/uid-20196318-id-4058561.html FastDFS是一个开源的轻量级分布式文件系统,由跟踪服务器(tracker ...

  9. BeanFactory容器的设计原理

    XmlBeanFactory设计的类继承关系 1.BeanFactory接口提供了使用IoC容器的规范.在这个基础上,Spring还提供了符合这个IoC容器接口的一系列容器的实现供开发人员使用. 2. ...

随机推荐

  1. Shell脚本一键部署——源码编译安装MySQL及自动补全工具

    Shell脚本一键部署--源码编译安装MySQL及自动补全工具 编译安装MySQL 1.软件包 Mysql安装包 将安装包拖至/opt目录下,编辑一个脚本文件,将以下内容复制进去,然后source或者 ...

  2. Qt 程序发布以及打包成exe安装包

    一.简述 Qt 项目开发完成之后,需要打包发布程序,而因为用户电脑上没有 Qt 配置环境,所以需要将 release 生成的 exe 文件和所依赖的 dll 文件复制到一个文件夹中,然后再用 Inno ...

  3. IPSEC的实现方式

    IPSEC的实现方式 在IPSEC通信中涉及到一个重要方面,那就是如何定义要保护的数据流(又称为感兴趣流).这不仅涉及到IPSEC最终要保护哪部分数据,还关系到IPSEC的实现方式,因此有必要把感兴趣 ...

  4. 清除router路由后面的参数

    清除router参数: 1.this.$router.push({ query: {}}) 2.var path = this.$route.path; //获取路由路径    this.$route ...

  5. Docker 安装 MySQL5.6

    方法一.docker pull mysql查找Docker Hub上的mysql镜像 #docker search mysql 这里我们拉取官方的镜像,标签为5.6 #docker pull mysq ...

  6. Android系统编程入门系列之应用数据文件化保存

    应用中关于数据的持久化保存,不管是简单的SharedPreferences还是数据库SQLiteDatabase,本质上都是将数据保存到系统的某种类型的文件中.因此可以直接使用java.io.File ...

  7. 自制计算器 v1.1

    之前的v1.0版本功能还不够完善,这个版本一并做了修改. 代码,每个sub表示哪个按钮做了注释. Dim a, temp, ans As Integer Dim op As String Sub sh ...

  8. CI框架页面打开空白,无报错为解决方法新环境

    1.打开错误显示,可以在控制controllers的首页入口加入以下代码,查看错误 error_reporting(-1); ini_set('display_errors', 1); //插入显示所 ...

  9. 用tcping检查网站开放的端口

    麦新杰之前分享过一款小巧玲珑工具软件:tcping,即在tcp层进行端口的ping. tcping可以用来检查和确认我们的网站有哪些端口是开放的,使用很顺手.比如麦新杰这几天在研究如何关闭mysql的 ...

  10. 给你一个app,怎么测试

    安装卸载 安装卸载路径是否能自己选择,在不同操作系统下(Android.ios)安装是否正常,能正常运行,安装的文件及文件夹是否写入了指定的目录里,安装来自不同来源的(应用宝.360助手)下是否正常. ...