Artemis是基于java语言实现并且100%开源的消息中间件,该系统采用netty的非堵塞IO架构,拥有出色的性能。性能方面,消息日志保证持久化消息可以像非持久化消息一样拥有出色的表现。灵活的集群可以通过不可靠的全球网络创建地理上分布的集群。同时, Artemis支持自动故障转移功能,在实时系统服务器故障时会话会自动重新连接到备份服务器。
不同于基于远程过程调用(RPC)模式的消息系统,Artemis是一个异步消息系统,请求和响应之间解耦,消息发送者和消息消费者分离,将整个异构应用系统松散的耦合在一起,同时可以提供可靠性、事务和其他许多功能。同时,异步系统可以最大限度的利用硬件资源,减少IO堵塞线程数量,很好的利用网络带宽资源。
总之,Artemis是一个基于java的开源的消息中间件,是集多消息协议、高性能、高可用、集群可扩展的异步消息系统。
系统主要结构如下:
图表 1 Artemis系统图
Artemis系统是基于CLI命令行来完成动作的执行,其支持的命令包括create、run和stop等。本章主要介绍基于CLI命令的执行流程。
涉及到Artemis命令执行的组件图如下:
图表 2 执行命令的组件图
其中:
下面主要对run命令的执行流程进行拆解。
图表 3 Run命令执行流程1
启机步骤描述如下:
1. 执行./artemis run命令后,将启动Artemis-Boot模块中的Artemis类,执行main方法,该方法主要获取artemis安装路径和实例路径,并调用execute方法。
2.Artemis类的excetoer主要是负责获取artemis安装路径和实例路径下的库文件名称,并新建一个类加载器,加载所有库文件,最后加载Artemis-CLI模块中的Artemis类,并反射调用该类的execute方法,执行命令的具体流程。
3. Artemis-CLI模块Artemis类的execute方法将调用internalExecute方法执行命令的具体流程:
3.1 实例化CLI:(每个命令的具体使用方法)
3.2 用上述构建的CLI实例,将启动时的命令转换成对应的Action对象,并设置artemis安装实例和创建实例路径(Artemis启动命令对应的Action是Run类)
4. Run命令的具体实现流程
4.1 根据management.xml配置文件中的配置创建对应的实例managementContext
4.2 打印artemis启动时的logo
4.3 根据bootstrap.xml配置文件创建对象实例
4.4 创建通用的鉴权实例对象,原生代码的鉴权对象是“ActiveMQJAASSecurityManager”,根据项目需要,新增加WSRTC鉴权“ActiveMQWSSecurityManager”,该版本兼容旧版本的鉴权
4.5 根据鉴权对象和broker.xml的路径对象,创建FileBroker服务对象
4.6 启动managementContext,事实上并不是通过该实例对象启动JMX功能
4.7 启动FileBroker,详细流程如下:
4.8 创建并启动队列TTl管理服务,用于定时删除消息队列。(项目需求,之所以放在Artemis-CLI模块中实例化,是为了避免循环依赖,有待确认)
4.9 将bootstrap.xml配置中
图表 4 Run命令执行流程2
ActiveMQServerImp初始化时,只需要记录broker.xml配置信息的FileConfiguration、MBeanServer和鉴权管理服务SecurityManager。初始化流程如下:
基于上述初始化,ActiveMQServerImp的启动流程如下:
1. 解析配置参数和运行的环境变量
2. 初始化线程池,包括
3. 初始化临界检验服务,用于周期性检测对象的存活情况
4. 初始化系统高可用的服务角色对象,默认采用LiveOnlyPolicy,即当前启动的就是活动服务机,并且没有备机,因此并没有故障转移功能。
5. 操作上下文服务清除所有上下文对象(OperationContextImpl)
6. 消息日志目录创建(配置路径,并且配置持久化),如果以创建则忽略。
7. 创建节点管理器(NodeManager)并启动,如果是非持久化,则是InVmNodeManager,默认采用文件格式也即FileNodeManager。
8. 激活并启动高可用角色服务(具体流程见下图与描述)
9. 创建并启动连接服务(ConnectorService),事实上该步骤没有实现什么操作。
高可用服务liveOnlyActivation的启机流程:
1. 首先调用ActiveMQServerImpl的initialisePart1方法,完成各个管理器的初始化和启动流程
1.1 设置持久化Journal的方式:如果配置是AsynNIO异步方式,但是系统不支持(比如没安装libao),则回退到NIO方式。
1.2 初始化管理服务器(ManagementService)(作用)
1.3 启动内存监管理器(MemoryManager),定时采集内存(总内存、可用内存、已使用内存等)并以debug的形式打印到日志,如果可用内存百分率低于配置值,则打印Error日志告警。(该功能生产环境并没有配置)
1.4 激活回调服务,实际上截止目前还没有待回调的服务。
1.5 创建存储管理服务器(StoreManager):
1.6 创建认证存储服务器(SecurityStoreImpl),并将该对象注册到SecurityRepository中。该认证服务器封装了鉴权管理服务SecurityManager,实现解耦。
1.7 创建队列工厂服务器(QueueFactoryImpl),用于创建或删除队列。
1.8 创建分页管理服务器(PagingManagerImpl),用于消息的分页管理,并将该对象注册到addressSettingsRepository中。
1.9 创建资源管理服务器(ResourceManagerImpl),用于管理事务资源,定时清理超时的事务
1.10 创建消息路由服务器(PostOfficeImpl),主要用于消息的路由分发
1.11 创建集群管理服务器(ClusterManager),负责集群、广播和网桥的管理和维护等。
1.12 创建备份管理服务器(BackupManager),针对每个集群连接创建,采用备端口更新集群信息。
1.13 部署集群管理服务器deploy():
1.14 创建远程连接管理器(RemotingServiceImpl),用于管理客户端连接。
1.15 调用ManagementService的registerServer方法创建消息服务控制管理器(ActiveMQServerControlImp),并将该对象注入到JMX。该消息服务控制管理器用于获取服务器的状态,包括队列、address等信息,并提供查询接口供Console使用
1.16 根据
1.17 存储管理器的启动流程
1.18 消息路由组件启动流程
1.19 分页管理服务启动流程
1.20 管理服务对象启动流程
1.21 资源管理对象启动流程
1.22 将配置文件中
1.23 声明配置文件重载管理服务,并配置回调处理器,每隔一段时间检查配置文件是否有更新,如果有更新,则重新加载。
1.24 注册broker插件,实际上没有配置任何插件
2. 注册激活服务的回调:激活节点服务器的状态,并将回调添加到ActiveMQServerImpl中。
3. 执行ActiveMQServerImpl的initialisePart2方法:
3.1 分页管理服务加载文件,过程同分页管理服务启动流程时一样
3.2 加载journal日志信息
3.3 创建清洁者(ServerInfo),并向调度线程池中添加一个任务,每个一段时间执行ServerInfo的dump方法,打印内存使用情况,前提是配置“server.dump.interval”字段。(生产环境没有配置)
3.4 部署预先定义的address,包括DLQ、expiryqueue等,并绑定订阅的该地址的队列
3.5 部署预先定义的队列queue,实际上broker没有预先配置队列。
3.6 根据config-delete-queues的配置对不在配置文件中的address和queue进行处理。该config-delete-queues的作用是当服务器重新加载配置时如何处理不在配置文件中的address和queue,处理策略有:OFF,在配置重新加载时不会删除;FORCE,在配置重新加载时会删除队列,即使消息仍然存在。默认是OFF
3.7 调用激活回调函数,所有激活服务必须在集群完全启机前执行完(原因待明确)
3.8 检查地址配置中潜在的OOM风险,如果加载完配置的地址和队列,内存超过了“global-max-size”,则打印日志告警。
3.9 部署预先定义的投递器。实际上没有配置。
3.10 启动remotingService。
3.11 启动集群管理器clusterService
3.11.1 启动BroadcastGroupImp
3.11.2 启动集群连接ClusterConnectionImpl
3.11.3 部署配置文件中的网桥信息,实际服务器上并没有该配置
3.11.4 启动StandaloneHAManager,设置状态为started,不过该类没做什么操作,应该是作者预留的类。
3.11.5 设置集群管理器的状态为started。
3.12 启动消息超时检测,向调度线程池中添加一个定时任务(默认是30s),检测流程查看postoffic的startExpiryScanner方法
3.13 向分页管理服务和存储管理服务注入磁盘监控器FileStoreMonitor,并启动FileStoreMonitor,启动流程也是向调度线程池中添加一个定时任务(定时disk-scan-period),如果存储空间大于配置数max-disk-usag,则打印日志告警(“AMQ222210: Storage usage is beyond max-disk-usage. System will start blocking producers.”)
4. 完成上述流程后,执行ActiveMQServerImpl的completeActivation()方法:
4.1 设置ActiveMQServerImpl的状态为started。
4.2 调用remotingService的startAcceptors()方法,启动netty服务端。
4.3 执行所有回调类的activationComplete方法,完成服务启动后的动作。