当前位置: 首页 > news >正文

消息队列的秘密 第二章:拜师学艺

第二章:拜师学艺

兔师傅的院落

清晨,林消息再次来到数据江湖。昨晚他成功地在公司系统中集成了简单的消息队列,系统终于能够平稳运行,这让他对消息队列的力量有了更深的认识,也更加渴望学习更多知识。

按照约定,他来到了兔师傅的院落。院子里种满了胡萝卜,一只白色的大兔子正在院子中央打太极,动作轻盈灵活,宛如行云流水。

"你来了,年轻人。"兔师傅停下动作,转身看向林消息,声音温和而富有节奏感,“队列老祖已经告诉我你的情况。我听说你已经初步掌握了点对点模式的基础知识。”

林消息恭敬地行了一礼,“是的,兔师傅。队列老祖教了我消息队列的基本概念和点对点模式,我已经在实际系统中应用,效果很好。”

兔师傅满意地点点头,“很好。点对点模式虽然实用,但在复杂系统中往往不够灵活。今天,我要教你RabbitMQ的核心心法——‘交换机路由’。”

他带着林消息来到一个特殊的练功房,房间中央是一个复杂的模型,由多条光线连接的节点组成。

"这就是交换机模型,"兔师傅解释道,“在RabbitMQ中,生产者不是直接将消息发送到队列,而是先发送到交换机,由交换机根据不同的规则将消息路由到一个或多个队列。”

林消息仔细观察着模型,“这样做有什么好处呢?”

"灵活性,"兔师傅回答,“通过交换机,你可以实现各种复杂的消息分发模式,而不仅仅是简单的点对点。今天,我会教你四种基本的交换机类型:直接交换机、主题交换机、扇出交换机和头交换机。”

直接交换机:精准投递

兔师傅首先演示了直接交换机(Direct Exchange)的工作原理。

“直接交换机是最简单的一种,它根据消息的路由键(Routing Key)将消息发送到绑定了相同路由键的队列。”

他拿出几个标有不同颜色的信封,代表消息,每个信封上都写着一个路由键。然后,他设置了三个队列,分别绑定了"red"、"green"和"blue"三个路由键。

"看好了,"兔师傅将一个标有"red"的信封放入交换机,“这个消息的路由键是’red’,所以它会被发送到绑定了’red’路由键的队列。”

果然,信封精准地进入了第一个队列。

"直接交换机适用于明确知道消息应该发送到哪个队列的场景,比如根据消息类型或优先级进行路由。"兔师傅解释道,“它的特点是精准投递,一个消息只会被发送到匹配的队列,如果没有队列匹配,消息会被丢弃。”

林消息点点头,“这就像是邮递员根据地址将信件精确地投递到对应的信箱。”

"没错!"兔师傅赞许地说,“现在,让我们来练习一下。”

他给了林消息几个不同路由键的信封,让他尝试通过直接交换机发送消息。林消息很快掌握了直接交换机的使用方法,成功地将每个消息发送到了正确的队列。

"做得好,"兔师傅说,“但直接交换机有一个限制:它只能进行精确匹配,不支持模式匹配。如果你需要更灵活的路由方式,就需要用到主题交换机了。”

主题交换机:模式匹配

接下来,兔师傅演示了主题交换机(Topic Exchange)的工作原理。

“主题交换机也是根据路由键将消息路由到队列,但它支持通配符匹配,这使得它比直接交换机更加灵活。”

他设置了一个新的模型,其中包含一个主题交换机和三个队列。第一个队列绑定了路由键".orange.“,第二个队列绑定了”..rabbit",第三个队列绑定了"lazy.#"。

"在主题交换机中,路由键通常是由点分隔的单词列表,"兔师傅解释道,"有两种特殊字符用于匹配:

  • ‘*’(星号)可以替代一个单词
  • ‘#’(井号)可以替代零个或多个单词"

他拿出一个标有"quick.orange.rabbit"的信封,“这个消息的路由键是’quick.orange.rabbit’,它会被发送到哪些队列呢?”

林消息思考了一下,“它匹配’.orange.‘和’..rabbit’,所以会被发送到第一个和第二个队列。”

"正确!"兔师傅将信封放入交换机,信封果然被复制并发送到了两个队列。

"再试一个,"兔师傅拿出一个标有"lazy.orange.elephant"的信封,“这个呢?”

"它匹配’.orange.‘和’lazy.#’,所以会被发送到第一个和第三个队列。"林消息回答。

兔师傅再次点头,“你学得很快。主题交换机非常适合需要根据多个条件进行路由的场景,比如日志系统根据日志级别和来源进行分类。”

林消息若有所思,“这就像是一个更智能的邮递系统,可以根据地址的模式将信件分发到不同的区域。”

"没错,"兔师傅说,“但有时候,你可能希望将消息广播给所有队列,这时就需要用到扇出交换机了。”

扇出交换机:广播模式

兔师傅接着演示了扇出交换机(Fanout Exchange)的工作原理。

“扇出交换机是最简单的一种交换机,它会将收到的消息广播到所有与之绑定的队列,不考虑路由键。”

他设置了一个新的模型,包含一个扇出交换机和三个队列,所有队列都与交换机绑定,但没有指定路由键。

"在扇出交换机中,路由键被完全忽略,"兔师傅解释道,“无论你发送什么路由键的消息,都会被广播到所有绑定的队列。”

他拿出一个信封,不管上面写着什么路由键,都将其放入扇出交换机。信封立即被复制并发送到了所有三个队列。

"扇出交换机适用于需要将消息广播给多个消费者的场景,比如聊天室消息、实时日志广播等。"兔师傅说,“它的特点是简单高效,但缺乏灵活性,因为它不能有选择地发送消息。”

林消息点点头,“这就像是广播电台,所有调到这个频道的收音机都能收到相同的内容。”

"很好的比喻!"兔师傅赞许道,“现在,让我们来看最后一种交换机类型:头交换机。”

头交换机:属性匹配

最后,兔师傅演示了头交换机(Headers Exchange)的工作原理。

“头交换机不使用路由键进行匹配,而是根据消息的头部属性进行路由。这种交换机在实际中使用较少,但在某些特殊场景下非常有用。”

他设置了一个新的模型,包含一个头交换机和两个队列。第一个队列要求消息头部包含"format=pdf,type=report",第二个队列要求消息头部包含"format=pdf,type=log"。

"在头交换机中,你可以定义多个头部属性作为匹配条件,并指定是需要全部匹配(x-match=all)还是部分匹配(x-match=any)。"兔师傅解释道。

他拿出一个特殊的信封,上面没有路由键,但标注了多个属性:format=pdf, type=report, language=en。

"这个消息会被发送到哪个队列?"兔师傅问道。

林消息分析了一下,“它的头部包含’format=pdf,type=report’,所以会被发送到第一个队列。”

"正确!"兔师傅将信封放入交换机,信封果然进入了第一个队列。

"头交换机适用于需要根据多个条件进行复杂匹配的场景,特别是当这些条件不适合编码为路由键的时候。"兔师傅总结道,“不过,由于其复杂性和性能开销,它在实际应用中不如其他类型的交换机常用。”

实战演练:消息分发系统

学习了四种交换机类型后,兔师傅决定让林消息进行一次实战演练。

"现在,我要给你一个任务:设计一个日志收集系统,需要满足以下需求:

  1. 所有日志都需要被存档
  2. 错误日志需要被发送到告警系统
  3. 来自支付系统的日志需要被专门处理
  4. 调试日志只在开发环境中处理"

林消息思考了一会儿,然后开始设计系统:

"我会使用一个主题交换机作为核心,路由键格式为’[环境].[系统].[级别]',例如’prod.payment.error’表示生产环境中支付系统的错误日志。然后设置以下绑定:

  1. 存档队列绑定’#',接收所有日志
  2. 告警队列绑定’..error’,接收所有错误日志
  3. 支付处理队列绑定’.payment.',接收所有支付系统日志
  4. 调试队列绑定’dev.*.debug’,只接收开发环境的调试日志"

兔师傅满意地点点头,“设计得很好!你已经掌握了主题交换机的精髓。现在,让我们实际构建这个系统。”

他们一起搭建了这个日志收集系统,并测试了各种类型的日志消息。系统运行得非常好,每条日志都被正确地路由到了相应的队列。

"你已经掌握了RabbitMQ的核心心法——交换机路由,"兔师傅说,“这是RabbitMQ最强大的特性之一,它使得RabbitMQ在消息路由方面比其他消息队列更加灵活。”

布罗克大师的课堂

学习完兔师傅的交换机心法后,林消息来到了布罗克大师的领地。布罗克大师是一位身材高大、表情严肃的中年人,他的领地充满了分区存储的架构,看起来简洁而强大。

"欢迎来到Kafka领域,年轻人,"布罗克大师的声音低沉而有力,“我听说你已经从兔师傅那里学习了交换机路由的知识。那是很好的基础,但在处理海量数据时,你需要更强大的工具。”

布罗克大师带着林消息来到一个巨大的数据中心,里面排列着无数的服务器。

"Kafka的核心理念与RabbitMQ有所不同,"布罗克大师解释道,“RabbitMQ专注于消息的路由和分发,而Kafka则专注于高吞吐量和持久化存储。在Kafka中,消息被组织为主题(Topic),每个主题又被分为多个分区(Partition)。”

布罗克大师的课堂(续)

布罗克大师指向一个巨大的显示屏,上面展示着Kafka的架构图。

“在Kafka中,数据流被组织为主题(Topic),每个主题又被分为多个分区(Partition)。这些分区分布在不同的服务器上,形成一个分布式的存储系统。”

林消息仔细观察着架构图,“为什么要将主题分成多个分区呢?”

"分区是Kafka实现高吞吐量和水平扩展的关键,"布罗克大师解释道,“通过将一个主题的数据分散到多个分区,Kafka可以实现并行处理,大大提高了系统的吞吐量。每个分区都是一个有序的、不可变的消息序列,新消息不断追加到分区的末尾。”

他带着林消息走到一排服务器前,每台服务器上都运行着Kafka的Broker(代理服务器)。

“这些是Kafka的Broker,它们负责存储和管理分区数据。每个分区都有一个领导者(Leader)和多个追随者(Follower)。领导者负责处理该分区的所有读写请求,而追随者则被动地复制领导者的数据。”

林消息点点头,“这样设计有什么好处呢?”

"高可用性和容错性,"布罗克大师回答,“如果领导者所在的Broker发生故障,Kafka会自动从追随者中选举出新的领导者,确保服务不中断。这就是Kafka的’分区复制’机制,它是Kafka高可靠性的基础。”

分区持久化:Kafka的核心绝技

布罗克大师带着林消息来到一个特殊的训练场,场地中央是一个巨大的日志系统模型。

"现在,我要教你Kafka的核心绝技:分区持久化。"布罗克大师的声音变得更加严肃,“在消息队列世界中,数据的持久化存储是一项基本要求,但Kafka将其提升到了一个新的高度。”

他指向模型中的一个分区,“在Kafka中,每个分区都是一个有序的、不可变的消息序列,被实现为一个日志(Log)。消息被追加到日志的末尾,并被分配一个唯一的偏移量(Offset)。”

布罗克大师拿出一块写着数据的板子,代表一条消息,将其放入日志的末尾。

“看,这条消息被分配了偏移量5,表示它是这个分区中的第6条消息(偏移量从0开始)。消费者可以通过指定偏移量来读取特定位置的消息。”

林消息观察着这个过程,“这与传统的消息队列有什么不同?”

"传统的消息队列通常采用’读即删’的模式,消息一旦被消费就会被删除。"布罗克大师解释道,“但Kafka采用了完全不同的方式:消息被持久化存储在磁盘上,并且不会因为被消费而删除。相反,Kafka为每个消费者组维护一个偏移量,记录它们的消费进度。”

他演示了这个过程:多个消费者从不同的偏移量读取消息,但日志中的消息保持不变。

“这种设计带来了几个重要优势:首先,消息的生产和消费完全解耦,生产者只管写入,不关心谁来消费;其次,同一条消息可以被多个消费者重复消费;最后,消费者可以随时回退到历史位置重新消费消息。”

林消息惊叹于这种设计的巧妙,“但是,如果一直保存所有消息,不会占用太多存储空间吗?”

布罗克大师笑了笑,“好问题。Kafka确实不会永久保存所有消息,它提供了两种数据保留策略:基于时间的保留和基于大小的保留。你可以配置消息的保留时间,比如保留7天的数据;或者配置分区的最大大小,超过这个大小就会删除最旧的数据。”

高吞吐量的秘密

接下来,布罗克大师揭示了Kafka高吞吐量的秘密。

"Kafka的高吞吐量来源于多方面的优化,"他解释道,“首先是零拷贝技术。在传统的数据传输中,数据需要在内核空间和用户空间之间多次复制,而Kafka使用零拷贝技术,直接从磁盘文件到网络通道传输数据,减少了数据复制次数。”

他在黑板上画出了传统数据传输和零拷贝的对比图。

“其次是顺序写入。Kafka将消息追加到分区日志的末尾,这是一种顺序写入操作,比随机写入快得多。磁盘的顺序读写性能远高于随机读写。”

布罗克大师拿出一个磁盘模型,演示了顺序写入和随机写入的速度差异。

“第三是页缓存。Kafka重度依赖操作系统的页缓存,而不是在JVM堆内存中维护自己的缓存。这样做的好处是,即使Kafka进程重启,缓存也不会丢失。”

林消息若有所思,“这就是为什么Kafka能处理如此大量的数据而保持高性能。”

"没错,"布罗克大师点头,“此外,Kafka还采用了批量处理和压缩技术来进一步提高吞吐量。生产者可以将多条消息打包成一个批次一起发送,减少网络传输的次数;同时,消息可以被压缩,减少网络带宽的使用。”

实战演练:日志收集系统

学习了Kafka的核心概念后,布罗克大师给林消息布置了一个实战任务。

"现在,我要你设计一个基于Kafka的日志收集系统,需要满足以下要求:

  1. 能够处理每秒数十万条的日志消息
  2. 日志需要保存7天
  3. 多个应用可以同时消费这些日志
  4. 系统需要具备高可用性,任何单点故障不应影响整体服务"

林消息思考了一会儿,然后开始设计系统:

"我会创建一个名为’application-logs’的主题,并将其分为10个分区,每个分区有3个副本,分布在不同的Broker上。这样可以实现负载均衡和高可用性。

对于生产者,我会配置适当的批处理大小和压缩算法,以提高吞吐量;同时设置acks=all,确保消息被安全复制到所有副本后才确认写入成功。

对于消费者,我会为不同的应用创建不同的消费者组,这样每个应用都可以独立消费全部日志。

最后,我会设置日志保留策略为7天,确保日志不会占用过多存储空间。"

布罗克大师满意地点点头,“设计得很好!你已经掌握了Kafka的核心理念。现在,让我们实际构建这个系统。”

他们一起搭建了这个日志收集系统,并进行了压力测试。系统表现出色,轻松处理了每秒数十万条的日志消息,而且在模拟的Broker故障场景中依然保持了服务的连续性。

"你已经掌握了Kafka的分区持久化绝技,"布罗克大师说,“这是处理海量数据的强大工具。记住,Kafka不仅仅是一个消息队列,它更是一个分布式流处理平台,可以用于构建实时数据管道和流式应用。”

若奇大师的事务消息

学习完Kafka后,林消息来到了若奇大师的院落。若奇大师是一位中年男子,身着阿里风格的服饰,表情沉稳而自信。

"欢迎来到RocketMQ的世界,"若奇大师微笑着说,“我听说你已经学习了RabbitMQ的路由技巧和Kafka的分区存储。这些都是很好的基础,但在处理复杂业务场景时,你还需要掌握一项特殊的武功:事务消息。”

若奇大师带着林消息来到一个模拟银行转账的场景。

"想象一下,"他说,“一个银行转账操作涉及两个步骤:从账户A扣款,然后向账户B存款。这两个操作必须同时成功或同时失败,否则就会出现数据不一致的问题。在单体应用中,我们可以使用数据库事务来保证这种一致性,但在分布式系统中,当这两个操作分布在不同的服务中时,问题就变得复杂了。”

林消息点点头,“这就是分布式事务问题。”

"没错,"若奇大师说,“RocketMQ提供了事务消息机制来解决这个问题。它的核心思想是将分布式事务拆分为两个本地事务,并通过消息队列来协调它们的执行。”

事务消息的工作原理

若奇大师在黑板上画出了事务消息的流程图。

"RocketMQ的事务消息分为三个阶段:

  1. 发送半消息(Half Message)
  2. 执行本地事务
  3. 提交或回滚消息"

他详细解释了每个阶段:

"首先,生产者发送一条’半消息’给RocketMQ服务器。这条消息对消费者不可见,相当于一个预备状态。

然后,生产者执行本地事务,例如从账户A扣款。

最后,根据本地事务的执行结果,生产者向RocketMQ服务器发送提交或回滚指令。如果本地事务成功,就提交消息,使其对消费者可见;如果本地事务失败,就回滚消息,消息将被丢弃。"

林消息思考着这个流程,“但是,如果在执行完本地事务后,生产者崩溃了,无法发送提交或回滚指令,会怎么样?”

"好问题!"若奇大师赞许道,“RocketMQ有一个事务状态回查机制。如果RocketMQ服务器在一定时间内没有收到提交或回滚指令,它会主动向生产者查询事务状态。生产者需要实现一个回查接口,通过查询本地事务的执行结果来决定是提交还是回滚消息。”

他演示了这个回查过程,展示了RocketMQ如何处理各种异常情况,确保事务的一致性。

实战演练:分布式事务

学习了事务消息的原理后,若奇大师给林消息布置了一个实战任务。

"现在,我要你实现一个电商系统的订单创建流程,包括以下步骤:

  1. 创建订单记录
  2. 扣减商品库存
  3. 生成支付单

这三个步骤分别由不同的服务处理,你需要使用RocketMQ的事务消息确保它们的一致性。"

林消息思考了一会儿,然后开始设计系统:

"我会将整个流程分为两个事务:
第一个事务处理订单创建和库存扣减:

  1. 订单服务发送一条半消息,内容是创建订单的信息
  2. 订单服务在本地数据库中创建订单记录
  3. 如果创建成功,提交消息;否则回滚消息
  4. 库存服务消费这条消息,扣减库存

第二个事务处理支付单生成:

  1. 库存服务完成库存扣减后,发送一条半消息,内容是生成支付单的信息
  2. 库存服务在本地更新库存状态
  3. 如果更新成功,提交消息;否则回滚消息
  4. 支付服务消费这条消息,生成支付单

同时,我会实现事务状态回查接口,处理可能的异常情况。"

若奇大师满意地点点头,“设计得很好!你已经掌握了事务消息的核心思想。现在,让我们实际实现这个系统。”

若奇大师的事务消息(续)

他们一起实现了这个电商系统的订单创建流程,并进行了各种异常场景的测试。系统表现出色,即使在模拟的服务崩溃和网络中断场景中,也能保证数据的一致性。

"你已经掌握了RocketMQ的事务消息武功,"若奇大师说,“这是处理分布式事务的强大工具。在复杂的业务场景中,保证数据一致性是一项重要但困难的任务,事务消息为我们提供了一种可靠的解决方案。”

顺序消息:保证消息顺序

学习完事务消息后,若奇大师又向林消息介绍了RocketMQ的另一个重要特性:顺序消息。

"在某些业务场景中,消息的处理顺序非常重要,"若奇大师解释道,“例如,对于同一个订单的创建、支付、发货、完成这几个状态变更消息,必须按照顺序处理,否则会导致业务逻辑错误。”

他在黑板上画出了顺序消息的处理流程。

“RocketMQ提供了两种顺序保证:全局顺序和分区顺序。全局顺序意味着一个主题内的所有消息都按照发送顺序被消费;分区顺序则意味着同一个分区内的消息按照发送顺序被消费,不同分区之间不保证顺序。”

若奇大师拿出几个标有不同订单ID的消息卡片,演示了如何通过消息队列保证顺序。

“在实践中,我们通常使用分区顺序,将具有相同业务标识(如订单ID)的消息发送到同一个分区,这样就能保证同一业务实体相关的消息按顺序处理,同时又能通过多个分区实现并行处理,提高吞吐量。”

林消息点点头,“这就像是在银行办理业务,每个窗口都按照顺序处理客户,不同窗口之间互不影响。”

"没错!"若奇大师赞许道,“RocketMQ通过MessageQueueSelector接口让生产者可以选择将消息发送到哪个队列,从而实现分区顺序;同时,消费者通过MessageListenerOrderly接口确保同一个队列的消息被顺序消费。”

消息过滤:精准投递

接下来,若奇大师向林消息介绍了RocketMQ的消息过滤机制。

"在实际应用中,消费者往往只对某些特定的消息感兴趣,而不是主题中的所有消息。"若奇大师解释道,“RocketMQ提供了多种消息过滤方式,让消费者可以只消费自己关心的消息。”

他演示了三种过滤方式:

“第一种是基于Tag的过滤。每条消息可以有一个Tag属性,消费者在订阅主题时可以指定感兴趣的Tag。例如,一个日志主题可能包含ERROR、WARNING、INFO三种Tag的消息,告警系统只需要订阅ERROR Tag的消息。”

“第二种是基于SQL表达式的过滤。消费者可以提供一个SQL92标准的表达式,RocketMQ会根据这个表达式过滤消息。这种方式比Tag更加灵活,可以基于消息的多个属性进行复杂的过滤。”

“第三种是通过Filter Server进行过滤。对于更复杂的过滤逻辑,可以部署Filter Server,在服务端执行自定义的过滤代码。”

林消息理解了这些过滤机制,“这样可以减少不必要的消息传输和处理,提高系统效率。”

"没错,"若奇大师说,“消息过滤是提高消息投递精准度和系统效率的重要手段。”

动感老师的JMS规范

学习完RocketMQ后,林消息来到了动感老师的练武场。动感老师是一位年长的男子,看起来经验丰富,但精力充沛。

"欢迎来到ActiveMQ的世界,年轻人,"动感老师热情地说,“我听说你已经学习了很多高级的消息队列技术。这很好,但今天我要教你一些更基础但同样重要的东西:JMS规范。”

动感老师带着林消息来到一个教室,墙上挂着JMS(Java消息服务)规范的图表。

"JMS是Java平台上的消息服务标准,"动感老师解释道,“它定义了一组API,使得Java应用程序可以创建、发送、接收和读取消息。ActiveMQ是JMS规范的一个实现,但了解JMS规范本身对于理解所有Java消息中间件都很有帮助。”

JMS的核心概念

动感老师首先介绍了JMS的核心概念。

"JMS模型包含以下几个关键组件:

  1. JMS提供者(Provider):实现JMS接口的消息中间件,如ActiveMQ
  2. JMS客户端(Client):生产或消费消息的Java应用程序
  3. JMS生产者(Producer):创建和发送消息的客户端
  4. JMS消费者(Consumer):接收和处理消息的客户端
  5. JMS消息(Message):在生产者和消费者之间传递的数据
  6. JMS队列(Queue):点对点模式下的消息目的地
  7. JMS主题(Topic):发布/订阅模式下的消息目的地
  8. JMS连接(Connection):客户端与JMS提供者之间的连接
  9. JMS会话(Session):用于创建消息生产者、消费者和消息的上下文"

他在黑板上画出了这些组件之间的关系图,帮助林消息理解它们是如何协同工作的。

消息传递模式

接下来,动感老师详细解释了JMS支持的两种消息传递模式。

“JMS支持两种消息传递模式:点对点(Point-to-Point,简称P2P)和发布/订阅(Publish/Subscribe,简称Pub/Sub)。”

他分别演示了这两种模式:

“在点对点模式中,消息被发送到一个队列,每条消息只能被一个消费者消费。即使有多个消费者连接到同一个队列,每条消息也只会被其中一个消费者接收和处理。这种模式适用于需要确保每条消息只被处理一次的场景。”

“在发布/订阅模式中,消息被发送到一个主题,所有订阅该主题的消费者都会收到消息的副本。这种模式适用于需要将消息广播给多个接收者的场景。”

林消息思考了一下,“这两种模式分别对应了我之前学习的点对点模式和扇出交换机?”

"是的,概念上是相似的,"动感老师点头,“不同的消息队列产品可能使用不同的术语,但基本原理是一致的。JMS规范为Java平台上的消息传递提供了一个标准接口,使得应用程序可以与不同的JMS提供者进行交互,而不需要修改代码。”

消息类型和属性

动感老师接着介绍了JMS支持的消息类型。

"JMS定义了几种消息类型,以适应不同的数据传输需求:

  1. TextMessage:包含一个字符串的消息
  2. MapMessage:包含键值对的消息
  3. BytesMessage:包含一个字节数组的消息
  4. StreamMessage:包含Java基本类型数据流的消息
  5. ObjectMessage:包含一个可序列化Java对象的消息"

他拿出几个不同类型的消息示例,展示了它们的结构和用法。

“除了消息体,JMS消息还包含头部(Header)和属性(Properties)。头部包含一些标准的元数据,如消息ID、时间戳、目的地等;属性则允许你添加自定义的元数据,可以用于消息过滤和处理。”

实战演练:基于ActiveMQ的消息系统

学习了JMS规范后,动感老师给林消息布置了一个实战任务。

"现在,我要你使用ActiveMQ实现一个简单的消息系统,包括以下功能:

  1. 创建一个点对点队列和一个发布/订阅主题
  2. 实现消息生产者,能够发送不同类型的消息
  3. 实现消息消费者,能够接收和处理消息
  4. 使用消息选择器进行消息过滤"

林消息根据所学知识,很快实现了这个系统。他创建了连接工厂、连接、会话、生产者和消费者,并成功地在队列和主题中传递了消息。

"做得好!"动感老师赞许道,“你已经掌握了JMS的基本用法。虽然ActiveMQ可能不如新一代的消息队列那么强大,但它实现了JMS规范,提供了标准化的API,这在企业级应用中非常有价值。”

消息持久化与确认机制

最后,动感老师向林消息介绍了JMS的消息持久化和确认机制。

“在JMS中,消息可以是持久的或非持久的。持久消息会被JMS提供者保存到持久存储中,即使服务器重启,消息也不会丢失;非持久消息则只存在于内存中,服务器重启后会丢失。”

他演示了如何设置消息的持久性:

“对于生产者,可以通过设置消息的持久模式(DeliveryMode)来指定消息是否持久化;对于消费者,可以创建持久订阅,确保即使在消费者离线期间发布的消息也能在消费者重新连接后被接收。”

接着,动感老师解释了JMS的消息确认机制:

"JMS提供了几种消息确认模式:

  1. AUTO_ACKNOWLEDGE:消息被消费者接收后自动确认
  2. CLIENT_ACKNOWLEDGE:消费者显式调用acknowledge()方法确认消息
  3. DUPS_OK_ACKNOWLEDGE:允许重复消息的延迟确认
  4. SESSION_TRANSACTED:在事务提交时确认消息"

他强调了选择合适的确认模式的重要性:

“确认机制直接关系到消息的可靠性。如果选择自动确认,但消费者在处理消息过程中崩溃,可能导致消息丢失;如果选择客户端确认,则可以在成功处理消息后再确认,提高可靠性,但也增加了编程复杂性。”

章节总结

经过一天的学习,林消息已经从四位大师那里学到了丰富的消息队列知识。

队列老祖将他们召集到一起,“今天,你学习了四种不同的消息队列技术,每种都有其独特的特点和适用场景。”

他总结道:

"兔师傅的RabbitMQ以灵活的路由机制著称,通过四种交换机类型(直接、主题、扇出和头交换机)实现了丰富的消息分发模式,适合需要复杂路由的场景。

布罗克大师的Kafka专注于高吞吐量和持久化存储,通过分区机制和日志结构实现了出色的性能和可靠性,适合处理海量数据的场景,如日志收集、流处理等。

若奇大师的RocketMQ在保证可靠性的同时,提供了事务消息、顺序消息和消息过滤等高级特性,适合对数据一致性要求高的复杂业务场景。

动感老师的ActiveMQ实现了JMS规范,提供了标准化的API和丰富的消息类型,适合Java平台上的企业级应用。"

林消息感叹道,“每种消息队列都有其独特的优势,选择合适的技术需要根据具体的业务需求和场景。”

"没错,"队列老祖点头,“消息队列不是一种’一刀切’的技术,而是一个丰富的工具箱,你需要根据实际情况选择合适的工具。今天你学到的知识只是一个开始,接下来你将在实际应用中不断深化和拓展这些知识。”

林消息向四位大师鞠躬致谢,"感谢各位大师的教导。

http://www.dtcms.com/a/282844.html

相关文章:

  • ES组合使用must与should时的注意事项
  • 【Springer出版 EI检索】第十三届信息系统与计算技术国际会议诚邀请您参与 8.15-17日 上海举办
  • Spring之核心容器(IoC,DI,基本操作)详解
  • iOS 性能监控工具全解析 选择合适的调试方案提升 App 性能
  • Towards Low Light Enhancement with RAW Images 论文阅读
  • 玩转Docker | 使用Docker部署bender个人导航页工具
  • 力扣-146.LRU缓存机制
  • 主机安全---开源wazuh使用
  • 在 Ubuntu 上安装 GBase 8s 的完整实战指南
  • 立创EDA操作记录
  • Linux网卡与软件仓库快捷配置脚本
  • 基于Hadoop与LightFM的美妆推荐系统设计与实现
  • Leetcode Easy刷题:合并两个连续系列
  • 【Java入门到精通】(五)初识MySql数据库
  • Linux Ubuntu apt包管理器安装K8s1.30.1+Ingress-Nginx
  • 神经网络之权重初始化
  • 【深度学习】神经网络-part3
  • 云原生技术
  • 合成孔径雷达干涉测量InSAR技术流程(星载/地基系统+DEM重建+DInSAR形变监测+时序分析)等
  • 杨辉三角-附C语言实现方法
  • TBT 5、TBT 4 和 USB4 的差异概述
  • 零基础数据结构与算法——第五章:高级算法-动态规划经典-背包问题
  • 单片机学习笔记.IIC通信协议(根据数据手册写IIC驱动程序,这里以普中开发板上的AT24C02为例)
  • HTTP REST API、WebSocket、 gRPC 和 GraphQL 应用场景和底层实现
  • 使用Django框架构建Python Web应用
  • 插入排序及其时间复杂度分析
  • 类模版的相关案例
  • 数字输入缓冲器是如何影响低功耗电流的?
  • 建设大模型应用的方法和理论
  • Lsposed/Xposed