定义: 消息中间件属于分布式系统中一个子系统,关注于数据的发送和接收,利用高效可靠的异步消息传递机制对分布式系统中的其余各个子系统进行集成。本质是个队列,FIFO 先入先出,只不过队列中存放的内容是消息内容,还是一种跨进程的通信机制,用于上下游传递消息。在互联网架构中,MQ 是一种比较常见的上下游“逻辑解耦+物理解耦”的消息通信服务。使用了 MQ 之后,消息发送上游只需要依赖 MQ,不用依赖其他服务。
高效:
对于消息的处理处理速度快。
可靠:
一般消息中间件都会有消息持久化机制和其他的机制确保消息不丢失。
异步:
指发送完一个请求,不需要等待返回,随时可以再发送下一个请求,既不需要等待。 一句话总结,我们消息中间件不生产消息,只是消息的搬运工。
2.1. 应用解耦
以电商应用为例,应用中有订单系统、库存系统、物流系统、支付系统。用户创建订单后,如果耦合调用库存系统、物流系统、支付系统,任何一个子系统出了故障,都会造成下单操作异常。当转变成基于消息队列的方式后,系统间调用的问题会减少很多,如果物流系统宕机,需要时间来修复。在修复的时间里,物流系统要处理的内存被缓存在消息队列中,用户的下单操作可以正常完成。当物流系统恢复后,继续处理订单信息即可,中单用户感受不到物流系统的故障,提升系统的可用性。
2.2. 异步
用户注册后,需要发注册邮件和注册短信。
2.2.1. 采用同步的方式:
将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。
2.2.2.并行方式:
将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并 行的方式可以提高处理的时间。 假设三个业务节点每个使用 50 毫秒钟,不考虑网络等其他开销,则串行方式的时间是 150 毫秒,并行的时间可能是 100 毫秒。 小结:如以上案例描述,传统的方式系统的性能(并发量,吞吐量,响应时间)会有瓶颈。如何解决这个问题呢? 引入消息队列,将不是必须的业务逻辑,异步处理。
2.2.3.采用消息中间件:
用户的响应时间相当于是注册信息写入数据库的时间,也就是 50 毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入 消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是 50 毫秒。因此架构改变后,系统的吞吐量提高到每秒 20 QPS。比串行提高了 3 倍,比 并行提高了两倍。
2.3. 流量削峰
流量削峰也是消息队列中的常用场景,一般在秒杀或团抢活动中使用广泛。秒杀活动一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用中加入消息队列:可以控制活动的人 数;可以缓解短时间内高流量压垮应用。
用户发送请求,服务器接收后,写入消息队列;如果消息队列长度超过设置的最大数量,则直接跳转其他提示页面,秒杀业务则根据消息队列中的消息进行业务处理;
2.4.日志处理
日志分析是大规模分布式系统不可避免的一个环节,用于快速定位系统问题,高效运维,实现高可靠的系统。一般来说,日志分布在若干台机器上,借助于消息中间件,收集多台机器上的日志数据,统一到日志分析平台作处理;日志采集客户端,负责日志数据采集,定时写入 Kafka 队列:Kafka 消息队列,负责日志数据的接收,存储和转发;日志处理应用:订阅并消费 kafka 队列中的日志数据;
2.5.消息通讯
消息通讯是指,消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。 点对点通讯:客户端 A 和客户端 B 使用同一队列,进行消息通讯。 聊天室通讯:客户端 A,客户端 B,客户端 N 订阅同一主题,进行消息发布和接收。实现类似聊天室效果。但是,实际业务中要实现聊天通讯,一般用websocket来实现,更加便捷,轻量;
消息队列利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。目前业界有很多的 MQ 产品,例如 RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq 等,也有直接使用数据库 Redis 充当消息队列的案例。而这些消息队列产品,各有侧重,在实际选型时,需要结合自身需求及 MQ 产品特征,综合考虑。
Kafka: Kafka是LinkedIn开源的分布式发布-订阅消息系统,目前归属于Apache顶级项目。Kafka主要特点是基于Pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输。0.8版本开始支持复制,不支持事务,对消息的重复、丢失、错误没有严格要求,适合产生大量数据的互联网服务的数据收集业务。相同环境下,Kafka的吞吐量高达17.3w/s。
RabbitMQ: RabbitMQ是使用Erlang语言开发的开源消息队列系统,erlang 语言阻止了我们去深 入研究和掌控,对公司而言,底层技术无法控制,但是是开源的,社区活跃度也很高;它是基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次,目前中小企业用得比较广泛。相同环境下,RabbitMQ的吞吐量5.95w/s,CPU资源消耗较高。它支持AMQP协议,实现非常重量级,为了保证消息的可靠性在吞吐量上做了取舍。Rabbitmq比kafka可靠,kafka更适合IO高吞吐的处理,比如ELK日志收集;
RocketMQ: RocketMQ是阿里开源的消息中间件,它是纯Java开发,具有高吞吐量、高可用性、适合大规模分布式系统应用的特点。RocketMQ思路起源于Kafka,但并不是Kafka的一个Copy,它对消息的可靠传输及事务性做了优化,目前在阿里集团被广泛应用于交易、充值、流计算、促销秒杀活动、消息推送、日志流式处理、binglog分发等场景,相同环境下,吞吐量在11.6w/s。
Redis: 是一个Key-Value的NoSQL数据库,开发维护很活跃,虽然它是一个Key-Value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。测试数据分为128Bytes、512Bytes、1K和10K四个不同大小的数据。入队时,当数据比较小时Redis的性能要高于RabbitMQ,而如果数据大小超过了10K,Redis则慢的无法忍受;出队时,无论数据大小,Redis都表现出非常好的性能,而RabbitMQ的出队性能则远低于Redis。redis 消息推送是基于分布式 pub/sub,多用于实时性较高的消息推送,并不保证可靠。redis主要做内存数据库。
ZeroMQ: 号称最快的消息队列系统,尤其针对大吞吐量的需求场景。ZMQ能够实现RabbitMQ不擅长的高级/复杂的队列,但是开发人员需要自己组合多种技术框架,技术上的复杂度是对这MQ能够应用成功的挑战。ZeroMQ具有一个独特的非中间件的模式,你不需要安装和运行一个消息服务器或中间件,因为你的应用程序将扮演了这个服务角色。你只需要简单的引用ZeroMQ程序库,可以使用NuGet安装,然后你就可以愉快的在应用程序之间发送消息了。但是ZeroMQ仅提供非持久性的队列,也就是说如果down机,数据将会丢失。其中,Twitter的Storm中使用ZeroMQ作为数据流的传输。
ActiveMQ: Apache ActiveMQ 是最受欢迎且功能最强大的开源消息传递和Integration Patterns服务器。Apache ActiveMQ速度快,支持许多跨语言客户端和协议,带有易于使用的企业集成模式和许多高级功能,同时完全支持JMS 1.1和J2EE 1.4。但是目前ActiveMQ 使用较少,ActiveMQ默认的配置性能偏低,需要优化配置,但是配置文件复杂,ActiveMQ本身不提供管理工具。