即时消息通讯:RPC
延迟消息通讯:消息队列
发送者构造,接受者解析,遵循一定的格式,这就是消息协议
消息是信息的载体
建立在网络IO模型的基础上
某一种消息通讯软件的实现,都建立在协议的基础上
比较流行的服务器叫做Openfire
基于XML,用于IM系统的开发,使用MINA作为下层的网络IO框架
协议的关键信息:
stream标记:通讯流标记。指通讯请求,不携带内容信息,表明发生了交互
iq标记:一组的形式出现,客户端请求,服务的返回结果
jid标记:表示XMPP网络中的各个XMPP实体
message标记:实体内容标记
presence标记:XMPP用户的服务状态
构成:命令/信息关键字,头信息,文本内容
两个角色 :
Stomp Broker:任意消息代理
Stomp Client
基本命令/返回信息(帧)
connect/stop,连接/断开代理端
connected, 代理端接受connect并处理成功,想客户端发送connected状态信息,有可能发送error信息
send:向代理端虚拟路径发送内容
subscribe:客户端向服务代理订阅某一虚拟路径的监听
unsbscribe:取消某个路径的消息时间的监听
message:对客户端订阅的位置收到的消息的描述
begin:开启事务命令
commit:提交命令,只有提交后,事务中的消息才会进入代理端的消息队列
abort:取消或终止未提交的事务
ack:客户订阅是ack设置为client,代理发送消息后,必须收到客户端确认,若没有确认,在客户端断开连接之后,代理将会发送给其他客户端
nack:不确认命令,客户端发送给代理端,表示消息在客户端处理失败,代理端将会发送给其他客户端(无论当前客户端是否断开)
disconnect:断开命令,断开客户端与代理端
Message消息体
Producer消息生产者
Consumer消息消费者
服务端(Broker)
Virtual Host:虚拟主机
Exchange: 交换机
Queue :队列
Connection:由生产者和消费者产生,连接到Broker物理节点上
Channel:客户端创建连接到VirtualBox Host 或者 Queue上
Exchange:交换机,可以绑定多个queue,或者其他的exchange
处理流程:
producer建立channel通道,连接到broker上的virtual host,向exchange发送消息
excahnge必须事先与其他exchange或者queue连接,并有明确的路由规则,接收消息,并送到queue/exchange
queue收到消息,若果当无consumer的channel,就将消息存储直至channel创建,若有按顺序发送
consumer接收到消息后,并进行处理,发送一条ack到queue,queue会将该消息移除掉
Message格式
PAYLOAD:交付区
header:记录在支持AMQP中间件中的交互状态
delivery-annotations:在header部分职能传递规范的,标准的,经过ISO/IEC组织定义的属性,而此处用来传递一些非标准的。
message-annotation:存储自定义的辅助属性,自定义属性主要用于消息的转换
properties:从properties到application-data都是正文,properties记录消息正文中不可变的属性。例如消息id,分组id等等
application-properties:记录和应用有关的数据,如:消息的routing值是什么,是否进行持久化等
application-data:我们发送的真实内容
footer:存储辅助内容,如消息hash值,签名或者加密细节
Exchange路由规则
AMQP路由实现
1.Direct Exchange (将消息中的Routing-Key 与Queue的Routing-key 进行对比,两者如果完全匹配,则进行发送到Queue)
2.Fanout Exchange (不需要Routing-key,将消息复制多份发送到和自己绑定的Queue之中。)
3.Topic Exchange (是Routing-key的匹配模式,即模糊查询后发送)
1,3 模式下,exchange找不到匹配的queue,消息将会被遗弃,exchange不会将消息保存queue会保存
JMS规范
不是消息队列,也不是消息队列协议
java消息服务接口,一套规范的Java API接口。
是一个典型的应用层协议
Channel的定义是基于网络连接记录会话状态
Queue等元素帮助AMQP完成路由规则
命令参数
stop:停止当前ActiveMQ节点的运行
restart:重启当前节点
status:查看节点运行状态,没有运行将会返回一条信息。status只能告诉我们节点是不是运行的,其他信息无法获得。
console:使用控制台启动节点,调试监控当前节点情况
dump:以console模式运行,获取当前节点的线程状态快照
不同工作机制的消息队列
Queue:JMS-Queue是一种负载均衡模式实现
Topics: JMS-Topic队列基于“订阅-发布模式”
消息收发模式
JMS和协议转换
1. 消息中间件只要实现了JMS规范,就可以进行多种消息协议之间的转换,比如生产者是AMQP协议,发送者可以接受XMPP协议。
2. AMQP消息并没有说必须经过Exchange规则才能到达队列,也没有规定Exchange必须要实现某种规则的路由,所以支持AMQP协议,是否需要有Exchange这样的路由处理规则,完全取决于AMQP的消息中间软件厂商自己的决定。
性能优化思路
代码级性能
规则性能
存储性能
网络性能
多节点协同方法(集群方案)
网络IO优化
ActiveMQ支持五种协议,为了优化,不同的协议需要配置不同的网络监听端口
5.13.0 将四种协议的端口监听进行了合并,使用auto关键字进行表示,只是表示简洁,没有提升性能
ActiveMQ的端口默认使用BIO网络IO模型,为提升吞吐性,可以指定nio网络模型,即为 每一个独立的MQ服务节点配置更高效的网络IO模型
默认协议
openwire
支持的协议
AMQP
MQTT
Openwire
Stomp
REST
XMPP
JMS规范概念
消息收发模式(订阅-发布和负载均衡模式)
消息存储模式(持久化消息和非持久化消息)
1. NON_PERSISTENT Message (该模式默认不等待服务节点给生产者发送回执,即异步)
2. PERSISTENT Message (该模式下,生产者发送消息,服务节点在完成持久化存储操作之后,会向生产者发出确认消息,即同步消息发送模式,也可以设置为为不进行等待回执,即异步消息发送模式)
订阅模型:(持续订阅和非持续订阅)
1. Durable-Subscribers
2. Non-Durable Subscribers
是针对订阅-发布模式的细分
处理规则和优化
1. (优化点)生产者不能一味追求发送效率,会产生消息堆积
2. 会以一种设置好的策略将消息发送给消费者:服务节点主动推送消息给某一个消费者,最
3.重要的属性是prefetchSize:单次获得的消息数量
4. 消费者的处理性能影响ActiveMQ系统的性能
生产者策略:
1. 默认发送持久化消息,非持久化需要指出,默认采用采用同步发送
2. 发送非持久化消息时,默认采用异步方式
3. 发送持久化消息,默认采用同步方式,可设置为异步,并需要设置累计文件大小后,进行一次回执
4. 事务:
启动一个事务后(发送者在连接会话设置一个事务号Transaction ID(自动设定)),事务中发送多条消息,事务提交前不会进入队列。
服务器会收到消息,发现有sessionID 会放置到transaction store 之中(带有redo日志,用于回滚),等待回滚或提交,因而不进入队列
5. 生产控制流:ProducerFlowControl
设定了产生消息堆积后,如何进行生产者端的限流
ActiveMQ会让生产者进入等待状态,或者直接抛出JMSException
异步发送非绝对的异步,消息发送者在发送一定大小的消息后,会等待服务端进行回执(这个方案只针对异步发送消息)
消费者策略:
1. Dispatch Async
采用异步推送模式,即服务端不会等待消费者端进行消息回执
2. prefetch(服务节点每一次消息推送都有一定的数量限制)
queue模式
持久化:1000
非持久化:1000
topic模式
持久化:100
非持久化:32766
3. 事务
消费者端支持事务,可通过commit和rollback方法,告知服务器,一组消息是否完成。采用事务的意义在于,一组消息,要么全部被处理并确认成功,要么全部回滚进行处理
调用commit,表示一组消息处理完毕
调用rollback,消费者已经消费的消息,并不是预取消息,会重新从服务节点发送到消费者端,并且redeliveryCounter(重发计数器)属性将会加1
4. 重发和死信
死信队列:一条消息被重发多次,会放置到死信队列,默认是6次
默认只接受持久化消息,非持久化消息达到重发上限后,会被删除掉,但是可以配置移动到死信队列
重发机制的可能性:
在支持消费者会话连接中调用rollback
在支持消费者连接会话中,使用commit告知服务器之前,会话连接终止。
在使用ack会话连接下,在告知服务器消息处理之前,会话连接终止
作用区域是本次连接会话
作用域是整个ActiveMQ的系统范围
5. ACK
除了使用事务告知服务节点之外,还可以使用acknowledge模式进行告知,并且更常用
AUTO_ACKNOWLEDGE: 消费者通过receiver或者MessageListener监听方式从服务端获取消息之后,会话默认处理成功(但ack并不一定是一条发送一个ack)
CLIENT_ACKNOWLEDGE:必须显示调用acknowledge,要么activeMQ会认为消息没有处理成功
DUPS_OK_ACKNOWLEDGE:批量确认方式,间隔发送ack到服务端
INDIVIDUAL_ACKNOWLEDGE:单条确认方式
推荐使用,并设置较小的prefetchsize,optimizeACK只有在该模式下生效,表示采用延迟确认方式,即消息达到一定的值之后,再发送确认消息
如果目标队列是queue模式,则和auto模式效果一致,没有开启optimizeACK,也会一条一条发送,如果是topic模式,无论是否开启optimizaACK,都会采用 >= prefetch * 0.5,批量确认消息
生产者和消费者性能总结:
1. 持久化存储和非持久化存储是有性能差异的,非持久化消息发生消息堆积,会转储到物理磁盘的temp store中
2. 带发送事务和不带发送事务是有差异的,带事务的消息会首先记录在服务器的transaction store 并带有redo日志,保证后面的commit和rollback操作
3.设置produceFlowController非常重要,保证ActiveMQ处理消息堆积,稳定工作
4.消费者和生产者都可采用异步连接服务节点,生产者使用异步要和producerWindowSize(回执窗口期)的设置共同使用,消费者异步接受消息,要记住prefetch这个预取数目
5.消费者端支持事务,要么全被commit,要么全被rollback,重发很消耗性能,因为prefetch但是还没有被处理的消息会一直等待重发的消息被最终确认。
6.避免无休止的重发,应设定MaximunRedeliveries阈值 默认为6,建议为3,加入死信队列
7. 消费者端有四种ack模式,建议使用auto_acknowledge 并要设定改小预取数量,设置OptimizeAcknowlege 为true, 设置OptimizeAcknowledgeTimeOut时间,保证工作在“延迟模式”下,以便优化ACK性能
持久消息存储方案
总结点:
1.所有的PRESISTENT Message都要执行持久化存储工作,非持久化虽然不会持久化,单非一直在内存区域之中
2.Topic模式在没有任何订阅者的情况下,也会进行持久化存储,然后再进行标记
3.启动事务的情况下,没有commit操作,持久化操作依旧会执行,只是这些事务中的消息不会进行确认操作,不会分到指定的具体队列,使用send方法,就会发送到服务器端,就会进行持久化操作。
4服务器内部持久化完成之后,会自己通知自己,是同步通知,但可以改为异步通知,加快处理效率
5.进行了持久化的消息,只有消费端消费掉,并返回确认值,才会删除掉
6.三种推荐存储方案:磁盘文件系统,active MQ的内置数据库,外部关系型数据库
存储方案配置:
1.ActiveMQ的内核是java编写,启动脚本使用wrapper包装器来启动JVM
2,ActiveMQ的每一个服务节点都是一个独立的进程
3.内存配置参数(AMQ主配置文件下)
systemUsage:节点进程级别的各种“容量设置”,可设置属性包括下面
sendFailIfNoSpaceAfterTimeout:服务器收到消息,没有地放,会等待这么久时间,超过等待时间,将会给发送端抛出异常,拒收这条消息
memoryUsage:设置整个ActiveMQ节点的“可用内存限制”,可用子标记 limit进行固定容量授权
storeUsage:用于存储“可持久化消息”的“可用磁盘空间”,子标记limit必须设置,对于采用数据库存储方案,该项不起作用
tempUsage:服务界节点存储达到memoryUsage限制,非持久化消息会转储到temp store区域(磁盘的临时区域),是为了防止数据洪峰,大量非持久化消息堆积导致内存耗尽。
4. 存储方案:
第一种方案: KahaDB存储方案
kahaDB
1.基于文件系统
2.支持事务
3.AMQ默认持久化存储方案
主要元素
1.一个内存 Metadata Cache 用来在内存中检索消息的存储位置
2.用于记录消息内容的Data log文件
1.每个Data Log 文件默认大小为32M。可设置
2,当Data log中所有消息被成功消费之后,Data log会在Metadata Cache被标记为删除,在下一个checkpoint会被删除掉
3.Data log文件采用顺序写的方式操作,为保证物理连续,会进行预占这些扇区
4,。消息的位置索引采用BTree的结构被存储在内存之中,即Metadata Cache之中,便于查找消息位于哪一个Data log之中。
5.内存中没有被处理的消息索引会以一定的周期为依据,同步到Metadata Store之中 即db.data文件 db.redo文件也会更新,以便节点重启后,对Metadata Cache进行恢复
3.用于磁盘上检索消息存储位置的Metatdata Store
4.用于恢复Btree的redo文件
第二种方案:关系型数据库存储方案
配置一定的文件,在AMQ的安装目录/lib下放置相关jar包,配置文件可放到jetty.xml 或者activemq.xml配置文件中
配置createTablesOnStartUp为true,保证mq第一次启动可以自行建表,后面可关闭
不能说性能最好,但是大多数选取方案,数据库有自己的热备和负载方案
第三种方案:LevelDB存储方案
处理十亿级别规模的Key-value型数据持久性存储的C++数据库
只能由本操作系统的其他进程进行调用,不具备网络性
基本结构:
核心设计算法:跳跃表
核心操作策略:对磁盘上的数据日志进行归并
结构:
-- Log文件:接受的新消息会同步到两个地方
内存中的MemTable区域
磁盘上的log文件:目的在于异常时恢复levelDB退出前的结构,采用预占方式写入,可设为异步,有数据丢失风险
log文件是顺序写,所以会预占100M(默认)磁盘空间
-- MemTable和Immutable:MemTable区域的数据结构就是跳跃表,当区域数量大于定值时,会被标记为Immutable,并开启新的Memtable区域,Immutable数据会被剔除掉标记已删除(消费)的数据,写入到磁盘的.sst文件中
-- SSTable文件
磁盘上最重要的数据记录文件,每个大小默认2M,按照数据的key排序随机写,不需要预占磁盘存储空间
由多个Block块构成,是levelDB读写磁盘的最小单元,最后一个block称为Index block,用来指明每一个Data block的起始位置
在levelDB的内存区域,有一个block Cache的内存区域,该区域存储众多的Index Block
-- Mainfest:
该文件记录了sst文件的关键信息,便于在sst中查找某条消息
方案的选择:
KahaDB和 levelDB采用内存存索引 + 磁盘存消息
关系型数据库为:AMQ对表的操作进行存储和修改
根据多种条件进行选择,并非所谓的越快越好
ActiveMQ集群方案
1.高可用:最终减少整个ActiveMQ停止服务的时间
2.高性能:更大的消息吞吐量,更快的处理时间,更稳定的客户连接
3.动态集群:同时提供消息服务的ActiveMQ节点数量,位置(IP和端口)是不固定的。 以网络组播的方式通知其他节点,其他节点收到后,发起连接,加入到集群之中。
-- 基于组播的节点发现
基于组播的ActiveMQ负载均衡模式的配置:动态网络连接Newwork Connections
--- 按照一定的周期,向组播地址发送UDP数据报,以便被感知
--- 每个UDP的数据报中,包含本节点ActiveMQ的版本信息,连接自己的host名字,协议名和端口信息。
--- 任何一个服务节点A连接其他的服务节点,都需要当前节点A已经公布的transportConnection连接端口
--- 配置networkConnector: multicast://[组播地址][:端口]
--- 配置 transportConnector : discoverUri=“multicast://239.0.0.5”
-- 桥接NetWork Bridges
只有tcp头的uri格式(openwire)能够被用于NetWork bridges连接
4.静态集群:位置是固定的。启动时按照给定的位置进行连接
只更改networkConnectors标签的配置即可
每一个节点都要配置其他所有节点的连接位置,如果有四个,则一个需要配置其他的三个,使用“,”进行隔开
本篇博客是针对于一位大神的博客系列文章的学习总结
具体详解见大神博客@说好不打脸
附上自己个人学习总结所整理的思维导图:
百度云盘:ActiveMQ 提取码:qdrz
思维导图软件:XMind8 update7
破解版安装博客推荐:Xmind8 破解版安装
本文章系博主原创,尊重博主辛劳成果,转载请注明出处,谢谢。