什么是消息持久化
在发送者将消息发送出去后,消息中心首先将消息存储到本地数据文件、内存数据库或者远程数据库等,而后试图将消息发送给接收者,发送成功则将消息从存储中删除,失败则继续尝试。
消息中心启动之后首先要检查制定的存储位置,若是有未发送成功的消息,则须要把消息发送出去。
ActiveMQ持久化方式
AMQ、KahaDB、JDBC、LevelDB。
AMQ
AMQ是一种文件存储形式,它具备写入速度快和容易恢复的特色。消息存储在一个个文件中,文件的默认大小为32M,若是一条消息的大小超过了32M,那么这个值必须设置大一点。当一个存储文件中的消息已经所有被消费,那么这个文件将被标识为可删除,在下一个清除阶段,这个文件被删除。AMQ适用于ActiveMQ5.3以前的版本。
KahaDB
KahaDB是基于
文件的本地数据库储存形式,虽然没有AMQ的速度快,可是它具备强扩展性,恢复的时间比AMQ短,从5.4版本以后KahaDB作为默认的持久化方式。
KahaDB是一种
可嵌入式的事务性的持久化机制
KahaDB,主要特性有:
一、日志形式存储消息。
二、消息索引以B-Tree结构存储,能够快速更新
三、彻底支持JMS事务
四、支持多种恢复机制
上图展现的是KahaDB的结构图。消息存储在
基于文件的数据日志中。若是消息发送成功,变
标记为可删除的。
系统会周期性的清除或者归档日志文件。
消息文件的位置索引存储在内存中,这样能快速定位到。按期将内存中的
消息索引保存到metadata store中,避免大量消息未发送时,消息索引占用过多内存空间。
Data logs
数据日志中保存着消息以及目的地、订阅、事务等相关信息。这些信息在日志文件中并未按照一个特定的格式来保存,因此就须要索引各种信息,以便能快速定位到。
Metadata cache
在
内存中保存日志文件中各种信息的索引,索引信息包含一个
MessageId与消息在日志文件中的偏移量的对应关系。
全部索引以B-Tree结构存在内存中,便于在一个有序的list上快速的查找,插入以及删除。内存中的消息索引会按期的保存到Metadata store中。具体时间周期能够设置checkpointInterval属性。理想状况下Metadata cache越大愈好,这样在定位消息的时候就不尽可能少的去Metadata store中获取索引了。实际能够参考db.data文件的大小来设置。indexCacheSize 即是设置缓存的大小。
Metadata store
在db.data文件中保存消息日志中
消息的元数据,也是以B-Tree结构存储的,定时从Metadata cache更新数据。同时,Metadata store中也会备份一些在消息日志中存在的信息,这样可让Broker实例快速启动。即使metadata store文件被破坏或者误删除了。broker能够读取Data logs恢复过来,只是速度会相对较慢些。
Metadata cache与Metadata store同步
KahaDB提供了两种触发同步设置
一、设定一个阀值,当Metadata cache与Metadata store中的索引不一样的数量达到这个阀值时,触发同步。indexWriteBatchSize
即是设置这个阀值。
二、设置一个时间周期,当时间周期到了后,无论Metadata cache与Metadata store是否不一样,都触发同步。
经过checkpointInterval设置一个时间周期。
一般为了达到更高的性能,会将indexWriteBatchSize值设置很大。只在到达checkpointInterval时间点时才同步。这样作的风险就是有可能在系统意外down机时丢失部分metadata信息。
JDBC
能够将消息存储到数据库中,例如:Mysql、SQL Server、Oracle、DB2。
dataSource指定持久化数据库的bean,createTablesOnStartup是否在启动的时候建立数据表,默认值是true,这样每次启动都会去建立数据表了,通常是第一次启动的时候设置为true,以后改为false。
LevelDB
这种文件系统是从ActiveMQ5.8以后引进的,它和KahaDB很是类似,也是基于
文件的本地数据库储存形式,可是它提供比KahaDB更快的持久性。
与KahaDB不一样的是,它
不是使用传统的B-树来实现对日志数据的提早写,而是使用基于索引的LevelDB。
与Kafka持久化对比
Kafka的存储布局很是简单。话题的每一个分区对应一个逻辑日志。物理上,一个日志为相同大小的一组分段文件。每次生产者发布消息到一个分区,代理就将消息追加到最后一个段文件中。当发布的消息数量达到设定值或者通过必定的时间后,段文件真正写入磁盘中。写入完成后,消息公开给消费者。
与传统的消息系统不一样,Kafka系统中存储的消息没有明确的消息Id。
消息经过
日志中的逻辑偏移量(只存储位置信息)来公开。这样就避免了维护配套密集寻址,用于映射消息ID到实际消息地址的随机存取索引结构的开销。消息ID是增量的,但不连续。要计算下一消息的ID,能够在其逻辑偏移的基础上加上当前消息的长度。
消费者始终从特定分区顺序地获取消息,若是消费者知道特定消息的偏移量,也就说明消费者已经消费了以前的全部消息。消费者向代理发出异步拉请求,准备字节缓冲区用于消费。每一个异步拉请求都包含要消费的消息偏移量。Kafka利用sendfile API高效地从代理的日志段文件中分发字节给消费者。