您的位置:首页 > 运维架构 > Apache

消息队列

2019-04-14 22:11 232 查看

消息队列扫盲

维基百科上的描述:在计算机科学中,消息队列(Message queue)是一种进程间通信或同一进程的不同线程间的通信方式,软件的贮列用来处理一系列的输入,通常是来自用户。 这个描述很生硬,对于没有接触过消息队列的你来说可能有点不好理解。

其实消息队列在上世纪八九十年代就有了,只不过它最早并不是用在目前我们所熟悉的互联网集群架构中。最近十几年,互联网发展太快,用户群体越来越大,早期的简单架构早就不能满足需求。所以聪明的架构师们,想尽各种办法解决一切瓶颈,其中消息队列就是一个典型代表。它目前被广泛使用在异步通信领域里。

什么叫异步?举个例子,用户在网站注册一个账号,需要通过邮件确认。正确的步骤是:1)用户填写信息(包括邮箱地址);2)服务器接收用户信息,写到数据库;3)服务器发送确认邮件给用户;4)网站提示用户注册完成。如果这4个步骤逐次完成,则整个流程耗费时间最大的是第三步,有可能需要不到1秒钟,也可能需要1分钟。所以,这样的设计最终会导致个别用户的不耐烦而放弃注册。

如果是异步的思路,那么会把第3步单独摘出来,也就是说不管用户有没有收到邮件,网站都会直接告诉用户注册成功了。这个设计没毛病,但是如何实现异步?这就用到了“消息队列”中间件。还接着说上面的小例子,在第二步的时候,服务器(其实是某个进程)除了将用户信息写入到数据库之外,它还会把用户的邮箱地址写入到消息队列里,而发送邮件的服务会到消息队列里取这个邮箱地址,然后再发邮件给那个邮箱地址。在这个过程中,写消息队列的服务(某个进程)和读消息队列的服务(发邮件的那个服务)没有直接关系,它们只需要专心写和读消息队列即可。

以上小例子,就是消息队列非常典型的一个应用场景。除了这种场景外,它还可以用在流量削峰的场景下。我想,你应该经历过双11淘宝秒抢商品吧,这个其实就是流量削峰。假如正常情况下一个网站架构最多承载1w人同时访问,但做活动时同时在线的人达到了100w,这时候要么增加服务器,要么限制在线活动的人。增加服务器的话,要考虑成本,一年就一次这样的大型活动,总不能为了这一次而增加99倍的设备,一点都不现实,所以只好限制在线活动的人数了。如何实现?消息队列可以做到,做活动时,先让大家排队,只放行1w人进入到消息队列里,而在消息队列里的这些人才可以进入到下一步的商品支付环节。进入消息队列的人支付完成,消息队列里面的人数减少,继续放行新的人进到消息队列里。

消息队列另外一个典型应用场景是解耦合,关于解耦合简单讲就是把本关联在一起的两个步骤拆分开,中间通过一个消息队列服务完成最终的通信,这其实也算是一种异步机制。

消息队列缺点

由于消息队列的异步特性,直接提升了整个架构的处理效率,提升了用户体验。但凡事都有两面性,消息队列在带来性能提升的同时也伴随着缺陷。

  • 系统可用性降低

    毕竟在整个架构中,我们单独加了一个消息队列中间件,所以增加了风险,如果消息队列服务挂掉,势必会影响到整个架构。

  • 系统复杂性提高

    本来非常简单的一个逻辑设计,但偏偏要在中间插入一个消息队列,所以这增加了程序员的工作量,需要考虑如何保证消息没有被重复消费、消息有没有丢失、消息顺序等细节问题。

  • 数据一致性无法保证

    消息如果没有正确写入到消息队列里,或者说读取消息的服务并没有正确读取到消息,这都会影响到数据的一致性。

消息队列点名

目前主流的几大消息队列有:RabitMQ、ActiveMQ、RocketMQ、Kafka、ZeroMQ等,也有一些小众的比如Beanstalk,当然我们之前学过的Redis也可以实现消息队列的功能。

下面关于几大消息队列的对比,我是从网上摘抄的,毕竟这几个消息队列我并没有完全深入研究过,只能借鉴别人的观点。

ActiveMQ基于JAVA语言开发,其社区算是比较成熟,但是目前来说,ActiveMQ的性能比较差,而且版本迭代很慢,不推荐使用。

RocketMQ阿里出品,Java系开源项目,源代码我们可以直接阅读,然后可以定制自己公司的MQ,并且RocketMQ有阿里巴巴的实际业务场景的实战考验。RocketMQ社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准JMS规范走的有些系统要迁移需要修改大量代码。还有就是阿里出台的技术,你得做好这个技术万一被抛弃,社区黄掉的风险,那如果你们公司有技术实力我觉得用RocketMQ挺好的

Kafka由Scala和Java编写,其特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展。同时kafka最好是支撑较少的topic数量即可,保证其超高吞吐量。Kafka唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略这个特性天然适合大数据实时计算以及日志收集。

RabbitMQ在吞吐量方面虽然稍逊于Kafka和RocketMQ ,但是由于它基于erlang开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。但是也因为RabbitMQ基于erlang开发,所以国内很少有公司有实力做erlang源码级别的研究和定制。如果业务场景对并发量要求不是太高(十万级、百万级),那这四种消息队列中,RabbitMQ一定是你的首选。如果是大数据领域的实时计算、日志采集等场景,用Kafka是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。

ZeroMQ只是一个网络编程的Pattern库,将常见的网络请求形式(分组管理,链接管理,发布订阅等)模式化、组件化,简而言之socket之上、MQ之下。对于MQ来说,网络传输只是它的一部分,更多需要处理的是消息存储、路由、Broker服务发现和查找、事务、消费模式(ack、重投等)、集群服务等。

RabbitMQ/Kafka/ZeroMQ都能提供消息队列服务,但有很大的区别。

在面向服务架构中通过消息代理(比如 RabbitMQ / Kafka等),使用生产者/消费者模式在服务间进行异步通信是一种比较好的思想。

ZeroMQ和RabbitMQ/Kafka 不同,它只是一个异步消息库,在套接字的基础上提供了类似于消息代理的机制。使用ZeroMQ的话,需要对自己的业务代码进行改造,不利于服务解耦。

RabbitMQ支持AMQP(二进制),STOMP(文本),MQTT(二进制),HTTP(里面包装其他协议)等协议。而Kafka使用自己的协议。

Kafka自身服务和消费者都需要依赖Zookeeper。

RabbitMQ在有大量消息堆积的情况下性能会下降,Kafka不会,毕竟AMQP设计的初衷不是用来持久化海量消息的,而Kafka一开始是用来处理海量日志的。

总的来说,RabbitMQ和Kafka都是十分优秀的分布式的消息代理服务,只要合理部署,不作,基本上可以满足生产条件下的任何需求。

给大家提供一个参考文档 https://www.zhihu.com/question/43557507

消息队列中角色/名词

  • Broker

    消息服务器,作为server提供消息核心服务

  • Producer

    消息生产者,业务的发起方,负责生产消息传输给broker

  • Consumer

    消息消费者,业务的处理方,负责从broker获取消息并进行业务逻辑处理

  • Topic

    主题,发布订阅模式下的消息统一汇集地,不同生产者向topic发送消息,由MQ服务器分发到不同的订阅者,实现消息的广播

  • Queue

    队列,PTP模式下,特定生产者向特定queue发送消息,消费者订阅特定的queue完成指定消息的接收

  • Message

    消息体,根据不同通信协议定义的固定格式进行编码的数据包,来封装业务数据,实现消息的传输

消息队列中两种工作模式

  • Point-to-Point

    其实就是点对点,其过程理解起来比较简单。它好比是两个人打电话,这两个人是独享这一条通信链路的。一方发送消息,另外一方接收,就这么简单。在点对点模式下,消息被保留在队列中。 一个或多个消费者可以消耗队列中的消息,但是特定消息只能由最多一个消费者消费。 一旦消费者读取队列中的消息,它就从该队列中消失。 该模式的典型示例,如订单处理系统,其中每个订单将由一个订单处理器处理,但多个订单处理器也可以同时工作。

  • Pub/Sub

    即发布/订阅模式,该模式有点类似于我们日常生活中订阅报纸。对于每一个订阅者来说,可以选择一份或者多份报纸。那么这些我们订阅的报纸,就相当于发布订阅模式里的topic。有很多个人订阅报纸,也有人可能和我订阅了相同的报纸。多人订阅了相同的报纸相当于多人在同一个topic里注册了。对于一份报纸发行方来说,它和所有的订阅者就构成了一个1对多的关系。在这种模式下,消息被保留在主题中。 与点对点模式不同,消费者可以订阅一个或多个主题并使用该主题中的所有消息。 该模式下消息生产者称为发布者,消息使用者称为订阅者。

(adsbygoogle = window.adsbygoogle || []).push({});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息