Java架构之消息队列 (一):消息队列的概述
消息队列系列分享大纲:
一、消息队列的概述
二、消息队列之RabbitMQ的使用
三、消息队列之Kafka的使用
四、消息队列之RabbitMQ的原理详解
五、消息队列之Kafka的原理详解
六、消息队列之面试集锦
1.消息队列的概述
消息队列(Message Queue)中间件是分布式系统中重要的组件; 主要解决应用耦合,异步消息,流量削锋等问题; 实现高性能,高可用,可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件; 目前在生产环境,使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ等; 部分数据库如Redis、Mysql以及phxsql也可实现消息队列的功能; 具有 低耦合、可靠投递、广播、流量控制、最终一致性 等一系列功能。 |
2.消息队列使用场景
消息队列在实际应用中有四个场景:
- 应用耦合:多应用间通过消息队列对同一消息进行处理,避免调用接口失败导致整个过程失败;
- 异步处理:多应用对消息队列中同一消息进行处理,应用间并发处理消息,相比串行处理,减少处理时间;
- 限流削峰:广泛应用于秒杀或抢购活动中,避免流量过大导致应用系统挂掉的情况;
- 消息驱动的系统:系统分为消息队列、消息生产者、消息消费者,生产者负责产生消息,消费者(可能有多个)负责对消息进行处理;
2.1异步处理
具体场景:用户为了使用某个应用,进行注册,系统需要发送注册邮件并验证短信。对这两个操作的处理方式有两种:串行及并行
(1)串行方式:新注册信息生成后,先发送注册邮件,再发送验证短信;
在这种方式下,需要最终发送验证短信后再返回给客户端。
(2)并行处理:新注册信息写入后,由发短信和发邮件并行处理;
在这种方式下,发短信和发邮件 需处理完成后再返回给客户端。
假设以上三个子系统处理的时间均为50ms,且不考虑网络延迟,则总的处理时间:
串行:50+50+50=150ms 并行:50+50 = 100ms
若使用消息队列:
并在写入消息队列后立即返回成功给客户端,则总的响应时间依赖于写入消息队列的时间,而写入消息队列的时间本身是可以很快的,基本可以忽略不计,因此总的处理时间相比串行提高了2倍,相比并行提高了一倍;
2.2 应用耦合
具体场景:用户使用QQ相册上传一张图片,人脸识别系统会对该图片进行人脸识别,一般的做法是,服务器接收到图片后,图片上传系统立即调用人脸识别系统,调用完成后再返回成功,如下图所示:
该方法有如下缺点:
- 人脸识别系统被调失败,导致图片上传失败;
- 延迟高,需要人脸识别系统处理完成后,再返回给客户端,即使用户并不需要立即知道结果;
- 图片上传系统与人脸识别系统之间互相调用,需要做耦合;
若使用消息队列:
客户端上传图片后,图片上传系统将图片信息写入消息队列,直接返回成功;而人脸识别系统则定时从消息队列中取数据,完成对新增图片的识别。
人脸识别系统可以选择不同的调度策略,按照闲时、忙时、正常时间,对队列中的图片信息进行处理。
2.3 限流削峰
具体场景:购物网站开展秒杀活动,一般由于瞬时访问量过大,服务器接收过大,会导致流量暴增,相关系统无法处理请求甚至崩溃。而加入消息队列后,系统可以从消息队列中取数据,相当于消息队列做了一次缓冲。
该方法有如下优点:
- 请求先入消息队列,而不是由业务处理系统直接处理,做了一次缓冲,极大地减少了业务处理系统的压力;
- 队列长度可以做限制,事实上,秒杀时,后入队列的用户无法秒杀到商品,这些请求可以直接被抛弃,返回活动已结束或商品已售完信息;
2.4 日志处理
日志处理是指将消息队列用在日志处理中,比如Kafka的应用,解决大量日志传输的问题。架构简化如下:
消息队列应用于日志处理的架构
- 日志采集客户端:负责日志数据采集,定时写受写入Kafka队列;
- Kafka消息队列:负责日志数据的接收,存储和转发;
- 日志处理应用:订阅并消费kafka队列中的日志数据;
|
2.5消息通讯
消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。
点对点通讯:
客户端A和客户端B使用同一队列,进行消息通讯。
聊天室通讯:
客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。
以上实际是消息队列的两种消息模式,点对点或发布订阅模式,下面会介绍这两种模式。
3.消息队列的两种模式
消息队列包括两种模式,点对点模式(point to point, queue)和发布/订阅模式(publish/subscribe,topic)。 JMS(JAVA Message Service,java消息服务)API是一个消息服务的标准/规范,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。 在JMS标准中,有两种消息模型P2P(Point to Point),Publish/Subscribe(Pub/Sub)。 |
3.1 点对点模式
点对点模式下包括三个角色:
- 消息队列
- 发送者 (生产者)
- 接收者(消费者)
消息发送者生产消息发送到queue中,然后消息接收者从queue中取出并且消费消息。消息被消费以后,queue中不再有存储,所以消息接收者不可能消费到已经被消费的消息。
点对点模式特点:
- 每个消息只有一个接收者(Consumer)(即一旦被消费,消息就不再在消息队列中);
- 发送者和接收者间没有依赖性,发送者发送消息之后,不管有没有接收者在运行,都不会影响到发送者下次发送消息;
- 接收者在成功接收消息之后需向队列应答成功,以便消息队列删除当前接收的消息;
3.2 发布/订阅模式
发布/订阅模式下包括三个角色:
- 角色主题(Topic)
- 发布者(Publisher)
- 订阅者(Subscriber)
发布者将消息发送到Topic,系统将这些消息传递给多个订阅者。
发布/订阅模式特点:
- 每个消息可以有多个订阅者;
- 发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息。
- 为了消费消息,订阅者需要提前订阅该角色主题,并保持在线运行;
4.消息中间件案例
3.1电商系统
消息队列采用高可用,可持久化的消息中间件。比如Active MQ,Rabbit MQ,Rocket Mq。
(1)应用将主干逻辑处理完成后,写入消息队列。消息发送是否成功可以开启消息的确认模式。(消息队列返回消息接收成功状态后,应用再返回,这样保障消息的完整性)
(2)扩展流程(发短信,配送处理)订阅队列消息。采用推或拉的方式获取消息并处理。
(3)消息将应用解耦的同时,带来了数据一致性问题,可以采用最终一致性方式解决。比如主数据写入数据库,扩展应用根据消息队列,并结合数据库方式实现基于消息队列的后续处理。
3.2日志收集系统
分为Zookeeper注册中心,日志收集客户端,Kafka集群和Storm集群(OtherApp)四部分组成。
- Zookeeper注册中心,提出负载均衡和地址查找服务;
- 日志收集客户端,用于采集应用系统的日志,并将数据推送到kafka队列;
- Kafka集群:接收,路由,存储,转发等消息处理;
Storm集群:与OtherApp处于同一级别,采用拉的方式消费队列中的数据;
5.常用消息队列介绍
5.1.ZeroMQ
ZeroMQ号称是“史上最快的消息队列”,基于c语言开发的,可以在任何平台通过任何代码连接,通过inproc、IPC、TCP、TIPC、多播传送消息,支持发布-订阅、推-拉、共享队列等模式,高速异步I/O引擎。 根据官方的说法,ZeroMQ是一个简单好用的传输层,像框架一样的可嵌入的socket类库,使Socket编程更加简单、简洁、性能更高,是专门为高吞吐量/低延迟的场景开发的。ZeroMQ与其他MQ有着本质的区别,它根本不是消息队列服务器,更类似与一个底层网络通讯库,对原有Socket API进行封装,在使用的使用引入对应的jar包即可,可谓是相当灵活。 同时,因为它的简单灵活,如果我们想作为消息队列使用的话,需要开发大量代码。而且,ZeroMQ不支持消息持久化,其定位并不是安全可靠的消息传输,所以还需要自己编码保证可靠性。简而言之一句话,ZeroMQ很强大,但是想用好需要自己实现。 特点是:
ZeroMQ高性能设计要点: 1、无锁的队列模型 对于跨线程间的交互(用户端和session)之间的数据交换通道pipe,采用无锁的队列算法CAS;在pipe两端注册有异步事件,在读或者写消息到pipe的时,会自动触发读写事件。 2、批量处理的算法 对于传统的消息处理,每个消息在发送和接收的时候,都需要系统的调用,这样对于大量的消息,系统的开销比较大,zeroMQ对于批量的消息,进行了适应性的优化,可以批量的接收和发送消息。 3、多核下的线程绑定,无须CPU切换 区别于传统的多线程并发模式,信号量或者临界区, zeroMQ充分利用多核的优势,每个核绑定运行一个工作者线程,避免多线程之间的CPU切换开销。 |
5.2 ActiveMQ
ActiveMQ是由Apache出品,ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现。它非常快速,支持多种语言的客户端和协议,而且可以非常容易的嵌入到企业的应用环境中,并有许多高级功能。 主要特性:
使用ActiveMQ需要:
ActiveMQ可以运行在Java语言所支持的平台之上。 优点:
缺点:
|
5.3.RabbitMQ
概述: RabbitMQ是流行的开源消息队列系统,用erlang语言开发。 RabbitMQ是AMQP(高级消息队列协议)的标准实现。 支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX,持久化。 用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。 主要特性:
优点:
缺点:
|
重要概念:
消息队列的使用过程,如下:
|
5.4.RocketMQ
RocketMQ出自 阿里公司的开源产品,用 Java 语言实现,在设计时参考了 Kafka,并做出了自己的一些改进,消息可靠性上比 Kafka 更好。RocketMQ在阿里集团被广泛应用在订单,交易,充值,流计算,消息推送,日志流式处理,binglog分发等场景。 主要特性:
使用RocketMQ需要:
RocketMQ可以运行在Java语言所支持的平台之上。 优点:
缺点:
|
5.5 Kafka
Apache Kafka是一个分布式消息发布订阅系统。它最初由LinkedIn公司基于独特的设计实现为一个分布式的提交日志系统( a distributed commit log),,之后成为Apache项目的一部分。Kafka系统快速、可扩展并且可持久化。它的分区特性,可复制和可容错都是其不错的特性。 主要特性:
使用Kafka需要:
优点:
缺点:
|
5.6 Apollo
Apache称Apollo为最快、最强健的STOMP服务器。支持STOMP、AMQP、MQTT、OpenWire协议,支持Topic、Queue、持久订阅等消费形式,支持对消息的多种处理,支持安全性处理,支持REST管理API。。。功能列表很长,最大的弊病就是目前市场接收度不够,所以使用的并不广泛。 |
6. RabbitMQ/ActiveMQ/RocketMQ/Kafka对比
结论:
Kafka在于分布式架构,RabbitMQ基于AMQP协议来实现,RocketMQ/思路来源于kafka,改成了主从结构,在事务性可靠性方面做了优化。广泛来说,电商、金融等对事务性要求很高的,可以考虑RabbitMQ和RocketMQ,对性能要求高的可考虑Kafka。
7.消息队列MQ选型
综合上面的材料得出以下两点: 建议选RabbitMQ erlang语言天生具备高并发的特性,而且他的管理界面用起来十分方便。正所谓,成也萧何,败也萧何!他的弊端也在这里,虽然RabbitMQ是开源的,然而国内有几个能定制化开发erlang的程序员呢?所幸,RabbitMQ的社区十分活跃,可以解决开发过程中遇到的bug,这点对于中小型公司来说十分重要。 不考虑rocketmq和kafka的原因是,一方面中小型软件公司不如互联网公司,数据量没那么大,选消息中间件,应首选功能比较完备的,所以kafka排除。不考虑rocketmq的原因是,rocketmq是阿里出品,如果阿里放弃维护rocketmq,中小型公司一般抽不出人来进行rocketmq的定制化开发,因此不推荐。 根据具体使用在rocketMq和kafka之间二选一。 大型软件公司,具备足够的资金搭建分布式环境,也具备足够大的数据量。针对rocketMQ,大型软件公司也可以抽出人手对rocketMQ进行定制化开发,毕竟国内有能力改JAVA源码的人,还是相当多的。 至于kafka,根据业务场景选择,如果有日志采集功能,肯定是首选kafka了。具体该选哪个,看使用场景。 |