共计 7306 个字符,预计需要花费 19 分钟才能阅读完成。
本文曾经收录到 Github 仓库,该仓库蕴含 计算机根底、Java 根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享 等外围知识点,欢送 star~
Github 地址:https://github.com/Tyson0314/Java-learning
为什么要应用音讯队列?
总结一下,次要三点起因:解耦、异步、削峰。
1、解耦。比方,用户下单后,订单零碎须要告诉库存零碎,如果库存零碎无法访问,则订单减库存将失败,从而导致订单操作失败。订单零碎与库存零碎耦合,这个时候如果应用音讯队列,能够返回给用户胜利,先把音讯长久化,等库存零碎复原后,就能够失常生产减去库存了。
2、异步。将音讯写入音讯队列,非必要的业务逻辑以异步的形式运行,不影响主流程业务。
3、削峰。生产端缓缓的依照数据库能解决的并发量,从音讯队列中缓缓拉取音讯。在生产中,这个短暂的高峰期积压是容许的。比方秒杀流动,个别会因为流量过大,从而导致流量暴增,利用挂掉。这个时候加上音讯队列,服务器接管到用户的申请后,首先写入音讯队列,如果音讯队列长度超过最大数量,则间接摈弃用户申请或跳转到谬误页面。
应用了音讯队列会有什么毛病
- 零碎可用性升高。引入音讯队列之后,如果音讯队列挂了,可能会影响到业务零碎的可用性。
- 零碎复杂性减少。退出了音讯队列,要多思考很多方面的问题,比方:一致性问题、如何保障音讯不被反复生产、如何保障音讯可靠性传输等。
常见的音讯队列比照
比照方向 | 概要 |
---|---|
吞吐量 | 万级的 ActiveMQ 和 RabbitMQ 的吞吐量(ActiveMQ 的性能最差)要比 十万级甚至是百万级的 RocketMQ 和 Kafka 低一个数量级。 |
可用性 | 都能够实现高可用。ActiveMQ 和 RabbitMQ 都是基于主从架构实现高可用性。RocketMQ 基于分布式架构。kafka 也是分布式的,一个数据多个正本,多数机器宕机,不会失落数据,不会导致不可用 |
时效性 | RabbitMQ 基于 erlang 开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。其余三个都是 ms 级。 |
性能反对 | 除了 Kafka,其余三个性能都较为齐备。Kafka 性能较为简单,次要反对简略的 MQ 性能,在大数据畛域的实时计算以及日志采集被大规模应用,是事实上的规范 |
音讯失落 | ActiveMQ 和 RabbitMQ 失落的可能性非常低,RocketMQ 和 Kafka 实践上不会失落。 |
总结:
- ActiveMQ 的社区算是比拟成熟,然而较目前来说,ActiveMQ 的性能比拟差,而且版本迭代很慢,不举荐应用。
- RabbitMQ 在吞吐量方面尽管稍逊于 Kafka 和 RocketMQ,然而因为它基于 erlang 开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。然而也因为 RabbitMQ 基于 erlang 开发,所以国内很少有公司有实力做 erlang 源码级别的钻研和定制。如果业务场景对并发量要求不是太高(十万级、百万级),那这四种音讯队列中,RabbitMQ 肯定是你的首选。如果是大数据畛域的实时计算、日志采集等场景,用 Kafka 是业内规范的,相对没问题,社区活跃度很高,相对不会黄,何况简直是全世界这个畛域的事实性标准。
- RocketMQ 阿里出品,Java 系开源我的项目,源代码咱们能够间接浏览,而后能够定制本人公司的 MQ,并且 RocketMQ 有阿里巴巴的理论业务场景的实战考验。RocketMQ 社区活跃度绝对较为个别,不过也还能够,文档相对来说简略一些,而后接口这块不是依照规范 JMS 标准走的有些零碎要迁徙须要批改大量代码。还有就是阿里出台的技术,你得做好这个技术万一被摈弃,社区黄掉的危险,那如果你们公司有技术实力我感觉用 RocketMQ 挺好的
- Kafka 的特点其实很显著,就是仅仅提供较少的外围性能,然而提供超高的吞吐量,ms 级的提早,极高的可用性以及可靠性,而且分布式能够任意扩大。同时 kafka 最好是撑持较少的 topic 数量即可,保障其超高吞吐量。kafka 惟一的一点劣势是有可能音讯反复生产,那么对数据准确性会造成极其轻微的影响,在大数据畛域中以及日志采集中,这点轻微影响能够疏忽这个个性人造适宜大数据实时计算以及日志收集。
如何保障音讯队列的高可用?
RabbitMQ:镜像集群模式
RabbitMQ 是基于主从做高可用性的,Rabbitmq 有三种模式:单机模式、一般集群模式、镜像集群模式。单机模式个别在生产环境中很少用,一般集群模式只是进步了零碎的吞吐量,让集群中多个节点来服务某个 Queue 的读写操作。那么真正实现 RabbitMQ 高可用的是镜像集群模式。
镜像集群模式跟一般集群模式不一样的是,创立的 Queue,无论元数据还是 Queue 里的音讯都会存在于多个实例上,而后每次你写音讯到 Queue 的时候,都会主动和多个实例的 Queue 进行音讯同步。这样设计,益处在于:任何一个机器宕机不影响其余机器的应用。害处在于:1. 性能开销太大:音讯同步所有机器,导致网络带宽压力和耗费很重;2. 扩展性差:如果某个 Queue 负载很重,即使加机器,新增的机器也蕴含了这个 Queue 的所有数据,并没有方法线性扩大你的 Queue。
Kafka:partition 和 replica 机制
Kafka 根本架构是多个 broker 组成,每个 broker 是一个节点。创立一个 topic 能够划分为多个 partition,每个 partition 能够存在于不同的 broker 上,每个 partition 就放一部分数据,这就是人造的分布式音讯队列。就是说一个 topic 的数据,是扩散放在多个机器上的,每个机器就放一部分数据。
Kafka 0.8 以前,是没有 HA 机制的,任何一个 broker 宕机了,它的 partition 就没法写也没法读了,没有什么高可用性可言。
Kafka 0.8 当前,提供了 HA 机制,就是 replica 正本机制。每个 partition 的数据都会同步到其余机器上,造成本人的多个 replica 正本。而后所有 replica 会选举一个 leader 进去,生产和生产都跟这个 leader 打交道,而后其余 replica 就是 follower。写的时候,leader 会负责把数据同步到所有 follower 下来,读的时候就间接读 leader 上数据即可。Kafka 会平均的将一个 partition 的所有 replica 散布在不同的机器上,这样才能够进步容错性。
MQ 罕用协定
AMQP 协定 AMQP 即 Advanced Message Queuing Protocol, 一个提供对立音讯服务的应用层规范高级音讯队列协定, 是应用层协定的一个凋谢规范, 为面向音讯的中间件设计。基于此协定的客户端与消息中间件可传递音讯,并不受客户端 / 中间件不同产品,不同开发语言等条件的限度。
长处:牢靠、通用
MQTT 协定 MQTT(Message Queuing Telemetry Transport,音讯队列遥测传输)是 IBM 开发的一个即时通讯协定,有可能成为物联网的重要组成部分。该协定反对所有平台,简直能够把所有联网物品和内部连接起来,被用来当做传感器和致动器(比方通过 Twitter 让屋宇联网)的通信协议。
长处:格局简洁、占用带宽小、挪动端通信、PUSH、嵌入式零碎
STOMP 协定 STOMP(Streaming Text Orientated Message Protocol)是流文本定向音讯协定,是一种为 MOM(Message Oriented Middleware,面向音讯的中间件) 设计的简略文本协定。STOMP 提供一个可互操作的连贯格局,容许客户端与任意 STOMP 音讯代理(Broker)进行交互。
长处:命令模式(非 topic/queue 模式)
XMPP 协定 XMPP(可扩大音讯解决现场协定,Extensible Messaging and Presence Protocol)是基于可扩大标记语言(XML)的协定,多用于即时消息(IM)以及在线现场探测。实用于服务器之间的准即时操作。外围是基于 XML 流传输,这个协定可能最终容许因特网用户向因特网上的其余任何人发送即时消息,即便其操作系统和浏览器不同。
长处:通用公开、兼容性强、可扩大、安全性高,但 XML 编码格局占用带宽大
- 其余基于 TCP/IP 自定义的协定:有些非凡框架(如:redis、kafka、zeroMq 等)依据本身须要未严格遵循 MQ 标准,而是基于 TCP\IP 自行封装了一套协定,通过网络 socket 接口进行传输,实现了 MQ 的性能。
MQ 的通信模式
- 点对点通信:点对点形式是最为传统和常见的通信形式,它反对一对一、一对多、多对多、多对一等多种配置形式,反对树状、网状等多种拓扑构造。
- 多点播送:MQ 实用于不同类型的利用。其中重要的,也是正在倒退中的是 ” 多点播送 ” 利用,即可能将音讯发送到多个指标站点(Destination List)。能够应用一条 MQ 指令将繁多音讯发送到多个指标站点,并确保为每一站点牢靠地提供信息。MQ 不仅提供了多点播送的性能,而且还领有智能音讯散发性能,在将一条音讯发送到同一零碎上的多个用户时,MQ 将音讯的一个复制版本和该零碎上接收者的名单发送到指标 MQ 零碎。指标 MQ 零碎在本地复制这些音讯,并将它们发送到名单上的队列,从而尽可能减少网络的传输量。
- 公布 / 订阅 (Publish/Subscribe) 模式:公布 / 订阅性能使音讯的散发能够冲破目标队列天文指向的限度,使音讯依照特定的主题甚至内容进行散发,用户或应用程序能够依据主题或内容接管到所须要的音讯。公布 / 订阅性能使得发送者和接收者之间的耦合关系变得更为涣散,发送者不用关怀接收者的目标地址,而接收者也不用关怀音讯的发送地址,而只是依据音讯的主题进行音讯的收发。在 MQ 家族产品中,MQ Event Broker 是专门用于应用公布 / 订阅技术进行数据通讯的产品,它反对基于队列和间接基于 TCP/IP 两种形式的公布和订阅。
- 集群(Cluster):为了简化点对点通信模式中的系统配置,MQ 提供 Cluster 的解决方案。集群相似于一个 域(Domain),集群外部的队列管理器之间通信时,不须要两两之间建设音讯通道,而是采纳 Cluster 通道与其它成员通信,从而大大简化了系统配置。此外,集群中的队列管理器之间可能主动进行负载平衡,当某一队列管理器呈现故障时,其它队列管理器能够接管它的工作,从而大大提高零碎的高可靠性
如何保障音讯的程序性?
RabbitMQ
拆分多个 Queue,每个 Queue 一个 Consumer;或者就一个 Queue 然而对应一个 Consumer,而后这个 Consumer 外部用内存队列做排队,而后分发给底层不同的 Worker 来解决。
Kafka
- 一个 Topic,一个 Partition,一个 Consumer,外部单线程生产,单线程吞吐量太低,个别不会用这个。
- 写 N 个内存 Queue,具备雷同 key 的数据都到同一个内存 Queue;而后对于 N 个线程,每个线程别离生产一个内存 Queue 即可,这样就能保障程序性。
如何防止音讯反复生产?
在音讯生产时,MQ 外部针对每条生产者发送的音讯生成一个惟一 id,作为去重和幂等的根据(音讯投递失败并重传),防止反复的音讯进入队列。
在音讯生产时,要求音讯体中也要有一全局惟一 id 作为去重和幂等的根据,防止同一条音讯被反复生产。
大量音讯在 MQ 里长时间积压,该如何解决?
个别这个时候,只能长期紧急扩容了,具体操作步骤和思路如下:
- 先修复 consumer 的问题,确保其复原生产速度,而后将现有 consumer 都停掉;
- 新建一个 topic,partition 是原来的 10 倍,长期建设好原先 10 倍的 queue 数量;
- 而后写一个长期的散发数据的 consumer 程序,这个程序部署下来生产积压的数据,生产之后不做耗时的解决,间接平均轮询写入长期建设好的 10 倍数量的 queue;
- 接着长期用 10 倍的机器来部署 consumer,每一批 consumer 生产一个长期 queue 的数据。这种做法相当于是长期将 queue 资源和 consumer 资源扩充 10 倍,以失常的 10 倍速度来生产数据;
- 等疾速生产完积压数据之后,得复原原先部署的架构,从新用原先的 consumer 机器来生产音讯。
MQ 中的音讯过期生效了怎么办?
如果应用的是 RabbitMQ 的话,RabbtiMQ 是能够设置过期工夫的(TTL)。如果音讯在 Queue 中积压超过肯定的工夫就会被 RabbitMQ 给清理掉,这个数据就没了。这时的问题就不是数据会大量积压在 MQ 里,而是大量的数据会间接搞丢。这个状况下,就不是说要减少 Consumer 生产积压的音讯,因为实际上没啥积压,而是丢了大量的音讯。
咱们能够采取一个计划,就是批量重导。就是大量积压的时候,间接将数据写到数据库,而后等过了高峰期当前将这批数据一点一点的查出来,而后从新灌入 MQ 外面去,把丢的数据给补回来。
消息中间件如何做到高可用?
以 Kafka 为例。
Kafka 的根底集群架构,由多个 broker
组成,每个 broker
都是一个节点。当你创立一个 topic
时,它能够划分为多个 partition
,而每个partition
放一部分数据,别离存在于不同的 broker 上。也就是说,一个 topic 的数据,是扩散放在多个机器上的,每个机器就放一部分数据。
每个 partition
放一部分数据,如果对应的 broker 挂了,那这部分数据是不是就失落了?那不是保障不了高可用吗?
Kafka 0.8 之后,提供了复制多正本机制来保障高可用,即每个 partition 的数据都会同步到其它机器上,造成多个正本。而后所有的正本会选举一个 leader 进去,让 leader 去跟生产和消费者打交道,其余正本都是 follower。写数据时,leader 负责把数据同步给所有的 follower,读音讯时,间接读 leader 上的数据即可。如何保障高可用的?就是假如某个 broker 宕机,这个 broker 上的 partition 在其余机器上都有正本的。如果挂的是 leader 的 broker 呢?其余 follower 会从新选一个 leader 进去。
如何保证数据一致性,事务音讯如何实现?
一条一般的 MQ 音讯,从产生到被生产,大略流程如下:
- 生产者产生音讯,发送带 MQ 服务器
- MQ 收到音讯后,将音讯长久化到存储系统。
- MQ 服务器返回 ACk 到生产者。
- MQ 服务器把音讯 push 给消费者
- 消费者生产完音讯,响应 ACK
- MQ 服务器收到 ACK,认为音讯生产胜利,即在存储中删除音讯。
举个下订单的例子吧。订单零碎创立完订单后,再发送音讯给上游零碎。如果订单创立胜利,而后音讯没有胜利发送进来,上游零碎就无奈感知这个事件,出导致数据不统一。
如何保证数据一致性呢?能够应用 事务音讯。一起来看下事务音讯是如何实现的吧。
- 生产者产生音讯,发送一条半事务音讯到 MQ 服务器
- MQ 收到音讯后,将音讯长久化到存储系统,这条音讯的状态是待发送状态。
- MQ 服务器返回 ACK 确认到生产者,此时 MQ 不会触发音讯推送事件
- 生产者执行本地事务
- 如果本地事务执行胜利,即 commit 执行后果到 MQ 服务器;如果执行失败,发送 rollback。
- 如果是失常的 commit,MQ 服务器更新音讯状态为可发送;如果是 rollback,即删除音讯。
- 如果音讯状态更新为可发送,则 MQ 服务器会 push 音讯给消费者。消费者生产完就回 ACK。
- 如果 MQ 服务器长时间没有收到生产者的 commit 或者 rollback,它会反查生产者,而后依据查问到的后果执行最终状态。
如何设计一个音讯队列?
首先是音讯队列的整体流程,producer 发送音讯给 broker,broker 存储好,broker 再发送给 consumer 生产,consumer 回复生产确认等。
producer 发送音讯给 broker,broker 发消息给 consumer 生产,那就须要两次 RPC 了,RPC 如何设计呢?能够参考开源框架 Dubbo,你能够说说服务发现、序列化协定等等
broker 思考如何长久化呢,是放文件系统还是数据库呢,会不会音讯沉积呢,音讯沉积如何解决呢。
生产关系如何保留呢?点对点还是播送形式呢?播送关系又是如何保护呢?zk 还是 config server
音讯可靠性如何保障呢?如果音讯反复了,如何幂等解决呢?
音讯队列的高可用如何设计呢?能够参考 Kafka 的高可用保障机制。多正本 -> leader & follower -> broker 挂了从新选举 leader 即可对外服务。
音讯事务个性,与本地业务同个事务,本地音讯落库; 音讯投递到服务端,本地才删除;定时工作扫描本地音讯库,弥补发送。
MQ 得伸缩性和可扩展性,如果音讯积压或者资源不够时,如何反对疾速扩容,进步吞吐?能够参照一下 Kafka 的设计理念,broker -> topic -> partition,每个 partition 放一个机器,就存一部分数据。如果当初资源不够了,简略啊,给 topic 减少 partition,而后做数据迁徙,减少机器,不就能够寄存更多数据,提供更高的吞吐量了吗。
参考链接
多线程异步和 MQ 的区别
- CPU 耗费。多线程异步可能存在 CPU 竞争,而 MQ 不会耗费本机的 CPU。
- MQ 形式实现异步是齐全 解耦 的,适宜于大型互联网我的项目。
- 削峰或者音讯沉积能力。当业务零碎处于高并发,MQ 能够将音讯沉积在 Broker 实例中,而多线程会创立大量线程,甚至触发回绝策略。
- 应用 MQ 引入了中间件,减少了我的项目复杂度和运维难度。
总的来说,规模比拟小的我的项目能够应用多线程实现异步,大我的项目倡议应用 MQ 实现异步。
最初给大家分享一个 Github 仓库,下面有大彬整顿的 300 多本经典的计算机书籍 PDF,包含 C 语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生 等,能够 star 一下,下次找书间接在下面搜寻,仓库继续更新中~
Github 地址:https://github.com/Tyson0314/java-books