metaq官方文档整理Word文档下载推荐.docx
《metaq官方文档整理Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《metaq官方文档整理Word文档下载推荐.docx(35页珍藏版)》请在冰豆网上搜索。
∙分布式环境下(broker,producer,consumer都为集群)的消息路由,对顺序和可靠性有极高要求的场景。
∙作为一般MQ来使用的其他功能
本分支说明
meta项目开源在淘蝌蚪上,这个分支是我从淘蝌蚪上fork出来的,起始版本是开源的第一个版本,也就是1.0.0-taocode。
我fork分支的主要目的是提供一个干净可用的版本,并且提供持续的维护,并添加更多适合外部用户的文档。
更重要的是,这个分支是我们自己在用:
)
概念和术语
Meta的概念和术语介绍
消息生产者
也称为MessageProducer,一般简称为producer,负责产生消息并发送消息到meta服务器。
消息消费者
也称为MessageConsumer,一般简称为consumer,负责消息的消费,meta采用pull模型,由消费者主动从meta服务器拉取数据并解析成消息并消费。
Topic
消息的主题,由用户定义并在服务端配置。
producer发送消息到某个topic下,consumer从某个topic下消费消息。
分区(partition)
同一个topic下面还分为多个分区,如meta-test这个topic我们可以分为10个分区,分别有两台服务器提供,那么可能每台服务器提供5个分区,假设服务器id分别为0和1,则所有分区为0-0、0-1、0-2、0-3、0-4、1-0、1-1、1-2、1-3、1-4。
分区跟消费者的负载均衡机制有很大关系,具体见集群和负载均衡。
Message
消息,负载用户数据并在生产者、服务端和消费者之间传输。
Broker
就是meta的服务端或者说服务器,在消息中间件中也通常称为broker。
消费者分组(Group)
消费者可以是多个消费者共同消费一个topic下的消息,每个消费者消费部分消息。
这些消费者就组成一个分组,拥有同一个分组名称,通常也称为消费者集群
Offset
消息在broker上的每个分区都是组织成一个文件列表,消费者拉取数据需要知道数据在文件中的偏移量,这个偏移量就是所谓offset。
Offset是绝对偏移量,服务器会将offset转化为具体文件的相对偏移量。
详细内容参见#消息的存储结构
可靠性、顺序和重复
可靠性
Metamorphosis的可靠性保证贯穿客户端和服务器。
生产者的可靠性保证
消息生产者发送消息后返回SendResult,如果isSuccess返回为true,则表示消息已经确认发送到服务器并被服务器接收存储。
整个发送过程是一个同步的过程。
保证消息送达服务器并返回结果。
服务器的可靠性保证
消息生产者发送的消息,meta服务器收到后在做必要的校验和检查之后的第一件事就是写入磁盘,写入成功之后返回应答给生产者。
因此,可以确认每条发送结果为成功的消息服务器都是写入磁盘的。
写入磁盘,不意味着数据落到磁盘设备上,毕竟我们还隔着一层os,os对写有缓冲。
Meta有两个特性来保证数据落到磁盘上
∙每1000条(可配置),即强制调用一次force来写入磁盘设备。
∙每隔10秒(可配置),强制调用一次force来写入磁盘设备。
因此,Meta通过配置可保证在异常情况下(如磁盘掉电)10秒内最多丢失1000条消息。
当然通过参数调整你甚至可以在掉电情况下不丢失任何消息。
服务器通常组织为一个集群,一条从生产者过来的消息可能按照路由规则存储到集群中的某台机器。
Meta已经实现高可用的HA方案,类似mysql的同步和异步复制,将一台meta服务器的数据完整复制到另一台slave服务器,并且slave服务器还提供消费功能(同步复制不提供消费)。
消费者的可靠性保证
消息的消费者是一条接着一条地消费消息,只有在成功消费一条消息后才会接着消费下一条。
如果在消费某条消息失败(如异常),则会尝试重试消费这条消息(默认最大5次),超过最大次数后仍然无法消费,则将消息存储在消费者的本地磁盘,由后台线程继续做重试。
而主线程继续往后走,消费后续的消息。
因此,只有在MessageListener确认成功消费一条消息后,meta的消费者才会继续消费另一条消息。
由此来保证消息的可靠消费。
消费者的另一个可靠性的关键点是offset的存储,也就是拉取数据的偏移量。
我们目前提供了以下几种存储方案
∙zookeeper,默认存储在zoopkeeper上,zookeeper通过集群来保证数据的安全性。
∙mysql,可以连接到您使用的mysql数据库,只要建立一张特定的表来存储。
完全由数据库来保证数据的可靠性。
∙file,文件存储,将offset信息存储在消费者的本地文件中。
Offset会定期保存,并且在每次重新负载均衡前都会强制保存一次。
顺序
很多人关心的消息顺序,希望消费者消费消息的顺序跟消息的发送顺序是一致的。
比如,我发送消息的顺序是A、B、C,那么消费者消费的顺序也应该是A、B、C。
乱序对某些应用可能是无法接受的。
Metamorphosis对消息顺序性的保证是有限制的,默认情况下,消息的顺序以谁先达到服务器并写入磁盘,则谁就在先的原则处理。
并且,发往同一个分区的消息保证按照写入磁盘的顺序让消费者消费,这是因为消费者针对每个分区都是按照从前到后递增offset的顺序拉取消息。
Meta可以保证,在单线程内使用该producer发送的消息按照发送的顺序达到服务器并存储,并按照相同顺序被消费者消费,前提是这些消息发往同一台服务器的同一个分区。
为了实现这一点,你还需要实现自己的PartitionSelector用于固定选择分区
publicinterfacePartitionSelector{
publicPartitiongetPartition(Stringtopic,List<
Partition>
partitions,Messagemessage)throwsMetaClientException;
}
选择分区可以按照一定的业务逻辑来选择,如根据业务id来取模。
或者如果是传输文件,可以固定选择第n个分区使用。
当然,如果传输文件,通常我们会建议你只配置一个分区,那也就无需选择了。
消息的顺序发送我们在1.2这个版本提供了OrderedMessageProducer,自定义管理分区信息,并提供故障情况下的本地存储功能。
消息重复
消息的重复包含两个方面,生产者重复发送消息以及消费者重复消费消息。
针对生产者来说,有可能发生这种情况,生产者发送消息,等待服务器应答,这个时候发生网络故障,服务器实际已经将消息写入成功,但是由于网络故障没有返回应答。
那么生产者会认为发送失败,则再次发送同一条消息,如果发送成功,则服务器实际存储两条相同的消息。
这种由故障引起的重复,meta是无法避免的,因为meta不判断消息的data是否一致,因为它并不理解data的语义,而仅仅是作为载荷来传输。
针对消费者来说也有这个问题,消费者成功消费一条消息,但是此时断电,没有及时将前进后的offset存储起来,则下次启动的时候或者其他同个分组的消费者owner到这个分区的时候,会重复消费该条消息。
这种情况meta也无法完全避免。
Meta对消息重复的保证只能说在正常情况下保证不重复,异常情况无法保证,这些限制是由远程调用的语义引起的,要做到完全不重复的代价很高,meta暂时不会考虑。
如何开始
下载服务器
从下载页面选择最新版本的服务器(目前是1.4.4)并下载到本地,假设下载后的文件在folder目录,执行下列命令解压缩文件:
cdfolder
tarzxvftaobao-metamorphosis-server-wrapper-1.4.4.tar.gz
解压缩文件,解压后目录结构大概为:
taobao
metamorphosis-server-wrapper
bin
env.bat
env.sh
log4j.properties
metaServer.bat
metaServer.sh
tools_log4j.properties
logs
conf
server.ini
......
lib
启动脚本放在bin目录,主要的脚本是metaServer.sh,日志在logs目录,而配置文件主要是conf目录下server.ini,lib存放所有的依赖jar包。
配置Broker
默认server.ini提供了一个topic——test用于测试,你可以添加自己定义的topic:
[topic=mytopic]
;
是否启用统计
stat=true
这个topic指定分区数目,如果没有设置,则使用系统设置
numPartitions=10
删除策略的执行时间,cron表达式
deleteWhen=006,18**?
大多数system参数都可以topic参数所覆盖。
启动和关闭服务器
确保你的机器上安装了JDK并正确设置JAVA_HOME和PATH变量,启动服务器:
bin/metaServer.shstartlocal
关闭服务器:
bin/metaServer.shstop
在windows上,双击执行"
bin/metaServer.bat"
即可(windows不支持local模式启动,需配置zookeeper,见下文的zookeeper配置一节)。
修改JAVA_HOME,JMX等变量,请修改bin/env.sh(forlinux)或者bin/env.bat(forwindows)。
更多metaServer.sh支持命令请使用help:
bin/metaServer.shhelp
=>
Usage:
metaServer.sh{start|status|stop|restart|reload|stats|open-partitions|close-partitions|move-partitions|delete-partitions|query}
验证服务器正常运行
除了通过观察日志logs/metaServer.log外,你还可以通过stats命令来观察服务器运行状况。
bin/metaServer.shstats
=>
STATS
pid7244
broker_id0
port8123
uptime2057
version1.4.2
curr_connections1
threads35
cmd_put0
cmd_get0
cmd_offset0
tx_begin0
tx_xa_begin0
tx_commit0
tx_rollback0
get_miss0
put_failed0
total_messages0
topics2
config_checksum718659887
END
你也可以telnet到默认的8123端口执行stats命令查看。
集群模式配置
Local模式
上文提到的启动方式是以本地模式也就是单机模式启动,它将启动一个内置的zookeeper,并将broker注册到该zookeeper。
这对于单机应用或者测试开发是最便捷方式的。
但是MetaQ是作为分布式软件设计的,更通常作为一个集群提供服务。
MetaQ的集群管理是利用zookeeper实现的,因此首先需要配置zookeeper。
一个MetaQ集群必须使用同一个zookeeper集群。
配置zookeeper
Metamorphosis使用zookeeper发布和订阅服务,并默认使用zookeeper存储消费者offset,因此,你需要首先安装一个zookeeper到某台机器上,或者使用某个现有的zk集群,安装zookeeper请参考zookeeper文档。
假设你在本机安装并启动了一个zookeeper,端口在默认的2181,请修改conf/server.ini文件,保证zookeeper地址正确:
;
zk的服务器列表
zk.zkConnect=localhost:
2181
zk心跳超时,单位毫秒,默认30秒
zk.zkSessionTimeoutMs=30000
zk连接超时时间,单位毫秒,默认30秒
zk.zkConnectionTimeoutMs=30000
zk数据同步时间,单位毫秒,默认5秒
zk.zkSyncTimeMs=5000
其他zk参数请酌情设置。
其他重要参数还包括dataPath和numPartitions,分别用于指定默认的数据存储路径,以及默认topic的分区数目。
具体参数信息请看conf/server_sample.ini示范文件。
启动服务器
假设你准备建立一个两台broker组成的MetaQ集群提供消息服务,那么通常你需要两台机器来运行MetaQ。
但是这里为了简单测试,以单机运行集群模式为例子。
首先,按照上文的提示,正常启用Local模式后,假设为broker1,请拷贝一份MetaQ到不同目录,假设为broker2,需要修改两个参数:
serverPort和dataPath,分别对应服务器端口和数据存储路径,将broker2的这两个参数修改为不同值,其他设置保持不变。
然后,停止local模式启动的broker1,并重新以集群模式启动:
metaServer.shstop
metaServer.shstart
进入broker2的bin目录,启动broker2:
这样即组成两个broker的MetaQ集群。
简单例子
∙metamorphosis-example
Example
消息中间件中有两个角色:
消息生产者和消息消费者。
Meta里同样有这两个概念,消息生产者负责创建消息并发送到meta服务器,meta服务器会将消息持久化到磁盘,消息消费者从meta服务器拉取消息并提交给应用消费。
我们假设你已经部署了你的meta服务器,参见如何开始。
Java客户端例子
推荐你使用maven,引用metajavaclient非常简单:
<
dependency>
groupId>
com.taobao.metamorphosis<
/groupId>
artifactId>
metamorphosis-client<
/artifactId>
version>
1.4.4<
/version>
/dependency>
创建一个示例工程,或者直接将metamorphosis-example
clone出来到你本地机器。
gitclonegit:
//
请注意,1.4.3及以上版本的java客户端只能连接1.4.3及以上版本的MetaQ服务器,而1.4.3之前的老客户端则没有限制。
主要是因为1.4.3引入了发布和订阅topic的分离,1.4.3的新客户端只能查找到新版本的broker
消息会话工厂类
在使用消息生产者和消费者之前,我们需要创建它们,这就需要用到消息会话工厂类——MessageSessionFactory,由这个工厂帮你创建生产者或者消费者。
除了这些,MessageSessionFactory还默默无闻地在后面帮你做很多事情,包括:
1.服务的查找和发现,通过diamond和zookeeper帮你查找日常的meta服务器地址列表
2.连接的创建和销毁,自动创建和销毁到meta服务器的连接,并做连接复用,也就是到同一台meta的服务器在一个工厂内只维持一个连接。
3.消息消费者的消息存储和恢复,后续我们会谈到这一点。
4.协调和管理各种资源,包括创建的生产者和消费者的。
因此,我们首先需要创建一个会话工厂类,MessageSessionFactory仅是一个接口,它的实现类是MetaMessageSessionFactory:
MessageSessionFactorysessionFactory=newMetaMessageSessionFactory(newMetaClientConfig());
请注意,MessageSessionFactory应当尽量复用,也就是作为应用中的单例来使用,简单的做法是交给spring之类的容器帮你托管。
翠花,上代码:
packagecom.taobao.metamorphosis.example;
importjava.io.BufferedReader;
importjava.io.InputStreamReader;
importcom.taobao.metamorphosis.Message;
importcom.taobao.metamorphosis.client.MessageSessionFactory;
importcom.taobao.metamorphosis.client.MetaClientConfig;
importcom.taobao.metamorphosis.client.MetaMessageSessionFactory;
importcom.taobao.metamorphosis.client.producer.MessageProducer;
importcom.taobao.metamorphosis.client.producer.SendResult;
importcom.taobao.metamorphosis.utils.ZkUtils.ZKConfig;
publicclassProducer{
publicstaticvoidmain(String[]args)throwsException{
finalMetaClientConfigmetaClientConfig=newMetaClientConfig();
finalZKConfigzkConfig=newZKConfig();
//设置zookeeper地址
zkConfig.zkConnect="
127.0.0.1:
2181"
metaClientConfig.setZkConfig(zkConfig);
//Newsessionfactory,强烈建议使用单例
MessageSessionFactorysessionFactory=newMetaMessageSessionFactory(metaClientConfig);
//createproducer,强烈建议使用单例
MessageProducerproducer=sessionFactory.createProducer();
//publishtopic
finalStringtopic="
test"
producer.publish(topic);
BufferedReaderreader=newBufferedReader(newInputStreamReader(System.in));
Stringline=null;
while((line=reader.readLine())!
=null){
//sendmessage
SendResultsendResult=producer.sendMessage(newMessage(topic,line.getBytes()));
//checkresult
if(!
sendResult.isSuccess()){
System.err.println("
Sendmessagefailed,errormessage:
"
+sendResult.getErrorMessage());
}
else{
System.out.println("
Sendmessagesuccessfully,sentto"
+sendResult.getPartition());
消息生产者的接口是MessageProducer,你可以通过它来发送消息。
创建生产者很简单,通过MessageSessionFactory的createProducer方法即可以创建一个生产者。
在Meta里,每个消息对象都是Message类的实例,Message表示一个消息对象,它包含这么几个属性:
∙id:
Long型的消息id,消息的唯一id,系统自动产生,用户无法设置,在发送成功后由服务器返回,发送失败则为0。
∙topic:
消息的主题,订阅者订阅该主题即可接收发送到该主题下的消息,生产者通过指定发布的topic查找到需要连接的服务器地址,必须。
∙data:
消息的有效载荷,二进制数据,也就是消息内容,meta永远不会修改消息内容,你发送出去是什么样子,接收到就是什么样子。
消息内容通常限制在1M以内,我的建议