iwehdio的博客园:https://www.cnblogs.com/iwehdio/
学习自:
1、概述
-
什么是消息队列?
- 消息队列,一般简称为MQ(Message Queue)。消息队列可以简单理解为:把要传输的数据放在队列中。
- 把数据放到消息队列叫做生产者。
- 从消息队列里边取数据叫做消费者。
- 消息队列,一般简称为MQ(Message Queue)。消息队列可以简单理解为:把要传输的数据放在队列中。
-
消息队列有什么使用场景?
- 解耦。消费者不需要直接调用生产者的接口,而是通过消息队列获取。
- 异步。不同的应用可以异步的从消息队列中获取数据,而不必要顺序执行。
- 削峰。如果请求的峰值太大,按服务器的处理能力消费数据,其他的存放在消息队列中。
-
消费者怎么从消息队列里边得到数据?
- 生产者将数据放到消息队列中,消息队列有数据了,主动叫消费者去拿(俗称push)
- 消费者不断去轮训消息队列,看看有没有新的数据,如果有就消费(俗称pull)
-
引入消息队列会产生什么问题?
- 增加系统的复杂性。需要考虑各种问题,比如重复消费、消息丢失、消息的顺序消费等。
- 数据一致性问题。由于是异步的,难以判断各个部分是否都成功完成了,需要引入分布式事务。
- 高可用,不能是单机的。
- 数据丢失问题,需要进行数据的持久化。
-
重复消费:
- 一般消息队列的使用,都是有重试机制的,就是我下游的业务发生异常了,我会抛出异常并且要求你重新发一次。
- 但是如果不止一个服务在监听这个消息,如果只有其中一个服务接收失败需要重发,但是其他服务正常接收了,就会导致重试后其他服务接收到了两次消息。
- 处理重复消费问题一般使用的方法是:接口幂等。
- 幂等操作:特点是其任意多次执行所产生的影响均与一次执行的影响相同。就是你同样的参数调用我这个接口,调用多少次结果都是一个。
-
如何保证接口幂等:
- 一般幂等,会分场景去考虑,看是强校验还是弱校验,比如跟金钱相关的场景那就很关键,就做强校验,别的不是很重要的场景做弱校验。
- 强校验:
- 把接收到消息后的操作放在一个事务中,要么同时成功要么同时失败。
- 校验是把比如
订单号+业务场景
这样的唯一标识去流水表查,如果存在就可以直接返回,没有再执行事务中的逻辑。
- 弱校验:
- 把唯一标识作为键存在Redis中,并设置一定的失效时间。
- 接收到消息后就去Redis中看存不存在这个键,是有可能存在丢失的情况的。
-
顺序消费:
- 指的是一组按顺序放入消息队列的数据,在实际过程中可能入队时不是按顺序的。而消费时是多线程的,也难以保证顺序。比如增、改、删和删、增、改的结果就完全不同。
- 生产者消费者一般需要保证顺序消息的话,可能就是一个业务场景下的,比如订单的创建、支付、发货、收货。
- 一个topic下有多个队列,为了保证发送有序,RocketMQ提供了MessageQueueSelector队列选择机制,可使用Hash取模法,让同一个订单发送到同一个队列中,再使用同步发送,只有同个订单的创建消息发送成功,再发送支付消息。
- 这样,首先保证了发送有序,其次每次只发送一个消息,该消息成功后再发送下一个消息,保证了消费有序。
2、Kafka
-
Apache Kafka是一个分布式消息发布订阅系统。它最初由LinkedIn公司基于独特的设计实现为一个分布式的提交日志系统,之后成为Apache项目的一部分。Kafka系统快速、可扩展并且可持久化。它的分区特性,可复制和可容错都是其不错的特性。
- Kafka是运行在一个集群上,所以它可以拥有一个或多个服务节点;
- Kafka集群将消息存储在特定的文件中,对外表现为Topics;
- 每条消息记录都包含一个key,消息内容以及时间戳。
-
Kafka为了拥有更强大的功能,提供了四大核心接口:
- Producer API允许了应用可以向Kafka中的topics发布消息;
- Consumer API允许了应用可以订阅Kafka中的topics,并消费消息;
- Streams API允许应用可以作为消息流的处理者,比如可以从topicA中消费消息,处理的结果发布到topicB中;
- Connector API提供Kafka与现有的应用或系统适配功能,比如与数据库连接器可以捕获表结构的变化。
-
Topics:
-
Topics是一些主题的集合,更通俗的说Topic就像一个消息队列,生产者可以向其写入消息,消费者可以从中读取消息,一个Topic支持多个生产者或消费者同时订阅它,所以其扩展性很好。Topic又可以由一个或多个partition(分区)组成。
-
其中每个partition中的消息是有序的,但相互之间的顺序就不能保证了,若Topic有多个partition,生产者的消息可以指定或者由系统根据算法分配到指定分区,若你需要所有消息都是有序的,那么你最好只用一个分区。
-
另外partition支持消息位移读取,消息位移有消费者自身管理不同消费者对同一分区的消息读取互不干扰,消费者可以通过设置消息位移(offset)来控制自己想要获取的数据,比如可以从头读取,最新数据读取,重读读取等功能。
-
-
Producers:
- Producers作为消息的生产者,可以自己指定将消息发布到订阅Topic中的指定分区,策略可以自己指定,比如语义或者结构类似的消息发布在同一分区,当然也可以由系统循环发布在每一个分区上。
- 消息的添加是有序的,生产者越早向订阅的Topic发送的消息,会更早的被添加到Topic中,当然它们可能被分配到不同的分区。
-
Consumers:
- Consumers是一群消费者的集合,可以称之为消费者组,是一种更高层次的的抽象,向Topic订阅消费消息的单位是Consumers,当然它其中也可以只有一个消费者(consumer)。
- 同一个消费者组中的消费者,将会协同消费订阅的Topic中的信息。(比如组中有两个消费者,Topic中有四个分区,则每个消费者消费两个分区中的消息)
- 不同组之间的消费者,将会共同消费订阅的Topic中的新形象。(比如有两个组,它们都会消费订阅的Topic中的所有消息)
- 消费者在消费Topic分区中的消息时是有序的。
-
消息在Kafka中的处理历程:
- 消息生产者将消息发布到具体的Topic,根据一定算法或者随机被分发到具体的分区中;
- 根据实际需求,是否需要实现处理消息逻辑;
- 若需要,则实现具体逻辑后将结果发布到输出Topic;
- 消费者根据需求订阅相关Topic,并消费消息。
-
高可用:
- 一台Kafka服务器叫做Broker,Kafka集群就是多台Kafka服务器。
- 一个topic会分为多个partition,实际上partition会分布在不同的broker中。数据存在不同的partition上,那kafka就把这些partition做备份。
- 红色块的partition代表的是主分区,紫色的partition块代表的是备份分区。生产者往topic丢数据,是与主分区交互,消费者消费topic的数据,也是与主分区交互。
- 备份分区仅仅用作于备份,不做读写。如果某个Broker挂了,那就会选举出其他Broker的partition来作为主分区,这就实现了高可用。
-
持久化:
- Kafka是将partition的数据写在磁盘的(消息日志),不过Kafka只允许追加写入(顺序访问),避免缓慢的随机 I/O 操作。
- Kafka也不是partition一有数据就立马将数据写到磁盘上,它会先缓存一部分,等到足够多数据量或等待一定的时间再批量写入(flush)。
iwehdio的博客园:https://www.cnblogs.com/iwehdio/