1、先进先出
不能先进先出,都不能说是队列了。消息队列的顺序在入队的时候就基本已经确定了,一般是不需人工干预的。而且,最重要的是,数据是只有一条数据在使用中。 这也是MQ在诸多场景被使用的原因。
2、发布订阅
发布订阅是一种很高效的处理方式,如果不发生阻塞,基本可以当做是同步操作。这种处理方式能非常有效的提升服务器利用率,这样的应用场景非常广泛。
3、持久化
持久化确保MQ的使用不只是一个部分场景的辅助工具,而是让MQ能像数据库一样存储核心的数据。
4、分布式
在现在大流量、大数据的使用场景下,只支持单体应用的服务器软件基本是无法使用的,支持分布式的部署,才能被广泛使用。而且,MQ的定位就是一个高性能的
1、为什么要使用消息队列? 以下六个字:解耦、异步、削峰
(1)解耦
传统模式:
传统模式的缺点:
中间件模式:
中间件模式的的优点:
(2)异步
传统模式:
传统模式的缺点:
中间件模式:
中间件模式的的优点:
(3)削峰
传统模式
传统模式的缺点:
中间件模式:
中间件模式的的优点:
RabbitMQ是一个分布式系统,这里面有几个抽象概念。
1:broker:每个节点运行的服务程序,功能为维护该节点的队列的增删以及转发队列操作请求。
2:master queue:每个队列都分为一个主队列和若干个镜像队列。
3:mirror queue:镜像队列,作为master queue的备份。在master queue所在节点挂掉之后,系统把mirror queue提升为master queue,负责处理客户端队列操作请求。注意,mirror queue只做镜像,设计目的不是为了承担客户端读写压力。
如上图所示,集群中有两个节点,每个节点上有一个broker,每个broker负责本机上队列的维护,并且borker之间可以互相通信。集群中有两个队列A和B,每个队列都分为master queue和mirror queue(备份)。那么队列上的生产消费怎么实现的呢?
队列消费
如上图有两个consumer消费队列A,这两个consumer连在了集群的不同机器上。RabbitMQ集群中的任何一个节点都拥有集群上所有队列的元信息,所以连接到集群中的任何一个节点都可以,主要区别在于有的consumer连在master queue所在节点,有的连在非master queue节点上。
因为mirror queue要和master queue保持一致,故需要同步机制,正因为一致性的限制,导致所有的读写操作都必须都操作在master queue上(想想,为啥读也要从master queue中读?和数据库读写分离是不一样的。),然后由master节点同步操作到mirror queue所在的节点。即使consumer连接到了非master queue节点,该consumer的操作也会被路由到master queue所在的节点上,这样才能进行消费。
队列生产
原理和消费一样,如果连接到非 master queue 节点,则路由过去。
所以,到这里小伙伴们就可以看到 RabbitMQ的不足:由于master queue单节点,导致性能瓶颈,吞吐量受限。虽然为了提高性能,内部使用了Erlang这个语言实现,但是终究摆脱不了架构设计上的致命缺陷。
1、话题(Topic):是特定类型的消息流。消息是字节的有效负载(Payload),话题是消息的分类名或种子(Feed)名;
2、生产者(Producer):是能够发布消息到话题的任何对象;
3、服务代理(Broker):已发布的消息保存在一组服务器中,它们被称为代理(Broker)或Kafka集群;安装了kafka的服务器就是一个broker。
4、消费者(Consumer):可以订阅一个或多个话题,并从Broker拉数据,从而消费这些已发布的消息;
上图中可以看出,生产者将数据发送到Broker代理,Broker代理有多个话题topic,消费者从Broker获取数据。
由此可见,Kafka绝对是为了高吞吐量设计的,比如设置分片数为100,那么就有100台机器去扛一个Topic的流量,当然比RabbitMQ的单机性能好。
如下图:一个topic 可以有多个partition,每个partition有一个leader副本和多个follower副本
对于生产者而言把数据写到每个分区时,每条消息在所在分区是有一个递增的序号的,序号从 0 开始,这个序号就是 offset,offset 既反映了每条消息在分区中的相对位置,也唯一标识了一条消息,offset越小,消息越旧,最新写入的消息的 offset在当前分区总是最大的。
对于消费者而言也有offset,消费者的 offset 就是它消费过的最后一条消息的 offset,比如上图中,消费者 A 的 offset 是 9,消费者 B 的 offset 是 11,而这个分区中消息的最大 offset 正在变成 12。我认为消费者的 offset 的最大作用是:当消费者掉线之后,消费者重启后知道从哪条消息继续消费。
我们将消息的发布(publish)称作 producer,将消息的订阅(subscribe)表述为 consumer,将中间的存储阵列称作 broker(代理),这样就可以大致描绘出这样一个场面:
多个 broker 协同合作,producer 和 consumer 部署在各个业务逻辑中被频繁的调用,三者通过 zookeeper管理协调请求和转发。这样一个高性能的分布式消息发布订阅系统就完成了。
producer 到 broker 的过程是 push(推送),也就是有数据就推送到 broker,而 consumer 到 broker 的过程是 pull(拉取),是通过 consumer 主动去拉数据的,而不是 broker 把数据主懂发送到 consumer 端的。
1.高吞吐量、低延迟
kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒,每个topic可以分多个partition, consumer group 对partition进行consume操作。
2.可扩展性
kafka集群支持热扩展
3.持久性、可靠性
消息被持久化到本地磁盘,并且支持数据备份防止数据丢失
4.容错性
允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
5.高并发
支持数千个客户端同时读写
1.日志收集
一个公司可以用Kafka可以收集各种服务的log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
2.消息系统
解耦和生产者和消费者、缓存消息等。
3.用户活动跟踪
Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
4.运营指标
Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
5.流式处理
比如spark streaming和storm
高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒
1.应当有一个非常好的运维监控系统,不单单要监控Kafka本身,还要监控Zookeeper。(kafka强烈的依赖于zookeeper,如果zookeeper挂掉了,那么Kafka也不行了)
2.对消息顺序不依赖,且不是那么实时的系统。
3.对消息丢失并不那么敏感的系统。
4.从 A 到 B 的流传输,无需复杂的路由,最大吞吐量可达每秒 100k 以上。
Kafka是LinkedIn开源的分布式发布-订阅消息系统,目前归属于Apache顶级项目。Kafka主要特点是基于Pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输。0.8版本开始支持复制,不支持事务,对消息的重复、丢失、错误没有严格要求,适合产生大量数据的互联网服务的数据收集业务。
在可用性上,稳定性上,可靠性上,RabbitMq超过kafka
1.RabbitMQ的消息应当尽可能的小,并且只用来处理实时且要高可靠性的消息。
2.消费者和生产者的能力尽量对等,否则消息堆积会严重影响RabbitMQ的性能。
3.集群部署,使用热备,保证消息的可靠性。
RabbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。
RocketMQ是阿里开源的消息中间件,它是纯Java开发,具有高吞吐量、高可用性、适合大规模分布式系统应用的特点。RocketMQ思路起源于Kafka,但并不是Kafka的一个Copy,它对消息的可靠传输及事务性做了优化,目前在阿里集团被广泛应用于交易、充值、流计算、消息推送、日志流式处理、binglog分发等场景。
是一个Key-Value的NoSQL数据库,开发维护很活跃,虽然它是一个Key-Value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。测试数据分为128Bytes、512Bytes、1K和10K四个不同大小的数据。实验表明:入队时,当数据比较小时Redis的性能要高于RabbitMQ,而如果数据大小超过了10K,Redis则慢的无法忍受;出队时,无论数据大小,Redis都表现出非常好的性能,而RabbitMQ的出队性能则远低于Redis。
对比项 |
kafka |
rabbitmq |
单机吞吐量 |
10万级 |
万级 |
时效性 |
ms级以内 |
us级(微秒级) |
是否支持消息回溯 |
支持消息回溯,因为消息持久化,消息被消费后会记录offset和timstamp |
不支持,消息确认被消费后,会被删除 |
是否支持消息数据持久化 |
支持消息数据持久 |
支持消息数据持久 |
是否支持事务性消息 |
支持 |
不支持 |
优先级队列 |
不支持 |
支持。建议优先级大小设置在0-10之间。 |
延迟队列 |
不支持 |
支持 |
重试队列 |
不支持。 |
不支持RabbitMQ中可以参考延迟队列实现一个重试队列,二次封装比较简单。如果要在Kafka中实现重试队列,首先得实现延迟队列的功能,相对比较复杂。 |
是否支持消息堆积 |
支持消息堆积,并批量持久化到磁盘 |
支持阈值内的消息对接,无法支持较大的消息堆积 |
是否支持流量控制 |
支持控制用户和客户端流量 |
支持生产者的流量控制 |
开发语言 |
scala,Java |
erlang |
是否支持多租户 |
2.x.x支持多租户 |
支持多租户 |
是否支持topic优先级 |
不支持 |
支持 |
是否支持消息全局有序 |
不支持 |
支持 |
是否支持消息分区有序 |
支持 |
支持 |
是否内置监控 |
无内置监控 |
内置监控 |
是否支持多个生产者 |
一个topic支持多个生产者 |
|
是否支持多个消费者 |
一个topic支持多个消费者 |
|
是否支持一个分区多个消费者 |
不支持 |
不支持 |
是否支持JMX |
支持 |
不支持(非java语言编写) |
是否支持加密 |
支持 |
支持 |
消息队列协议支持 |
仅支持自定义协议 |
支持AMQP、MQTT、STOMP协议 |
客户端语言支持 |
支持多语言客户端 |
支持多语言客户端 |
是否支持消息追踪 |
不支持消息追踪 |
支持消息追踪 |
是否支持消费者推/拉模式 |
拉模式 |
推模式+拉模式 |
是否支持广播消息 |
支持广播消息 |
支持广播消息 |
元数据管理 |
通过zookeeper进行管理 |
支持消息数据持久 |
默认服务端口 |
9200 |
5672 |
默认监控端口 |
kafka web console 9000;kafka manager 9000; |
15672 |
网络开销 |
相对较小 |
相对较大 |
内存消耗 |
相对较小 |
相对较大 |
cpu消耗 |
相对较大 |
相对较小 |
消息一般有两种传递模式:点对点(P2P,Point-to-Point)模式和发布-订阅(Publish/Subscribe)模式
分析:我们在使用消息队列的过程中,应该做到消息不能多消费,也不能少消费。如果无法做到可靠性传输,可能给公司带来千万级别的财产损失。同样的,如果可靠性传输在使用过程中,没有考虑到,这不是给公司挖坑么,你可以拍拍屁股走了,公司损失的钱,谁承担。还是那句话,认真对待每一个项目,不要给公司挖坑。
回答:其实这个可靠性传输,每种MQ都要从三个角度来分析:生产者弄丢数据、消息队列弄丢数据、消费者弄丢数据
RabbitMQ
从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。
transaction机制就是说,发送消息前,开启事物(channel.txSelect()),然后发送消息,如果发送过程中出现什么异常,事物就会回滚(channel.txRollback()),如果发送成功则提交事物(channel.txCommit())。然而缺点就是吞吐量下降了
RabbitMQ 消费者如何保证消息不丢失?
RabbitMQ一般情况很少丢失,但是不能排除意外,为了保证我们自己系统高可用,我们必须作出更好完善措施,保证系统的稳定性。
下面来介绍下,如何保证消息的绝对不丢失的问题,下面分享的绝对干货,都是在知名互联网产品的产线中使用。
1.消息持久化
2.ACK确认机制
3.设置集群镜像模式
4.消息补偿机制
第一种:消息持久化
RabbitMQ 的消息默认存放在内存上面,如果不特别声明设置,消息不会持久化保存到硬盘上面的,如果节点重启或者意外crash掉,消息就会丢失。
所以就要对消息进行持久化处理。如何持久化,下面具体说明下:
要想做到消息持久化,必须满足以下三个条件,缺一不可。
1) Exchange 设置持久化
2)Queue 设置持久化
3)Message持久化发送:发送消息设置发送模式deliveryMode=2,代表持久化消息
第二种:ACK确认机制
多个消费者同时收取消息,比如消息接收到一半的时候,一个消费者死掉了(逻辑复杂时间太长,超时了或者消费被停机或者网络断开链接),如何保证消息不丢?
这个使用就要使用Message acknowledgment 机制,就是消费端消费完成要通知服务端,服务端才把消息从内存删除。
这样就解决了,及时一个消费者出了问题,没有同步消息给服务端,还有其他的消费端去消费,保证了消息不丢的case。
第三种:设置集群镜像模式
第四种:消息补偿机制
为什么还要消息补偿机制呢?难道消息还会丢失,没错,系统是在一个复杂的环境,不要想的太简单了,虽然以上的三种方案,基本可以保证消息的高可用不丢失的问题,
但是作为有追求的程序员来讲,要绝对保证我的系统的稳定性,有一种危机意识。
比如:持久化的消息,保存到硬盘过程中,当前队列节点挂了,存储节点硬盘又坏了,消息丢了,怎么办?
产线网络环境太复杂,所以不知数太多,消息补偿机制需要建立在消息要写入DB日志,发送日志,接受日志,两者的状态必须记录。
然后根据DB日志记录check 消息发送消费是否成功,不成功,进行消息补偿措施,重新发送消息处理。
参考网址:https://www.jianshu.com/p/3d15798b88d2