读书笔记 2 -- 《rabbitMq 实战指南》
消息中间件的作用: 1、解耦 2、冗余(存储) 3、扩展性(增加生产者/消费者) 4、削峰 5、异步处理 6、保证顺序 消息通信标准: 1、JMS(Java Message Service):隐藏单独MQ产品提供商的实际接口。针对API编程,选择合适的MQ驱动(该驱动实现了JMS接口规范)即可随意切换MQ。 ActiveMQ就是JMS的一种实现。 2、AMQP(Advanced Message Queuing Protocol,高级消息队列协议) 特性:使用协议就可以对队列和交换器这样的资源进行配置。 RabbitMq 1、AMQP(Advanced Message Queuing Protocol,高级消息队列协议) 2、特性: 2.1、可靠性:持久化、传输确认、发布确认。 2.1、灵活的路由:在消息进入队列之前,通过交换器来路由消息。 2.3、扩展性:集群。 2.4、高可用:副本镜像。 2.5、多种协议:原生支持AMQP协议,还支持STOMP、MQTT等多种消息中间件协议。 2.6、多语音客户端、管理界面、插件机制等。 第二章: 1、概念介绍 1、队列(Queue):用于存储消息。 多个消费者可以订阅同一个队列,此时队列中的消息会被平均分摊(Round-Robin,即轮询),给多个消费者进行处理。 2、交换器、路由键、绑定 Exchange:交换器。负责交换的动作。 RoutingKey:路由键。用于将消息路由到对应的队列。 Binding:绑定。将队列和交换器关联起来。 消息 -》Exchange -> 根据RoutingKey路由到对应的队列 -> 存入队列 3、交换器类型 1、fanout:发送到该交换机的消息路由到所有与该交换机绑定的队列中。 2、direct:把消息路由到BindingKey和RoutingKey完全匹配的队列。 3、topic:模糊匹配的direct。用“.”来分割,“*”:模糊匹配一个单词;“#”:模糊匹配多个单词。 4、headers:不依赖路由键的规则来路由消息。根据发送的消息内容中的headers属性进行匹配。(性能差,基本不用) 4、运转流程 生产者流程: 1、建立链接 Connection , 开启通道 Channel 2、声明交换器,设置交换器相关属性,如交换器类型、是否持久化等。 3、声明一个队列,并设置相关属性,如是否排他、是否持久化、是否自动删除等。 4、用路由键将交换器和队列绑定。 5、生产者发送消息到RabbitMq Broker,其中包含路由键、交换器等信息。 6、Broker的交换器根据路由键查找相匹配的队列。 7、找到匹配队列,则将消息存入队列中。 8、没有找到匹配的队列,则根据生产者的属性将消息丢弃或者回退给生产者。 9、关闭通道。 10、关闭链接。 消费者流程: 1、消费者链接到Broker,建立Connection,开启通道Channel。 2、消费者向Broker请求消费相应队列中的消息,可能会 设置相应的回调函数。 3、等待Broker回应并投递相应队列中的消息,消费者接收消息。 4、消费者确认接到消息。(ack) 5、RabbitMq从队列中删除被确认的消息。 6、关闭通道。 7、关闭链接。 5、链接、通道 一个TCP链接,多个通道。(NIO,TCP链接复用) NIO中有一个很有名的Reactor模式。 一个Connection对应多个Channel,当流量很大时,需要多开几个Connection。 2、AMQP协议 协议分为三层 1、Module Layer:协议最高层,定义了一些供客户端调用的命令。如:声明队列,订阅队列。 2、Session Layer:协议中间层,负责将客户端的命令发送给服务器,再将服务端的应答返回给客户端。处理客户端和服务器之间的通信,同步机制和错误处理。 3、Transport Layer:协议最底层,主要传输二进制数据流,提供帧的处理,信道复用,错误检测和数据标识等。 AMQP说到底还是一个通信协议,通信协议都会涉及到报文交互。 第三章: 重点:连接、交换器/队列的创建与绑定、发送消息、消费消息、消费消息的确认、关闭链接。 1、连接RabbitMQ Connection开启多个Channel。 Connection可以多线程共享,Channel不可以多线程共享。 2、交换器和队列 1、交换器初始化参数解析 1、durable:设置是否持久化。Broker重启,持久化的交换器会恢复。 2、autoDelete:设置是否自动删除。交换器与队列之间的绑定关系。 3、noWait:不需要服务器返回。(创建交换器不需要服务器应答,弊端:不确定交换器是否创建成功。) 2、队列初始化参数解析 1、durable:设置是否持久化。服务重启消息还在。 2、exclusive:设置是否排他。排他:仅首次声明队列的连接可见,断开连接时自动删除。基于连接可见的(非通道,意思连接下的多个通道可以使用该队列) 3、autoDelete:设置是否自动删除。消费者连接到这个队列,当所有的消费者都断开连接时,删除队列。 3、发送消息 1、mandatory:确保消息到达。 3、消息消费 1、推模式:Basic.Consume 参数详解: consumerTag:消费者标签,用来区分多个消费者。 noLocal:true表示不能将同一个Connection中生产者的消息给同一个Connection中的消费者消费。 2、拉模式:Basic.Get 4、消息的确认与拒绝 1、确认 自动确认:消息推送给消费者后,就删除消息。不管消息是否真的被消费。 手动确认:等待消费者显式地回复确认信号后,才从内存/磁盘中移除消息。(先标记为删除,之后再删除。) 队列中消息分成两个部分:一部分是等待投递给消费者的消息,另外一部分是已经投递给消费者,等待消费者确认的消息。 如果RabbitMQ一直没有收到消费者的确认信号,并且消费此消息的消费者已经断开连接,则RabbitMQ会安排该消息重新进入队列,等待投递给下一个消费者。 2、拒绝 requeue,拒绝的消息是否重新入队列。 死信队列:存放requeue=false的信息 第四章: 1、消息丢弃策略 mandatory:(强制的)true 找不到队列,返回给生产者。 false 丢弃。 immediate:(立即的)true 队列上不存在消费者,那么该消息不存入队列。当所有的队列都不匹配时,消息将会返回。 false 存入队列。 备份交换器:(Alternate-Exchange) 如果不想消息被丢弃,那么需要设置mandatory,但是这样的处理方式需要生产者添加ReturnListener监听,增加了生产者的复杂性。因此引入备胎交换器。 2、过期时间(TTL, Time to Live) 1、设置消息的TTL 1、通过队列属性设置,队列中所有的消息都有一样的过期时间。 2、仅对某条消息设置过期时间。 3、以上两点,那个时间短,用谁的。 3、死信队列(DLX , Dead-Letter-Exchange 死信交换器) 1、死信的原因 1、消息被消费者拒绝。 2、消息过期。 3、队列达到最大长度。 2、死信队列绑定到正常的队列上,当该队列有死信消息,就发送该消息到死信队列上。 4、延迟队列 使用场景: 1、订单系统中,用户下单之后通常有30分钟的时间进行支付,如果超过30分钟,那么订单将进行失效处理。 2、支付的异步通知。 3、在半夜(系统不繁忙的时间段)轮询数据库,将要今天内处理的事情,发送到延迟队列。等待消费者进行处理。 实现方式: 使用TTL和DLX实现。 5、优先级队列 1、设置队列的x-max-priority参数来实现。 2、存在消息堆积,才有意义。 3、优先级高的消息,优先被消费。 6、持久化(弊端:内存的速度当然快于硬盘的速度) 1、交换器持久化:durable=true 2、队列持久化:durable=true 3、消息持久化:BasicProperties的deliveryMode=2 7、生产者确认 1、通过事务机制实现 1、channel.txSelect 用于将当前的通道设置为事务模式。 2、channel.txCommit 用于提交事务。 3、channel.txRollback 用于事务回滚。 (缺点,性能差。推荐下面的方式) 2、通过发送方确认(publisher confirm)机制实现。 生产者将通道设置成confirm(确认)模式,通道发布消息时会被指派一个唯一的ID(从1开始),一旦消息投递到对应的队列后,RabbitMQ会发送一个确认给生产者(确认的消息包含ID), 通过该方式确保消息到达。 8、消费端要点介绍 1、消息分发 1、默认用轮询的方式接收。(由于机器性能不一,需要做额外的处理) 2、channel.basicQos(); 允许限制通道上的消费者所能保持的最大未确认消息的数量。 2、消息顺序性 消费者消费的消息和发送者发送的消息顺序是一致的。 RabbitMQ不保证消息的顺序性。 如果需要顺序消息,需要开发者自己处理。(在消息体内添加全局有序标识) 3、弃用 QueueingConsumer 9、消息传输保证 1、最多一次。 2、最少一次。 3、恰好一次:无法保证。
未完,待续。