MetaQ安装与使用

1        基本简介

        Metamorphosis是淘宝开源的一个Java消息中间件。关于消息中间件,你应该听说过JMS规范,以及一些开源实现,如ActiveMQ和HornetQ等。Metamorphosis也是其中之一。

Metamorphosis的起源是我从对linkedin的开源MQ--现在转移到apache的kafka的学习开始的,这是一个设计很独特的MQ系统,它采用pull机制,而不是一般MQ的push模型,它大量利用了zookeeper做服务发现和offset存储,它的设计理念我非常欣赏并赞同,强烈建议你阅读一下它的设计文档,总体上说metamorphosis的设计跟它是完全一致的。但是为什么还需要meta呢?

 

简单概括下我重新写出meta的原因:

Kafka是scala写,我对scala不熟悉,并且kafka整个社区的发展太缓慢了。

有一些功能是kakfa没有实现,但是我们却需要:事务、多种offset存储、高可用方案(HA)等

Meta相对于kafka特有的一些功能:

文本协议设计,非常透明,支持类似memcached stats的协议来监控broker

纯Java实现,从通讯到存储,从client到server都是重新实现。

提供事务支持,包括本地事务和XA分布式事务

支持HA复制,包括异步复制和同步复制,保证消息的可靠性

支持异步发送消息

消费消息失败,支持本地恢复

多种offset存储支持,数据库、磁盘、zookeeper,可自定义实现

支持group commit,提升数据可靠性和吞吐量。

支持消息广播模式

一系列配套项目:python客户端、twitter storm的spout、tail4j等。

因此meta相比于kafka的提升是巨大的。meta在淘宝和支付宝都得到了广泛应用,现在每天支付宝每天经由meta路由的消息达到120亿,淘宝也有每天也有上亿的消息量。

Meta适合的应用:

日志传输,高吞吐量的日志传输本来就是kafka的强项

消息广播功能,如广播缓存配置失效。

数据的顺序同步功能,如mysql binlog复制

分布式环境下(broker,producer,consumer都为集群)的消息路由,对顺序和可靠性有极高要求的场景。

作为一般MQ来使用的其他功能

 

 

2       MetaQ架构设计

2.1  
 总体结构图

2.2    消息存储

消息中间件中消息堆积是很常见,这要求broker具有消息存储的能力,消息存储结构决定了消息的读写性能,对整体性能有很大影响,metaq是分布式的,多个borker可以为一个topic提供服务,一个topic下的消息分散存储在多个broker,它们是多对多关系

 

 

 

 

 

 

 

 

 

 

 

 

2.3  
逻辑分区

一个逻辑分区实际上是一组索引文件。一个topic在一个broker上可以有多个逻辑分区,默认为1,但可自由配置。为什么会有多个分区的情况?逻辑分区的作用不仅仅是通过索引提供快速定位消息的功能,它还跟整个metaq的集群有很大的关系

 

 
   

 

 

3        安装

3.1    下载安装

wget http://fnil.net/downloads/metaq-server-1.4.6.2.tar.gz

tar zxvf  metaq-server-1.4.6.2.tar.gz

 

3.2    配置说明

Meta服务端配置主要在服务器conf目录下的server.ini文件,整体配置分为三部分:系统参数、zookeeper参数以及topic配置。系统参数在system section,zookeeper参数配置在zookeeper section,而topic的配置是在topic=xxxx section。具体说明如下:

一份默认提供的参数配置在这里

3.2.1    系统参数部分

 

brokerId: 服务器集群中唯一的id,集群间的brokerId不能一样,必须为整型0-1024之间。对服务器集群的定义是使用同一个zookeeper并且在zookeeper上的root path相同

hostName: 服务器hostname,默认取本机IP地址,如果你是多网卡机器,可能需要明确指定。服务器会将此hostname加上端口写入到zookeeper提供给客户端发现。

serverPort:服务器端口,默认8123

numPartitions:系统默认情况下每个topic的分区数目,默认为1,可被topic配置覆盖。逻辑分区的作用不仅仅是通过索引提供快速定位消息的功能,它还跟整个metaq的集群有很大的关系。单个服务器的总分区数目不建议超过1000,太多将导致频繁的磁盘寻道严重影响IO性能。

dataPath: 服务器数据文件路径,默认在~home/meta下,每个topic可以覆盖此配置,对于多块磁盘的机器,可设置不同topic到不同磁盘来提升IO效率。

dataLogPath:数据日志文件路径,主要存放事务日志,默认跟dataPath一致,最好单独设置到不同的磁盘或者目录上。如果为空,使用指定的dataPath

getProcessThreadCount: 处理get请求的并发线程数,默认为CPUS*10。

putProcessThreadCount: 处理put请求的并发线程数,默认为CPUS*10。

maxSegmentSize: 单个数据文件的大小,默认为1G。默认无需修改此选项。

maxTransferSize: 传输给消费者的最大数据大小,默认为1M,请根据你的最大消息大小酌情设置,如果太小,每次无法传输一个完整的消息给消费者,导致消费者消费停滞。可设置成一个大数来取消限制。

 

acceptPublish: 是否接收消息,默认为true;如果为false,则不会注册发送信息到zookeeper上,客户端当然无法发送消息到该broker。本参数可以被后续的topic配置覆盖。

acceptSubscribe: 与acceptPublish类似,默认也为true;如果为false,则不会注册消费信息到zookeeper上,消费者无法发现该broker,当然无法从该broker消费消息。本参数可以被后续的topic配置覆盖。

 

stat全局性地控制是否开启实时统计,可被topic配置覆盖,默认为false。

loadMessageStoresInParallel: 是否启动时并行加载数据,开启可提升启动速度。默认不开启。开启后启动日志顺序可能紊乱。

updateConsumerOffsets: 当消费者的offset不在Broker的数据范围内,是否强制更新消费者的offset为当前最大offset。默认为false。测试开发环境建议开启此选项,生产环境不建议

3.2.2    数据可靠性参数

Meta保证消息可靠性是建立在磁盘可靠性的基础上,发送的每一条消息都保证是在“写入磁盘”的情况下才返回给客户端应答。这里有两个关键参数可以控制:

 

unflushThreshold: 每隔多少条消息做一次磁盘sync,强制将更改的数据刷入磁盘。默认为1000。也就是说在掉电情况下,最多允许丢失1000条消息。可设置为0,强制每次写入都sync。在设置为0的情况下,服务器会自动启用group commit技术,将多个消息合并成一次sync来提升IO性能。经过测试,group commit情况下消息发送者的TPS没有受到太大影响,但是服务端的负载会上升很多。

unflushInterval: 间隔多少毫秒定期做一次磁盘sync,默认是10秒。也就是说在服务器掉电情况下,最多丢失10秒内发送过来的消息。不可设置为小于或者等于0。

请注意,上述两个参数都可以被topic单独配置说覆盖,也就是说每个topic可以配置不同的数据可靠级别。

当某个topic开启group commit后,将为每个分区配置一个线程做聚集force,因此请控制启用group commit技术的topic数量,太多可能导致过多线程,反而效率下降

3.2.3    数据删除策略配置

默认情况下,meta是会保存不断添加的消息,然后定期对“过期”的数据进行删除或者归档处理,这都是通过下列参数控制的:

deleteWhen: 何时执行删除策略的cron表达式,默认是0 0 6,18 * * ?,也就是每天的早晚6点执行处理策略。

deletePolicy: 数据删除策略,默认超过7天即删除,这里的168是小时,10s表示10秒,10m表示10分钟,10h表示10小时,不明确指定单位默认为小时。delete是指删除,超过指定时间的数据文件将被彻底从磁盘删除。也可以选择archive策略,即不对过期的数据文件做删除而是归档,当使用archive策略的时候可以选择是否压缩数据文件,如167,archive,true即选择将更改时间超过7天的数据文件归档并压缩为zip文件,如果不选择压缩,则重命名为扩展名为arc的文件。

上述两个参数都可以被topic单独配置所覆盖,也就是每个topic可以指定自己独特的删除策略。通常来说,对于不重要的topic可以将更早地将他们删除来节省磁盘空间。

3.2.4    事务相关配置

maxCheckpoints: 最大保存事务checkpoint数目,默认为3,服务器在启动的时候会从最近一次checkpoint回访事务日志文件,恢复重启前的事务状态。不建议修改此参数。

checkpointInterval事务checkpoint时间间隔,单位毫秒,默认1小时。间隔时间太长,会导致启动的时候replay事务日志占用了太多时间,太短则可能影响到性能。

maxTxTimeoutTimerCapacity最大事务超时timer的数量。服务端会为每个事务启动一个定时器监控事务是否超时,定时器的数目上限通过本参数限制。限制了本参数,也变相地控制了最大可运行的事务数。默认为30000个。

maxTxTimeoutInSeconds最大事务超时时间,单位为秒,默认为60秒。客户端设置的事务超时时间不能超过此设定,超过将被强制限制为此设定。

flushTxLogAtCommit服务端对事务日志的sync策略,0表示让操作系统决定,1表示每次commit都刷盘,2表示每隔1秒刷盘一次。此参数严重影响事务性能,可根据你需要的性能和可靠性之间权衡做出一个合理的选择。通常建议设置为2,表示每隔1秒刷盘一次,也就是最多丢失一秒内的运行时事务。这样的可靠级别对大多数服务是足够的。最安全的当然是设置为1,但是将严重影响事务性能。而0的安全级别最低。安全级别上 1>=2>0,而性能则是0 >= 2 > 1。

3.2.5    zookeeper配置

meta服务端会将自身id,topic信息和socket地址发送到zookeeper上,让客户端可以发现并连接服务器。Zookeeper相关的配置放在[zookeeper]模块下面:

zk.zkEnable: 是否启用zookeeper,也就是是否将信息注册到zookeeper上。默认为true。对于同步复制的slave来说,本参数会被强制设置为false。

zk.zkConnect: zookeeper服务器列表,例如localhost:1281这样的字符串。默认也是localhost:2181。请设置你的zk集群地址列表,形如host:port,host:port的字符串

zk.zkSessionTimeoutMs: zookeeper的session timeout,默认为30秒。单位毫秒。

zk.zkConnectionTimeoutMs zookeeper的连接超时时间,默认同样为30秒,单位毫秒。

zk.zkSyncTimeMs: 预期的zk集群间数据同步延迟,默认为5秒,这个参数对服务器无意义。

3.2.6    Topic配置

服务器将提供哪些topic服务都是通过topic配置来实现的,topic配置都是在[topic=xxx]的模块下面,其中xxx就是topic名称,一个示范配置如下:

[topic=boyan-test]

stat=true

numPartitions=1

这里配置了一个名为test的topic,并针对该topic启用实时统计,并将topic的在本服务器的分区数目设置为1。可见,topic配置可覆盖服务器的部分配置,包括:

stat:是否启用实时统计,启用则会在服务端对该topic的请求做实时统计,可以通过stats topic-name协议观察到该topic运行状况,可选。

numPartitions: 该topic在本服务器的分区总数,覆盖系统配置,可选。

unflushInterval每隔多少条消息做一次磁盘sync,覆盖系统配置,可选。

unflushThreshold每隔多少秒做一次磁盘sync,覆盖系统配置,可选。

deletePolicytopic的删除策略,覆盖系统配置,可选。

deleteWhen删除策略的执行时间,覆盖系统配置,可选。

dataPath设置数据文件路径,覆盖系统配置,可选。

acceptPublish: 是否接收该topic的消息,覆盖系统配置,可选。

acceptSubscribe: 是否接受消费者的订阅,覆盖系统配置,可选

 

3.3    高可用配置

Meta相比于kafka的一个重要特性就是消息高可用方案的实现,我们称之为HA方案。消息在发送到broker之后立即写入磁盘才返回客户端告诉消息生产者消息发送成功,通过unflushThreshold和unflushInterval两个参数的控制,可以保证单机消息数据的安全性,只要机器的磁盘没有永久损坏,消息总可以在重启后恢复并正常投递给消费者们。但是,如果遇到了磁盘永久损坏或者数据文件永久损坏的情况,那么该broker上的消息数据将可能永久丢失。为了防止这种情况的发生,一个可行的方案就是将消息数据复制到多台机器,类似mysql的主从复制功能。

 

meta提供类似mysql主从复制的异步复制和同步功能,分别对应不同的可靠级别。理论上说同步复制能带来更高的可靠级别,异步复制因为延迟的存在,可能会丢失极少量的消息数据,相应地,同步复制会带来性能的损失,因为要同步写入两台甚至更多的broker机器上才算写入成功。

在实际实践中,我更推荐采用异步复制的架构,因为异步复制的架构相对简单,并且易于维护和恢复,对性能也没有影响。而同步复制对运维要求相对很高,机制复杂容易出错,故障恢复也比较麻烦。异步复制加上磁盘做磁盘阵列,足以应对非常苛刻的数据可靠性要求

3.3.1    异步复制

1:部署一个新的broker,具体仍然参照如何开始这份文档,配置server.ini从master broker拷贝一份。

2:配置slave文件。编辑conf/async_slave.properties:

#slave编号,大于等于0表示作为slave启动,同一个master下的slave编号应该设不同值.

slaveId=0

#作为slave启动时向master订阅消息的group,如果没配置则默认为meta-slave-group

#不同的slaveId请使用不同的group

slaveGroup=meta-slave-group

#slave数据同步的最大延时,单位毫秒 

slaveMaxDelayInMills=500

#是否自动从master同步server.ini, 1.4.2新增选项

#第一次仍然需要自己拷贝server.ini,后续可以通过设置此选项为true来自动同步

autoSyncMasterConfig=true

3:启动

bin/metaServer.sh start slave

 

4:第一次复制因为需要跟master完全同步需要耗费一定时间,你可以在数据文件的目录观察复制情况。

5:请注意,异步复制的slave将参与消费者的消费活动,消息消费者可以从slave中获取消息并消费,消费者会随机从master和slaves中挑选一台作为消费broker。

6:请注意,从1.4.2开始,可以通过autoSyncMasterConfig选项配置是否自动同步master的server.ini到异步复制的slave上,当master的server.ini文件变更并通过bin/metaServer.sh reload之后,slave将监控到这一变更并自动同步

 

3.3.2    异步复制的局限

异步复制有延迟,虽然可以通过设定slaveMaxDelayInMills来控制延迟。

3.3.3    异步复制的故障处理

master永久故障: 将slave作为master启动,去除启动参数中的slave即可,也就是

metaServer.sh restart

slave永久故障: 启动新的broker并配置作为master新的slave启动。

 

3.3.4    同步复制

 

        

3.4    服务管理

启动

Master方式启动

bin/metaServer.sh start

Slave方式启动

bin/metaServer.sh start slave

Local方式启动

bin/metaServer.sh start local

停止

bin/metaServer.sh stop

 

新增Topic热部署

 

在新增或者删除topic并保存server.ini之后,可以通过下列命令热加载新的配置文件并生效:

bin/metaServer.sh reload

 

3.5    管理

        服务启动后,可以通过浏览器,查看metaq集群情况:http://192.168.1.137:8120/#cluster

 

 

4       客户端调用

4.1   Java版本

<dependency>

    <groupId>com.taobao.metamorphosis</groupId>

    <artifactId>metamorphosis-client</artifactId>

    <version>${version}</version>

</dependency

 


producer示例:

 

 

 

 

 
   


consumer调用示例:

 

 

4.2   Python

暂时只支持发送消息功能

4.3   Ruby

暂时只支持发送消息功能

5        高级特性

5.1    Spring框架支持

5.2    使用Log4j扩展发送消息

Metaq还支持log4j发送消息,通过log4j写入的任何日志信息都将以消息的方式发送到Metaq的Broker服务器,只要通过简单的配置就可以

如果要用到log4j扩展,你需要使用client-extenstion的包:

依赖

 <dependency>

     <groupId>com.taobao.metamorphosis</groupId>

     <artifactId>metamorphosis-client-extension</artifactId>

     <version>1.4.4</version>

 </dependency>

 

配置log4j.properties

 log4j.logger.testLog=info, testMessage

 log4j.additivity.testMessage=false

 log4j.appender.testMessage=com.taobao.metamorphosis.client.extension.log4j.StreamAppender

 log4j.appender.testMessage.topic=meta-test

 log4j.appender.testMessage.zkConnect=127.0.0.1:2181

 log4j.appender.testMessage.EncodeType=1

 log4j.appender.testMessage.BufferedIO=true

 log4j.appender.testMessage.DatePattern='.'yyyy-MM-dd_HH

 log4j.appender.testMessage.File=../../logs/test.log

 log4j.appender.testMessage.layout=org.apache.log4j.PatternLayout

 log4j.appender.testMessage.layout.ConversionPattern=%d{MM-dd HH:mm:ss} - %m%n

 

最重要的三个参数就是`appender、topic和zkConnect`,分别指定使用metaq扩展的log4j appender,设定metaq发送消息的topic以及zookeeper的服务器地址列表。其他log4j相关的参数只是为了提供给log4j,防止错误的产生,不会产生作用。

使用

在Java代码里使用就很简单了:

static final Log log = LogFactory.getLog("testLog");

log.info("just a test");

默认日志将使用Java序列化成byte[]并发送,这可以通过EncodeType控制,0表示Java序列化,1表示hessian1序列化

 

5.3    消息过滤

6        常见问题

6.1    多网卡机器如何指定服务器使用IP

指定hostname参数

hostName: 服务器hostname,默认取本机IP地址,如果你是多网卡机器,可能需要明确指定。服务器会将此hostname加上端口写入到zookeeper提供给客户端发现。

6.2   master宕机slave会自动切换吗?    

不会,master宕机后,将slave去掉slave参数,重启启动即可,metaq不会做主从自动切换

7       参考阅读地址

官方地址:

https://github.com/killme2008/Metamorphosis/wiki

博客:

http://jameswxx.iteye.com/blog/2034111