代码编织梦想

1.1 简介

1.1.1 概述

  为了避免意外宕机以后丢失信息,需要做到重启后可以恢复消息队列,消息系统一般都会采用持久化机制。ActiveMQ 的消息持久化机制有 JDBC,AMQ,KahaDB 和 LevelDB,无论使用哪种持久化方式,消息的存储逻辑都是一致的。就是在发送者将消息发送出去后,消息中心首先将消息存储到本地数据文件、内存数据库或者远程数据库等再试图将消息发送给接收者,成功则将消息从存储中删除,失败则继续尝试发送。消息中心启动以后首先要检查指定的存储位置,如果有未发送成功的消息,则需要把消息发送出去。

1.1.2 配置文件

在这里插入图片描述





1.2 持久化方式

1.2.1 AMQ【了解】

☞ 概述

  AMQ 是一种文件存储形式,它具有写入速度快和容易恢复的特点。消息存储在一个个文件中,文件的默认大小为 32M,当一个存储文件中的消息已经全部被消费,那么这个文件将被标识为可删除,在下一个清除阶段,这个文件被删除。AMQ 适用于 ActiveMQ 5.3 之前的版本,主要的缺点是 AMQ Message 会为每一个 Destination 创建一个索引,如果使用了大量的 Queue,索引文件的大小会占用很多磁盘空间。而且由于索引巨大,一旦 Broker 崩溃,重建索引的速度会非常慢。

☞ 配置

<persistenceAdapter>
     <amqPersistenceAdapter directory="${activemq.data}/activemq-data" maxFileLength="32mb"/>
</persistenceAdapter>

1.2.2 KahaDB【默认】

☞ 概述

  KahaDB 是从 ActiveMQ 5.4 开始默认的持久化存储方式,可用于任何场景,提高了性能和恢复能力。消息存储使用一个事务日志和仅仅用一个索引文件来存储它所有的地址。KahaDB 是一个专门针对消息持久化的解决方案,它对典型的消息使用模式进行了优化。数据被追加到 data logs 中。当不再需要 log 文件中的数据的时候,log 文件会被丢弃。

☞ 存储原理

Kahadb 在消息保存目录中只有 4类文件和一个 lock,跟 ActiveMQ 的其他几种文件存储引擎相比这就非常简洁了。
 ♞ db-<Number>.log:KahaDB 存储消息到预定义大小的数据记录文件中,文件命名为 db-xxx.log。当数据文件已满时,一个新的文件会随之创建,number 数值也会随之递增,它随着消息数量的增多,如每 32M 一个文件,文件名按照数字进行编号,如 db-1.log、db-2.log、db-3.log ···。当不再有引用到数据文件中的任何消息时,文件会被删除或归档。
 ♞ db.data:该文件包含了持久化的 B-Tree 索引,索引了消息数据记录中的消息,它是消息的索引文件,本质上是 B-Tree(B树),使用 B-Tree 作为索引指向 db-xxx.log 里面存储的消息。
 ♞ db.free:当前 db.data 文件里哪些页面是空闲的,文件具体内容是所有空闲页的 ID
 ♞ db.redo:用来进行消息恢复,如果 KahaDB 消息存储在强制退出后启动,用于恢复 B-Tree 索引。
 ♞ lock:文件锁,表示当前获得 KahaDB 读写权限的 broker。
在这里插入图片描述


☞ 配置文件

<persistenceAdapter>
	<!-- directory: 指定持久化消息的存储目录; journalMaxFileLength: 指定保存消息的日志文件大小 -->
    <kahaDB directory="${activemq.data}/activemq-data" journalMaxFileLength="16mb"/>
</persistenceAdapter>

1.2.3 LevelDB【了解】

☞ 概述

  这种文件系统是从 ActiveMQ 5.8 之后引进的,它和 KahaDB 非常相似,也是基于文件的本地数据库储存形式,但是它提供比 KahaDB 更快的持久性。但它不使用自定义 B-Tree 实现来索引预写日志,而是使用基于 LevelDB 的索引。目前默认的持久化方式仍然是 KahaDB,不过 LevelDB 持久化性能高于 KahaDB,可能是以后的趋势。

☞ 配置文件

<persistenceAdapter>
	<levelDB directory="activemq-data"/>
</persistenceAdapter>

1.2.4 JDBC

☞ 配置文件

<broker ···>
	···

	<persistenceAdapter> 
		<!--
			dataSource 指定将要引用的持久化数据库的 bean 名称,很显然我们还要添加一个 bean 配置数据源
			createTablesOnStartup 默认 true,MQ 启动的时候都重新创建数据表,一般首次设置为 true,之后设置为 false
		-->
		<jdbcPersistenceAdapter dataSource="#my-ds" createTablesOnStartup="false" /> 
	</persistenceAdapter>

	···
</broker>

<!-- 注意这个需要在 </broker> 之后,<import resource="jetty.xml"/> 之前配置 -->
<bean id="mysql-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true"/>
  <property name="username" value="activemq"/>
  <property name="password" value="activemq"/>
  <property name="poolPreparedStatements" value="true"/>
</bean>

☞ 添加 jar

  从配置文件可以看出我们使用了 MySQL,所以我们需要在 /lib 目录中添加 MySQL 驱动包,ActiveMQ 默认的数据库连接池是 dbcp,如果要更改也是需要将数据库连接池的 jar 包添加到库中。


☞ 数据库

  新建一个名为 activemq 的数据库,如果上述配置没有问题,启动时会自动创建三张表,其中 activemq_msgs 用于存储消息,Queue和Topic都存储在这个表中;activemq_acks 用于存储订阅关系。如果是持久化 Topic,订阅者和服务器的订阅关系在这个表保存;activemq_lock 在集群环境中才有用,只有一个 Broker 可以获得消息,称为 Master Broker,其他的只能作为备份等待 Master Broker 不可用,才可能成为下一个 Master Broker。这个表用于记录哪个 Broker 是当前的 Master Broker。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

☞ 编码及数据库情况

  注意编码时一定要加上 producer.setDeliveryMode(DeliveryMode.PERSISTENT); 开启持久化,才会保存到数据库中,否则保存到内存中。Queue 模式会将每一条消息保存到数据库 activemq_msgs 表中,等消息被消费者签收后会删除消息。Topic 模式中先启动消费者订阅,在启动生产者,可以在数据库 activemq_acks 表中看到订阅者,该模式的消息依旧会被保存到数据库 activemq_msgs 表中,但是消息被订阅者签收后不会从数据库中删除。

☞ 可能存在的问题

在配置关系型数据库作为 ActiveMQ 的持久化存储方案时,可能会出现以下问题
 ♞ 需要使用到的相关 jar 文件放置到 ActiveMQ 安装路径下的 lib 目录,否则会找不到 jar。
 ♞ 启动时报 java.lang.llegalStateException:BeanFactory not initialized or already closed 这是因为操作系统的机器名中有 _,修改机器名并且重启后即可解决问题。
 ♞ ActiveMQ 第一次启动完成后需要去掉 jdbcPersistenceAdapter 标签中 createTablesOnStartup 这个属性,或者更改为 false,否则会重新创建相关表。


1.2.5 JDBC With Journal

☞ 概述

  JDBC With Journal 克服了 JDBC Store 的不足,JDBC 每次消息过来,都需要去写库和读库。ActiveMQ Journal 使用高速缓存写入技术,大大提高了性能。当消费者的消费速度能够及时跟上生产者消息的生产速度时,Journal 文件能够大大减少需要写入到 DB 中的消息。使用 JDBC With Journal 后,发送出来的消息会在内存中告诉缓存,接收端若在没有接收情况下 7~10 分钟后再写入数据库,这样接收端就不用等到数据库操作完了之后再接收消息。举个例子,生产者生产了 1000 条消息,这 1000 条消息会保存到 Journal 文件,如果消费者的消费速度很快的情况下,在 Journal 文件还没有同步到 DB 之前,消费者已经消费了 90% 的以上的消息,那么这个时候只需要同步剩余的 10% 的消息到 DB。如果消费者的消费速度很慢,这个时候 Journal 文件可以使消息以批量方式写到 DB。

☞ 配置文件

<persistenceFactory>
	<journalPersistenceAdapterFactory
	        journalLogFiles="4"
	        journalLogFileSize="32768"
	        useJournal="true"
	        useQuickJournal="true"
	        dataSource="#mysql-ds"
	        dataDirectory="activemq-data"/>
</persistenceFactory>

<!-- 省略 mysql-ds bean -->



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/Demo_Null/article/details/110959018

mysql发生Lock wait timeout exceeded; try restarting transaction(解决备忘)-爱代码爱编程

Lock wait timeout exceeded; try restarting transaction 原因:超过锁等待超时;请尝试重新启动事务 解决方法:更改数据库的事务隔离级别。 首先我这个是用INSERT INTO SELECT 方法批量处理了两个表,进行数据转移,大概有42万条数据(业务需求),然后数据库报错 1205 - Loc

Freemark生成Word文件的加密处理-爱代码爱编程

Word文件加密处理 Word文件的加密处理具体实现 Word文件的加密处理 最近完成了一个使用freemark生成文档的需求。本次实现使用的是freemark模板技术。 具体实现 首先使用wps或者word编辑模板内容,然后把编辑好的模板文件另存为xml(可以把文件后缀名改成ftl也可以不做修改) 编辑生成文档工具类 package

浅析INSERT INTO SELECT用法及多数据源操作-爱代码爱编程

SQL INSERT INTO SELECT 语句 通过 SQL,您可以从一个表复制信息到另一个表。 INSERT INTO SELECT 语句从一个表复制数据,然后把数据插入到一个已存在的表中。 1,对于在一个数据库里面的数据。 INSERT INSERT user (id,`name`) select t_id,t_name FROM test_k

2020-12-10-爱代码爱编程

1 网络编程 1.1 网络协议 http协议的里程: http0.9版本:短链接、只支持GET请求、响应的数据格式只能是html的字符串 http1.0版本:短链接、可支持GET请求、POST请求,增加了状态码、响应的数据格式多元化(数字、字符串、图片、视频等) http1.1版本:长链接、可支持GET、POST、DELETE、PUT等

了解工厂模式-爱代码爱编程

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。 意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟

Java基础前言-爱代码爱编程

Java语言入门 1.1 Java语言概述1.2 计算机基础知识 1.1 Java语言概述 什么是Java语言 Java语言是美国Sun公司(Stanford University Network),在1995年推出的高级的编程语言。所谓编程语言,是计算机的语言,人们可以使用编程语言对计算机下达命令,让计算机完成人们需要的功能。 Java语

记一次内网渗透(ATT&CK第五个攻防靶场)-爱代码爱编程

记一次内网渗透(ATT&CK第五个攻防靶场) 靶场下载地址:download 渗透测试 拿到题目打开是一个thinkphp框架 测试thinkphp版本 找到此版本漏洞的poc 可以命令执行 http://192.168.199.206/?s=index/\think\app/invokefunction&function=cal

Node.js中exports 和 module.exports 的区别-爱代码爱编程

exports 和 module.exports 的区别 每个模块中都有一个 module 对象, module 对象中有一个 exports 对象 ,我们可以把需要导出的成员都挂载到 module.exports 接口对象中 也就是:moudle.exports.xxx = xxx 的方式, 但是每次都 moudle.exports.xxx = xxx

Python数据类型&运算符-爱代码爱编程

变量&Python数据类型&运算符 一、变量 1.变量 1.1. 概念 定义: 程序在运行的过程中,值可以随时发生改变 作用:存储数据,参与运算 1.2. 定义 定义格式:变量名 = 初始值 说明: ​ 变量名: 对于每一个变量,需要给他定义一个名称,定义的规则就是标识符的规则 ​ =: 赋值运算

iOS奇思妙想之使用block替代通知(二)-爱代码爱编程

前言 在之前的文章iOS奇思妙想之使用block替代通知(一)中,自己实现了通知功能。在之前的实现中,使用了Runtime进行动态绑定,虽然达到了最后的效果,但是也会增加耦合。 作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:196800191,加群密码:112233,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面

Java的TheadLocal使用-爱代码爱编程

很多时候,当我们需要存储线程私有变量或者要实现线程安全的变量时或者想减少线程资源竞争的时候,可以使用ThreadLocal来为每个线程存储对应的私有变量。但是,如果你使用不当,会有可能造成严重的问题,最容易出现的就是内存泄漏。今天以一个案例分析出发,给大家介绍一下TheadLocal的原理及使用TheadLocal时注意的事项。 案例介绍 出于公司代码

java类中的构造方法、成员方法、方法调用、方法格式相关介绍-爱代码爱编程

方法 1.方法的理解和语法格式: 解决某一件事的功能实现。方法,是一段代码块的封装,方法中的代码应围绕某一功能的实现来写,目标明确,逻辑清晰。方法的语法格式如下: 修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2,......){ 执行语句 1.方法的调用 2.变量的操作:声明 赋值 修改 3.程序结构:选择结构 循环结构………