大家好,我是狼王,一个爱玩的程序员。随着互联网的发展,技术也在快速迭代。由于大流量、高并发的出现,很多问题也随之而来。为了解决这些问题,一些高端人才研究了各种各样的东西来解决这些问题,消息队列就是其中之一。所以今天,我们来谈谈消息队列!什么是消息队列?不知道大家看到这个词是不是觉得是比较高端的技术。无论如何,我认为它似乎非常棒。被迫。消息队列,一般我们会简称为MQ(MessageQueue),嗯,是一个很直白的简称。让我们忽略Message这个词,让我们看看Queue。从这点来看,队列大家应该不陌生了。队列是一种先进先出的数据结构。在Java中,已经实现了很多队列。那为什么我们需要消息队列(MQ)这样的中间件???其实这个问题和我之前学Redis的时候很像。Redis是一个以key-value形式存储的内存数据库。很明显,我们可以使用HashMap这样的实现类来实现类似的效果,那为什么要使用Redis呢?在这里,大家可以先猜猜我们为什么要使用消息队列(MQ)这种中间件消息队列可以简单理解为:把要传输的数据放在队列中。科普一下:将数据放入消息队列中,称为生产者。从消息队列中获取数据称为消费者。市场上有很多消息队列产品,比如老牌的ActiveMQ和RabbitMQ。目前流行Kafka,阿里巴巴捐给Apache。RocketMQ,甚至像redis这样的NoSQL数据库也支持MQ功能。简而言之,这一块有十几个知名产品。为什么使用消息队列就是要问:使用消息队列有什么好处。解耦以常见的订单系统为例。用户点击【下单】按钮后的业务逻辑可能包括:扣除库存、生成对应单据、发货、发送短信通知等。在业务开发初期,这些逻辑可能会放在一起同步执行。随着业务的发展和订单量的增加,需要提高系统服务的性能。这时候可以把一些不需要立即生效的操作拆分出来异步执行,比如发货,发送短信通知等等。在这种场景下,可以使用MQ,在下单主流程(比如扣库存,生成对应单据)完成后向MQ发送消息,这样主流程可以快速完成,另外一个单独的线程拉取MQ的消息(或者MessagesarepushedbyMQ),当发现MQ中有快递或短信等消息时,执行相应的业务逻辑。简单来说,服务a需要调用服务b的接口或方法来传递数据。这时如果使用消息队列,服务a只需要向消息队列发送数据,服务b从消息队列中取出相应的数据即可,实现解耦和异步即可。异步其实就是服务a发送数据到消息队列后可以返回或者执行其他流程,不需要等待服务b处理数据,从而提高一些异步业务场景的效率。调峰/限流让我们来看另一种情况。例如,现在我们每个月都有大促销。大促的时候可能并发很高,比如每秒5000个请求。假设我们现在有两台机器处理请求,每台机器一次只能处理2000个请求。多出来的1000个请求可能会把我们整个系统搞垮,所以,有一个办法,我们可以写入消息队列:服务器A和服务器B根据自己能处理的请求数去消息队列取数据,这样即使如果每秒有10000个请求,它只是将请求放到消息队列中,系统控制消息获取消息队列,这样整个系统就不会崩溃。使用消息队列有什么问题?经过我们上面的场景,我们已经可以发现消息队列可以做的事情还是蛮多的。说了这么多,让我们回到文章开头,“明明JDK已经实现了很多队列,我们??还需要消息队列中间件吗?”其实很简单。虽然JDK实现的队列种类很多,但都是简单的内存队列。为什么我说JDK是一个简单的内存队列呢?我们来看看实现一个消息队列(中间件)可能会考虑哪些问题。高可用无论我们使用消息队列是为了解耦、异步还是调峰,消息队列都不能是单机的。试想一下,如果是单机的消息队列,如果这台机器挂了,那我们整个系统就几乎不可用了,就会出现单点故障。所以我们在项目中使用消息队列的时候,都是集群/分布式的。如果要做集群/分布式,肯定希望消息队列能够提供现成的支持,而不是自己写代码去手动实现。数据丢失问题我们向消息队列写入数据,服务器A和服务器B还没来得及消费消息队列中的数据就挂掉了。如果什么都不做,我们的数据将会丢失。研究过Redis的都知道,Redis可以将数据持久化到磁盘上,如果Redis挂了,还可以从磁盘中恢复数据。同样,消息队列中的数据也需要存储在别处,这样才能最大限度地减少数据丢失。它存在于何处?磁盘?数据库?同步存储还是异步存储?不同的MQ对于消息丢失有不同的处理和解决方案,但是必须从生产者和消费者两端来分析。如果生产者丢了消息,生产者必须保证消息发送到MQ,会有回调确认机制和事务方法。消息队列丢失消息。在消息队列中,如果因为MQ挂了导致消息丢失,那么可以持久化消息。或者使用生产者端重发消息的方式。消费者端丢失消息。一般消费者丢失消息的原因是从MQ获取消息,但是有可能消费失败,需要重新消费,而MQ中并没有这个消息。这种情况下,可以由消费者端手动确认,或者生产者端重新发送消息。消费者如何获取消息队列的数据呢?消费者如何从消息队列中获取数据呢?一般有两种方式:production算子把数据放在消息队列中,消息队列有数据,主动要求消费者去获取(俗称push)。消费者继续训练消息队列,看看有没有新的数据。如果有新的数据,就会被消费(俗称pull)。其他除了这些问题,我们在使用的时候还要考虑各种问题:消息重复消费怎么办?我想确保消息绝对有序。好处很多,但同时我们发现引入消息队列也会增加系统的复杂度。市面上已经有很多消息队列的轮子,每个消息队列都有自己的特点。您必须仔细考虑选择哪个MQ。这次我们先来说说RabbitMQRabbitMQRabbitMQ是一个用Erlang语言开发的AMQP的开源实现。AMQP:AdvancedMessageQueue,高级消息队列协议。它是应用层协议的一个开放标准,专为面向消息的中间件而设计,基于该协议的客户端和消息中间件可以不受产品和开发语言等条件的限制传递消息。RabbitMQ最初起源于金融系统,用于分布式系统中的消息存储和转发。它在易用性、可扩展性和高可用性方面表现良好。具体特性包括:可靠性(Reliability)RabbitMQ使用一些机制来保证可靠性,如持久化、传输确认、发布确认等。灵活的路由在消息进入队列之前通过Exchange路由消息。对于典型的路由功能,RabbitMQ已经提供了一些内置的Exchange实现。对于更复杂的路由功能,可以将多个Exchange绑定在一起,也可以通过插件机制实现自己的Exchange。Clustering多个RabbitMQ服务器可以组成一个集群,形成一个逻辑Broker。高可用性队列(HighlyAvailableQueues)队列可以在集群中的机器上进行镜像,这样当某些节点出现故障时队列仍然可用。多协议RabbitMQ支持多种消息队列协议,如STOMP、MQTT等。多语言客户端(ManyClients)RabbitMQ支持几乎所有常见的语言,如Java、.NET、Ruby等消息代理。Tracing如果消息异常,RabbitMQ提供了消息跟踪机制,让用户可以及时发现发生了什么。插件机制(PluginSystem)RabbitMQ提供了很多插件可以进行多方面的扩展,你也可以自己编写插件。RabbitMQ中消息模型的概念模型所有MQ产品在模型抽象上都有相同的过程:一个消费者(consumer)订阅一个队列。生产者(producer)创建消息,然后发布到队列(queue),最后将消息发送给监听的消费者。RabbitMQ的基本概念上面只是最简单的抽象描述,但是说到RabbitMQ,还有更详细的概念需要说明。上文提到,RabbitMQ是AMQP协议的开源实现,所以它的内部其实就是AMQP中的基本概念:Message消息,消息是匿名的,由消息头和消息体组成。消息体是不透明的,而消息头由一系列可选属性组成,包括routing-key(路由键)、priority(相对于其他消息的优先级)、delivery-mode(表示该消息可能需要持久化存储)、等等。Publisher消息的生产者和将消息发布到交换的客户端应用程序。Exchange一种交换器,它从生产者那里接收消息并将它们路由到服务器中的队列。Binding绑定,用于消息队列与交换器的关联。绑定是一种路由规则,它根据路由键连接交换器和消息队列,因此交换器可以理解为由绑定组成的路由表。Queue消息队列,用于保存消息直到发送给消费者。它是消息的容器,也是消息的目的地。一条消息可以放在一个或多个队列中。消息一直在队列中,等待消费者连接队列取走。连接网络连接,例如TCP连接。Channel,多路复用连接中独立的双向数据流通道。通道是在真实的TCP连接中建立的虚拟连接。AMQP命令通过通道发送。无论是发布消息、订阅队列还是接收消息,这些动作都是通过通道完成的。由于操作系统建立和销毁TCP的开销非常大,因此引入通道的概念来复用一个TCP连接。Consumer消息的消费者表示从消息队列中获取消息的客户端应用程序。VirtualHost虚拟主机,代表一批交换器、消息队列和相关对象。虚拟主机是共享相同身份验证和加密环境的独立服务器域。每个虚拟主机本质上都是RabbitMQ服务器的迷你版,有自己的队列、开关、绑定和权限机制。vhost是AMQP概念的基础,必须在连接时指定。RabbitMQ的默认虚拟主机是/。Broker代表消息队列服务器实体。本文主要讲解什么是消息队列,消息队列能给我们带来什么好处,以及消息队列可能会涉及到哪些问题。稍后我将更深入地讨论它!希望对您有所帮助。好吧。今天就到这里吧,我会继续分享我的所学所想,希望我们一起走在成功的路上!
