Apache ActiveMQ Artemis 附带两种持久化选项。文件日志,高度优化消息传递用例,并提供出色的性能,以及 JDBC 存储,它使用 JDBC 连接到您选择的数据库。
1. 文件日志(默认)
文件日志是 *仅追加* 的日志。它由磁盘上的一组文件组成。每个文件预先创建为固定大小,并最初填充有填充。当在服务器上执行操作时,例如添加消息、更新消息、删除消息,记录会被追加到日志中。当一个日志文件已满时,我们就会转到下一个文件。
由于记录只是追加的,即添加到日志的末尾,因此我们最大限度地减少了磁盘磁头移动,即我们最大限度地减少了随机访问操作,而随机访问操作通常是磁盘上最慢的操作。
使文件大小可配置意味着可以选择最佳大小,即使每个文件适合一个磁盘柱面。现代磁盘拓扑结构很复杂,我们无法控制文件映射到的柱面,因此这不是一项精确的科学。但通过最大限度地减少文件使用的磁盘柱面数量,我们可以最大限度地减少磁盘磁头移动量,因为整个磁盘柱面只需通过磁盘旋转即可访问 - 磁头不必移动。
当删除记录被添加到日志时,Apache ActiveMQ Artemis 具有一个复杂的垃圾回收算法,该算法可以确定是否还需要特定日志文件,即所有数据是否已在相同或其他文件中被删除。如果是,则可以回收并重新使用该文件。
Apache ActiveMQ Artemis 还具有一个压缩算法,该算法可以从日志中删除死空间并将数据压缩,以便它在磁盘上占用更少的空间。
如果需要,日志还完全支持事务操作,支持本地事务和 XA 事务。
日志的大部分是用 Java 编写的,但是我们将与实际文件系统的交互抽象出来,以允许不同的可插拔实现。Apache ActiveMQ Artemis 附带两种实现
1.1. 日志和数据保留
ActiveMQ Artemis 提供了一种存储和重播历史数据的方法。有关更多信息,请参阅数据保留章节。
1.3. Linux 异步 I/O
第二个实现使用一个薄的原生代码包装器与 Linux 异步 I/O 库 (AIO) 交谈。使用 AIO,Apache ActiveMQ Artemis 将在数据已写入磁盘时被回调,使我们能够完全避免显式同步,并在 AIO 通知我们数据已持久化时简单地发送完成确认。
使用 AIO 通常比使用 Java NIO 提供更好的性能。
此日志选项仅在运行 Linux 内核 2.6 或更高版本以及安装了 libaio(如果尚未安装)后可用。有关如何安装 libaio 的说明,请参见安装 AIO 部分。
此外,请注意 AIO 仅适用于以下文件系统:ext2、ext3、ext4、jfs、xfs 和 NFSV4。
有关 libaio 的更多信息,请参见lib AIO.
libaio 是内核项目的一部分。
1.4. 内存映射
第三个实现使用文件支持的 READ_WRITE 内存映射 针对 OS 页面缓存与文件系统进行交互。
这提供了极好的性能(尤其是在严格的进程故障持久性要求下),几乎为零的复制(实际上是内核页面缓存)和为零的垃圾(从 Java HEAP 的角度来看)操作,并在任何有 Java 4+ 运行时的平台上运行。
在断电故障持久性要求下,它的性能至少与 NIO 日志相当,唯一的例外是内核小于或等于 2.6 的 Linux 操作系统,其中确保持久写入所需的 msync) 实现不同(并且更慢)从 NIO 日志中使用 fsync。
它受益于 OS 巨型页面 的配置,特别是在使用大量日志文件并将它们的大小设置为 OS 页面大小(以字节为单位)的倍数时。
1.5. 标准文件
标准 Apache ActiveMQ Artemis 核心服务器使用日志的两个实例
-
绑定日志。
此日志用于存储与绑定相关的数据。其中包括在服务器上部署的一组队列及其属性。它还存储数据,例如 ID 序列计数器。
绑定日志始终是 NIO 日志,因为它通常与消息日志相比吞吐量较低。
此日志上的文件以
activemq-bindings为前缀。每个文件都有一个bindings扩展名。文件大小为1048576,它位于绑定文件夹中。 -
消息日志。
此日志实例存储所有与消息相关的数据,包括消息本身以及重复 ID 缓存。
默认情况下,Apache ActiveMQ Artemis 将尝试使用 AIO 日志。如果 AIO 不可用,例如平台不是 Linux,内核版本不正确,或者没有安装 AIO,那么它将自动回退到使用 Java NIO,Java NIO 在任何 Java 平台上都可用。
此日志上的文件以
activemq-data为前缀。每个文件都有一个amq扩展名。默认情况下,文件大小为10485760(可配置),它位于日志文件夹中。
对于大型消息,Apache ActiveMQ Artemis 将它们持久化到消息日志之外。这将在大型消息中讨论。
Apache ActiveMQ Artemis 还可以配置为在内存不足的情况下将消息分页到磁盘。这将在分页中讨论。
如果根本不需要持久化,Apache ActiveMQ Artemis 还可以配置为根本不将任何数据持久化到存储中,如配置代理以实现零持久化部分所述。
1.5.1. 配置绑定日志
使用 broker.xml 中的以下属性配置绑定日志
- bindings-directory
-
这是绑定日志所在的目录。默认值为
data/bindings。 - create-bindings-dir
-
如果将其设置为
true,则如果绑定目录在bindings-directory中指定的地址不存在,则该目录将被自动创建。默认值为true
1.5.2. 配置 JMS 日志
JMS 配置与其绑定日志共享其配置。
1.5.3. 配置消息日志
使用 broker.xml 中的以下属性配置消息日志
- journal-directory
-
这是消息日志所在的目录。默认值为
data/journal。为了获得最佳性能,我们建议日志位于自己的物理卷上,以最大限度地减少磁盘磁头移动。如果日志位于与可能正在写入其他文件的其他进程共享的卷上(例如绑定日志、数据库或事务协调器),则磁盘磁头很可能会在写入这些文件时快速移动,从而极大地降低性能。
当消息日志存储在 SAN 上时,我们建议存储在 SAN 上的每个日志实例都被赋予自己的 LUN(逻辑单元)。
- node-manager-lock-directory
-
这是节点管理器文件锁所在的目录。默认情况下,它与
journal-directory的值相同。当消息日志位于 SAN 上,并使用共享存储 HA策略,且代理实例位于同一台物理机上时,这很有用。
- create-journal-dir
-
如果将其设置为
true,则如果日志目录在journal-directory中指定的地址不存在,则该目录将被自动创建。默认值为true - journal-type
-
有效值为
NIO、ASYNCIO或MAPPED。选择
NIO将选择 Java NIO 日志。选择ASYNCIO将选择 Linux 异步 I/O 日志。如果您选择ASYNCIO,但没有运行 Linux 或没有安装 libaio,则 Apache ActiveMQ Artemis 将检测到这一点,并自动回退到使用NIO。选择MAPPED将选择 Java 内存映射日志。 - journal-sync-transactional
-
如果将其设置为 true,则 Apache ActiveMQ Artemis 将确保所有事务数据在事务边界(提交、准备和回滚)上被刷新到磁盘。默认值为
true。 - journal-sync-non-transactional
-
如果将其设置为 true,则 Apache ActiveMQ Artemis 将确保非事务性消息数据(发送和确认)每次都被刷新到磁盘。此参数的默认值为
true。 - journal-file-size
-
每个日志文件的大小(以字节为单位)。此参数的默认值为
10485760字节 (10MiB)。 - journal-min-files
-
日志将维护的最小文件数。当 Apache ActiveMQ Artemis 启动且没有初始消息数据时,Apache ActiveMQ Artemis 将预先创建
journal-min-files个文件。创建日志文件并用填充填充它们是一项相当昂贵的操作,我们希望最大限度地减少在运行时执行此操作,因为文件会填满。通过预先创建文件,当一个文件填满时,日志可以立即继续使用下一个文件,而无需暂停来创建它。
根据您预计队列在稳定状态下包含的数据量,您应该调整此文件数量以匹配该总数据量。
- journal-pool-files
-
系统将创建尽可能多的文件,但是当回收文件时,它将缩减回
journal-pool-files。此参数的默认值为 -1,这意味着一旦创建,它将永远不会删除日志上的文件。
请注意,系统不能无限增长,因为您仍然需要为可以无限增长的目标使用分页。
请注意:如果您得到太多文件,您可以使用压缩。
- journal-max-io
-
写入请求在被提交到系统执行之前会被排队。此参数控制 I/O 队列中可以存在的最大写入请求数。如果队列已满,则写入将阻塞,直到释放空间。
使用 NIO 时,此值应始终等于
1使用 ASYNCIO 时,默认值应为
500。系统根据它是 NIO 还是 ASYNCIO 为此参数维护不同的默认值(NIO 的默认值为 1,ASYNCIO 的默认值为 500)
有一个限制,总的最大 ASYNCIO 不能高于在 OS 级别配置的值(/proc/sys/fs/aio-max-nr),通常为 65536。
- journal-buffer-timeout
-
与每次写入都进行刷写不同,我们维护一个内部缓冲区,并在缓冲区满或超时时刷写整个缓冲区,以先发生者为准。这适用于 NIO 和 ASYNCIO,并允许系统在需要刷写的许多并发写入情况下更好地扩展。
此参数控制缓冲区在未填满的情况下刷写的超时时间。ASYNCIO 通常比 NIO 可以承受更高的刷写速率,因此系统对 NIO 和 ASYNCIO 维护不同的默认值(NIO 的默认值为 3333333 纳秒 - 每秒 300 次,ASYNCIO 的默认值为 500000 纳秒 - 即每秒 2000 次)。
将此属性设置为 0 将禁用内部缓冲区,写入将立即直接写入日志文件。
通过增加超时时间,您可能能够以延迟为代价提高系统吞吐量,默认参数的选择是在吞吐量和延迟之间取得合理平衡。
- journal-buffer-size
-
ASYNCIO 上的定时缓冲区大小。默认值为
490KiB。 - journal-compact-min-files
-
在我们能够考虑压缩日志之前,文件的最小数量。压缩算法只有在您至少有
journal-compact-min-files个文件时才会开始。将其设置为 0 将完全禁用压缩功能。但这可能很危险,因为日志可能会无限增长。明智地使用它!
此参数的默认值为
10。 - journal-compact-percentage
-
启动压缩的阈值。当日志空间中小于此百分比的区域被视为活动数据时,我们将开始压缩。还要注意,只有在日志上至少有
journal-compact-min-files个数据文件时,压缩才会开始。此参数的默认值为
30。 - journal-lock-acquisition-timeout
-
在放弃之前,等待(以毫秒为单位)获取日志文件锁的时间。
此参数的默认值为
-1(即无限时间)。 - journal-datasync
-
这将禁用在日志写入时使用 fdatasync。启用此选项可确保完全断电持久性,否则在日志写入时会确保进程故障持久性(操作系统保证)。这对
NIO和MAPPED日志特别有效,这些日志依赖于 fsync/msync 来强制将写入更改写入磁盘。默认值为
true。
1.6. 安装 AIO
Java NIO 日志提供了出色的性能,但如果您使用的是 Linux 内核 2.6 或更高版本的 Apache ActiveMQ Artemis,我们强烈建议您使用 ASYNCIO 日志以获得最佳的持久性性能。
在其他操作系统或更早版本的 Linux 内核下,无法使用 ASYNCIO 日志。
如果您运行的是 Linux 内核 2.6 或更高版本,并且尚未安装 libaio,则可以使用以下步骤轻松安装它。
使用 yum(例如,在 Fedora 或 Red Hat Enterprise Linux 上)
yum install libaio
使用 aptitude(例如,在 Ubuntu 或 Debian 系统上)
apt-get install libaio
2. JDBC 持久性
Apache ActiveMQ Artemis JDBC 持久性层提供了使用数据库存储代理状态(消息、地址和队列定义等)的功能。
|
使用 ActiveMQ Artemis 文件日志是推荐的配置,因为它提供了更高水平的性能并且更加成熟。JDBC 在分页和大型消息方面的性能尤其降低。JDBC 持久性层面向必须使用数据库的用户,例如,由于公司内部政策。 |
ActiveMQ Artemis 目前支持有限数量的数据库供应商。
-
PostgreSQL
-
MySQL
-
Microsoft SQL Server
-
Oracle
-
DB2
-
Apache Derby
JDBC 存储使用 JDBC 连接将消息和绑定数据存储在数据库表中的记录中。存储在数据库表中的数据使用 Apache ActiveMQ Artemis 内部编码进行编码。
2.1. 配置 JDBC 持久性
要将 Apache ActiveMQ Artemis 配置为使用数据库来持久化消息和绑定数据,您必须执行以下两项操作。
-
有关如何使 JDBC 驱动程序对代理可用的信息,请参阅有关添加运行时依赖项的文档。
-
在您的
<core>元素下的 broker.xml 配置文件中创建一个 store 元素。例如
<store>
<database-store>
<jdbc-driver-class-name>org.apache.derby.jdbc.EmbeddedDriver</jdbc-driver-class-name>
<jdbc-connection-url>jdbc:derby:data/derby/database-store;create=true</jdbc-connection-url>
<bindings-table-name>BINDINGS_TABLE</bindings-table-name>
<message-table-name>MESSAGE_TABLE</message-table-name>
<page-store-table-name>MESSAGE_TABLE</page-store-table-name>
<large-message-table-name>LARGE_MESSAGES_TABLE</large-message-table-name>
<node-manager-store-table-name>NODE_MANAGER_TABLE</node-manager-store-table-name>
</database-store>
</store>
- jdbc-connection-url
-
您的数据库服务器的完整 JDBC 连接 URL。连接 URL 应包含所有配置参数和数据库名称。
使用 XML 配置文件配置服务器时,请确保转义任何非法字符;例如,“&” 是 JDBC 连接 URL 中的典型字符,应将其转义为 "&"。 - bindings-table-name
-
将为 ActiveMQ Artemis 服务器持久化绑定数据的表的名称。指定表名允许用户在多个服务器之间共享单个数据库,而不会相互干扰。
- message-table-name
-
将为 ActiveMQ Artemis 服务器持久化绑定数据的表的名称。指定表名允许用户在多个服务器之间共享单个数据库,而不会相互干扰。
- large-message-table-name
-
将为 ActiveMQ Artemis 服务器持久化消息和相关数据的表的名称。指定表名允许用户在多个服务器之间共享单个数据库,而不会相互干扰。
- page-store-table-name
-
用于存放页面存储目录信息的表的名称。请注意,每个地址都有自己的页面表,该表将使用此名称附加一个最多 20 个字符的唯一 ID。
- node-manager-store-table-name
-
将为 ActiveMQ Artemis 服务器持久化 HA 共享存储锁(即主和备用)和 HA 相关数据的表的名称。指定表名允许用户在多个服务器之间共享单个数据库,而不会相互干扰。每个共享存储主/备用对必须使用相同的表名,并且不支持在多个(且无关)主/备用对之间共享相同的表。
- jdbc-driver-class-name
-
所需数据库驱动程序的全限定类名。
- jdbc-network-timeout
-
以毫秒为单位的 JDBC 网络连接超时时间。默认值为 20000 毫秒(即 20 秒)。使用共享存储时,建议将其设置为小于或等于
jdbc-lock-expiration。 - jdbc-lock-renew-period
-
JDBC 锁的保持活动服务的周期,以毫秒为单位。默认值为 2000 毫秒(即 2 秒)。
- jdbc-lock-expiration
-
JDBC 锁在保持活动状态的情况下被视为有效的时长,以毫秒为单位。默认值为 20000 毫秒(即 20 秒)。
- jdbc-journal-sync-period
-
日志与 JDBC 同步的时长,以毫秒为单位。默认值为 5 毫秒。
- jdbc-allowed-time-diff
-
在更新和验证主锁和备用锁时,请求数据库当前时间时,代理和数据库之间允许的最大时间偏移量,以毫秒为单位。当前,此值只影响日志记录,如果检测到的差异超过限制,则会显示警告。默认值为 250 毫秒。
- jdbc-max-page-size-bytes
-
页面可以使用的最大尺寸。默认值和推荐的最大值为 100K 字节。使用更大的尺寸会导致下载大型 Blob,这会影响使用分页消息时的性能。
| 某些 DBMS(例如 Oracle,30 个字符)对表名的尺寸有限制,在为 Artemis 数据库存储配置表名时应考虑这一点,特别是注意页面存储表名,它可以附加一个最多 20 个字符的唯一 ID。(对于 Oracle,这意味着配置最大尺寸为 10 个字符的 page-store-table-name)。 |
如果需要对用户和密码进行编码,也可以显式添加它们,而不是在 JDBC URL 中添加它们,这将类似于
<store>
<database-store>
<jdbc-driver-class-name>org.apache.derby.jdbc.EmbeddedDriver</jdbc-driver-class-name>
<jdbc-connection-url>jdbc:derby:data/derby/database-store;create=true</jdbc-connection-url>
<jdbc-user>ENC(dasfn353cewc)</jdbc-user>
<jdbc-password>ENC(ucwiurfjtew345)</jdbc-password>
<bindings-table-name>BINDINGS_TABLE</bindings-table-name>
<message-table-name>MESSAGE_TABLE</message-table-name>
<page-store-table-name>MESSAGE_TABLE</page-store-table-name>
<large-message-table-name>LARGE_MESSAGES_TABLE</large-message-table-name>
<node-manager-store-table-name>NODE_MANAGER_TABLE</node-manager-store-table-name>
<jdbc-page-max-size-bytes>100K</jdbc-page-max-size-bytes>
</database-store>
</store>
2.2. 配置 JDBC 连接池
要将 Apache ActiveMQ Artemis 配置为使用带有 JDBC 连接池的数据库,您需要设置数据源属性,例如
<store>
<database-store>
<data-source-properties>
<data-source-property key="driverClassName" value="com.mysql.jdbc.Driver" />
<data-source-property key="url" value="jdbc:mysql://:3306/artemis" />
<data-source-property key="username" value="artemis" />
<data-source-property key="password" value="artemis" />
<data-source-property key="poolPreparedStatements" value="true" />
</data-source-properties>
<bindings-table-name>BINDINGS</bindings-table-name>
<message-table-name>MESSAGES</message-table-name>
<large-message-table-name>LARGE_MESSAGES</large-message-table-name>
<page-store-table-name>PAGE_STORE</page-store-table-name>
<node-manager-store-table-name>NODE_MANAGER_STORE</node-manager-store-table-name>
</database-store>
</store>
您可以在 https://commons.apache.org/proper/commons-dbcp/configuration.html 上找到数据源属性的文档。
要掩盖属性的值,可以使用与掩盖密码相同的步骤。
请注意,重新连接只有在没有客户端发送消息时才有效。相反,如果在重新连接期间尝试写入日志的表,则代理将快速失败并关闭。
3. 零持久性
在某些情况下,消息系统有时需要零持久性。将 Apache ActiveMQ Artemis 配置为执行零持久性很简单。只需在 broker.xml 中将参数 persistence-enabled 设置为 false 即可。
请注意,如果将此参数设置为 false,则将发生零持久性。这意味着不会持久化任何绑定数据、消息数据、大型消息数据、重复 ID 缓存或分页数据。