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://127.0.0.1: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 缓存或分页数据。