Artemis拥有两种持久化方案,一种是使用针对消息持久化高度优化并且拥有出色性能的日志系统;另一种是JDBC存储,使用JDBC连接到数据库。JDBC存储还在开发中,可以使用日志功能(基本上除了分页和大消息外的所有场景)。
1.日志文件
日志文件由磁盘上的一组文件组成。每个文件都是预先创建好并且固定大小并且最初是填充满的。当服务器上进行操作,如:增、删、改消息都将记入到日志,一个文件满后移到下一个日志文件。写日志方式为追加到日志末尾,可以最小化磁头移动。即最小化随机访问操作,这通常是磁盘上最慢的操作。
使用文件大小的配置也是选择最佳大小,也就是每个文件刚好在一个磁盘柱面上。由于现代磁盘拓扑很复杂,我们无法控制文件映射到哪个柱面上,但是可以通过使用文件时最小化使用磁盘柱面数量,从而我们可以最小化磁盘磁头移动,因为只需要通过磁盘旋转即可访问整个磁盘柱面-磁头不必移动。
当删除记录被添加到日志中,Artemis具有复杂文件垃圾收集算法,该算法用于确定是否还需要特定的日志文件。所有文件中的数据已经在相同或者其他文件中删除,如果这样,则可以回收并重新使用该文件。
Artemis还有压缩算法,可以从日志中删除废弃空间并且压缩数据,从而是其占用较少的磁盘空间。
如果需要日志还完全支持事务操作,支持本地和XA事务。
日志功能大部分内容用java编写,但是我们抽象出与实际文件系统的交互可以使用不同的可插入实现,Artemis附带如下实现:
- java NIO 第一个实现使用标准的Java NIO与文件系统交互,提供了非常好的性能可以在JDK 6+上运行。
- Linux AIO 第二个实现使用一个少量的本地代码包装器与Linux异步IO库(AIO)进行通信,使用AIO当数据写入磁盘时,Artemis会接收到一个回调,可以避免显式同步,当AIO在数据被持久化是通过简单的发送回调来通知我们。使用AIO通常会提供比Java NIO更好的性能。Linux AIO选项仅支持运行在Linux 2.6以上内核中以及安装了libaio的系统。需注意AIO仅适用于如下文件系统:ext2、ext3、ext4、jfs、xfs和NFSV4。
- 内存映射(Memory mapped)第三种实现支持文件READ_WRITE的内存映射通过系统页面缓存来与文件系统进行交互。这提供了非常好的性能(特别是在严格的进程失败持久性的要求下)和零拷贝(实际上是内核的页面缓存)和零垃圾(通过Java heap视图而来)可以运行在任何安装了JDK 4+的平台上。它的性能至少与NIO日志相当。内存映射受益于系统大页面配置,特别是在大量的日志文件情况下和将调整日志文件大小为多个系统页面大小情况下。
2.文件标准
标准Artemis core服务器使用日志的两个实例:
绑定日志
日志用于存储绑定相关的数据。包括在服务器中的队列集及其属性,还存储id序列计数器等数据。绑定日志通常是使用NIO日志,与消息日志相比,其通常是低吞吐量的。
此日志文件前缀为activemq-bindings。每个文件都有一个bindings扩展名,文件大小为1048576,位于bindings文件夹中。
消息日志
此日志实例存储所有与消息相关的数据,包含消息本身和duplicate-id(副本id)缓存。
默认情况下Artemis尝试使用AIO日志,如果AIO不可用会自动回退到Java NIO。
此日志文件以activemq-data为前缀,每个文件都有一个amp扩展名,文件大小默认为10485760(可配置),位于日志文件夹中。
对应大型消息,Artemis会将其存储在消息日志之外。Artemis还可以配置在内存不足的情况下将消息分页到磁盘。在不需要持久化的情况下,Artemis可以配置不存储任何数据。
2.1 配置绑定日志
在broker.xml中配置。
bindings-directory:绑定日志文件存储的目录,默认为data/bindings.
create-bindings-dir:如果为true,将会自动创建bindings-diredtory目录(如果该目录不存在),默认为true。
2.2 配置jms日志
绑定日志的配置与jms日志配置共享。
2.3 配置消息日志
在broker.xml中配置。
- journal-directory
存储消息日志文件的目录,默认为data/journal。
为了获取最佳性能,建议将日志存放在自身的物理卷上,最大限度的减少磁头移动。如果日志位置与其他可能正在编写文件(例如绑定日志,数据库或者事务协调器)的其他进程共享的物理卷上,那么磁盘头可能会在这些文件写入时快速的在这些文件之间快速移动,从而大大降低性能。
当消息日志存储在SAN上时,建议为SAN上存储的每个日志实例提供自己的LUN(逻辑单元)。
- create-journal-dir
如果设置为true,将会自动创建bindings-diredtory目录(如果该目录不存在),默认为true。
- journal-type
有效值为NIO、ASYNCIO、MAPPED。
选择NIO会使用Java NIO,选择ASYNCIO会使用AIO,使用MAPPED会使用java memory mapped。
- journal-sync-transactional
如果设置为true,这Artemis将确保在事务边界(提交,准备和回滚)上将所有事务数据刷写到磁盘上。默认为true。
- journal-sync-non-transactional
如果设置为true,Artemis将确保无事务消息(发送和确认)每次都刷写到到磁盘。默认为true。
- journal-file-size
设置每个日志文件的大小(单位bytes)。默认值为10485760bytes(10MiB)
- journal-min-files
日志最小维护文件数量,当Artemis启动并且没有初始化消息数据时,Artemis将预先创建的文件数。
创建数据文件并且填充他们是一项非常昂贵的操作。如果希望在运行时文件写满尽量减少重新创建文件操作,可以通过预先创建文件,日志文件在写满后可以直接使用下一个文件,而不是暂停去创建日志文件。可以根据数据量来调整预创建文件数量。
- journal-pool-files
系统会根据需要创建尽可能多的文件,但是在回收文件时会被缩小到此配置设置的文件数。
此参数默认值为-1,表示日志文件一旦创建,它将永远不会被删除。系统无法无限增长,因为仍然需要对可以无限增长的目标使用分页。
注意,如果文件太多可以使用压缩。
- journal-max-io
写入请求在提交给系统之前进行排队。此参数控制在任何时候IO队列中允许的最大写入请求数。如果队列变满将阻塞写入,直到空间被释放。
当使用NIO时,这个值始终为1,使用AIO时默认值为500。
这个配置,最大值不能高于系统级别的配置(/proc/sys/fs/aio-max-nr),通常为65536。
- journal-buffer-timeout
数据的刷写并不是在每次写入的时候进行,Artemis维护了一个内部缓冲区,只有在整个缓冲区已满或者超时到期(无论这个缓冲区中那条数据超时)才会刷写整个缓冲区。
如果缓冲区尚未填满,此参数控制缓冲区的超时时间。AIO通常可以应对比NIO更高的刷写频率。因此对于NIO和AIO有不同默认值(NIO为3333333纳秒-即每秒300次,AIO默认值为500000纳秒-即每秒2000次)。
注意:如果增加超时,是以延迟为代价提高系统吞吐量,选择默认参数以在吞吐量和延迟之间提高合理的平衡。在创建Artemis实例时,程序会检测磁盘IO来设定一个默认值。
- journal-buffer-size
定义AIO的定时缓冲区大小,默认值为490KiB。
- journal-compact-min-files
此参数定义在考虑压缩数据之前的最小文件数。压缩至少达到此配置定义的值时才会启动。
设置为0表示完全禁用压缩功能,这可能是危险,因为日志文件可以无限增长。最好启用它。默认值为10。
- journal-compact-percentage
设置开始压缩的阀值。但实时数据低于此百分比时,开始进行压缩。需注意在日志文件数量少于journal-compact-min-files配置数量之前,压缩不会启动。
此配置默认值为30.
- journal-datasync(默认为true)
此配置是否禁用在日志写入时使用fdatasync。启用这个配置,它可以确保断电时的持久化完整性,关闭此配置可能会在断电时造成持久化的失败。这个配置对NIO和MAPPED日志特别有效,它们依靠fsync/msync强制写入磁盘变更。
禁用journal-datasync需注意:在现代操作系统中都保证在进程失败(即崩溃)时,页面缓存所有未提交的更改都会刷新到文件系统中,从而保持后续操作相同页面的数据一致性,确保不丢失任何数据。在禁用journal-datasync情况下,数据刷写时间的可预测性取决于系统配置,不会损坏(或放松)如上进程失败的定义。但是依靠系统页面缓存,在系统断电时就无法保证了,可是提高了日志操作的效率,能够利用操作系统内核页面缓存子系统提高的读取缓存和写入组合功能。
禁止磁盘写缓存的注意事项:大多数情况下磁盘包括硬件都有写缓存。写缓存可以提高磁盘性能,因为写入只是加入磁盘缓存并且会延迟写入磁盘。
磁盘写缓存发生无关于是否在操作系统上执行fsync()还是从java程序内部执行正确的同步数据,它是系统及的配置。默认情况下,许多操作系统都启用了磁盘写缓存,此意味着即使在操作系统同步数据执行之后也无法保证数据实际上已将其存储到磁盘,如果发生故障关键数据可能会丢失。
一些昂贵的磁盘具备非易失性或支持的写缓存,在发生故障是不一定丢失数据但是需要测试他们。如果没有上述设备,且磁盘不属于某种亢余阵列(例如RAID),如果非常重视数据的完整性,则需要确保禁用磁盘写缓存。需要住的是禁用了磁盘写缓存会大大降低写性能。
在Linux上可以使用工具hdparm(适用于IDE磁盘)或sdparm或sginfo(适用于SDSI/SATA磁盘)检查和更改磁盘的写缓存设置。
3.安装AIO
如果在Linux 2.6+内核的系统上运行Artemis,强烈建议使用AIO,使用AIO要依赖libaio库,如果系统中没有安装此库使用如下命令安装:
使用yum:
yum install libaio
使用apt-get:
apt-get install libaio
4.JDBC持久化
JDBC持久化存储功能还在开发中,目前支持如下数据库:
PostgreSQL 9.4.x
MySQL 5.7.x.
Apache Derby 10.11.1.1
对应配置例子如下:
<store>
<database-store>
<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>
<jdbc-driver-class-name>org.apache.derby.jdbc.EmbeddedDriver</jdbc-driver-class-name>
</database-store>
</store>
5.非持久化
当要使用非持久化时,只需要在broker.xml中将参数persistence-enable设置为false。使用非持久化将不会持久化绑定数据、消息数据、大型消息数据、副本ID缓存或者分页数据。
注:此系列文章为Apache Artemis V2.6.2官方使用文档的简要翻译文档(非完全按照官方文档排版进行翻译,有删减),个人能力有限如有错误请谅解。源文档地址:http://activemq.apache.org/artemis/docs/latest/index.html