掌握高并发、高可用架构第三章 分布式

本章介绍分布式架构的底层技术。主要说明面试过程中可能被问到的技术点。

第三节 消息队列(MQ,Message Queue)

消息队列 MQ JMS AMQP ActiveMQ RabbitMQ RocketMQ kafka

1. 什么是消息队列

可以把消息队列简单理解为存放消息的容器,并且当我们需要消息的时候可以取出消息供自己使用。消息队列是分布式系统中重要的中间件,它可以通过异步操作来实现提高系统性能、流量削峰、降低系统耦合。

目前比较流行的消息队列有:ActiveMQ、RabbitMQ、RocketMQ、Kafka

2. 为何要用消息队列,它的优势

消息队列的优势主要体现在:

通过异步处理来提高系统性能

使用了消息队列后,用户的请求发送到消息队列后就返回了,由消息队列的消费者把消息异步的写到数据库。由于消息队列服务器的处理速度大于数据库,所以系统性能大幅提高

降低系统的耦合性

使用了消息队列后,应用之间不再是强耦合关系,各个应用从消息队列获取需要的消息,从而降低耦合

限流削峰

购物网站的秒杀活动,在秒杀开始的一瞬间流量巨大,可能会导致系统无法处理而崩溃。加入消息队列后,用户请求都会放入消息队列,系统处理则从消息队列获取数据,不至于导致系统崩溃

请求先入消息队列,而不是直接交给业务处理,做了一次缓冲,极大的降低了系统的压力队列长度可以进行限制,后面的请求无法入队,就可以直接抛弃了3. 使用消息队列带来的问题系统可用性降低:加入MQ后,需要考虑服务器宕机的问题系统复杂性提高:消息丢失、重复消费、消息传递的顺序性一致性问题:消息被正确的消费4. JMS VS AMQP

JMS,Java Message Service即Java消息服务,它是消息服务的规范。JMS API允许应用程序组件基于JMEE平台创建 、发送、接收、读取消息。它使分布式通信耦合性降低、消息服务更加可靠

ActiveMQ就是基于JMS规范实现的

JMS支持两种消息模型:

点对点(P2P)模型

使用队列(Queue)来满足生产者消费者模式,一条消息只能被一个消费者消费

发布/订阅(Pub/Sub)模型

发布-订阅模型使用主题(Topic)作为消息通信载体,发布者发布一条消息,该消息通过主题传递给所有的订阅者

JMS支持的五种消息格式

StreamMessage,Java原始值的数据流MapMessage,键值对TextMessage,字符串ObjectMessage,序列化的对象BytesMessage,字节数据流

AMQP,Advanced Message Queuing Protocol,高级消息队列协议(二进制应用层协议)。它是一个协议,兼容JMS。基于它实现的消息队列,不收客户端、中间件的开发语言限制

RabbitMQ就是基于AMQP实现的

比较内容JMSAMQP定义JMS API,是一种规范是一个协议跨语言否,仅支持JAVA是夸平台否是消息模型点对点模型、发布-订阅模型提供了五种消息模型:<br />1.direct exchange<br />2.fanout exchange<br />3.topic change<br />4.header exchange<br />5.system exchange<br />后四种和发布订阅仅是在路由机制上做了更详细的划分消息类型上述的五种消息格式byte[] 二进制5. 消息队列选型

比较目前流行的四种消息队列

特性ActiveMQRabbitMQRocketMQKafka开发语言javaerlangjavascala单机吞吐量万级(最差)万级(其次)十万级(最高)十万级(次之)时效性ms级us级ms级ms以内可用性基于Zookeeper <br />+ LevelDB的<br />master-slave模式master/slave模式<br />master提供服务<br />slave仅做备份多master模式<br />多master多slave异步复制模式<br />多master多slave同步双写模式replica机制,<br />leader宕机备份自动顶替,<br />并重新选举leader(基于Zookeeper)功能特性成熟产品,社区不活跃,文档齐全并发能力强,性能好,管理界面丰富比较成熟,扩展性佳只提供主要的MQ功能,在大数据领域应用广消息推拉pull,push都支持pull,push都支持pull,push都支持pull6. 如何保证不被重复消费

什么情况会发生重复消费呢?正常情况下,消费者在消费消息完成后,会发送一个确认消息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除。因为网络传输等故障,导致确认消息没有传送到消息队列,继而消息队列不知道该消息已被消费,再次将消息分发消费了

这个问题在不同的场景下有不同的解决方案,主要是在消费方来解决重复问题

消息用作DB的insert操作,此时可以把消息作为一个主键,当出现重复消费时,就会主键冲突,自然就避免了消息用作Redis的set操作,此时,因为set操作会覆盖上一个值 ,但是两次的值一样,也是无所谓的最坏的情况下,可以准备第三方介质来存储消费的消息。比如Redis,每次操作时都去Redis中查看是否之前操作过7. 如何保证数据不丢失

消息丢失主要分为:生产者丢失、消息队列丢失、消费者丢失

每种MQ都有不同的处理,这里就不详细论述了

Topic模式参考资料

一个用消息队列 的人,不知道为啥用 MQ,这就有点尴尬

新手也能看懂,消息队列其实很简单