Metaq的一些简单机制

目前用到一些Metaq的东西,虽然对Metaq的使用很少,并且不是特别深,但还是觉得应该针对其消息的分发以及简单的机制进行一些记录。

Metaq 的简单介绍:

MetaQ(全称Metamorphosis)是一个高性能、高可用、可扩展的分布式消息中间件,,MetaQ具有消息存储顺序写、吞吐量大和支持本地和XA事务等特性,适用于大吞吐量、顺序消息、广播和日志数据传输等场景,METAQ在阿里巴巴各个子公司被广泛应用,每天转发250亿+条消息。主要应用于异步解耦,Mysql数据复制,收集日志等场景。但是目前就我接触的来看,其广播机制是通过定义多个group来进行实现。其对单个消息的大小建议不超过1M,最好几百K。

Metaq的消息机制:

Metaq的消息会对应相应的消息生产者,消息消费者,一种对应的关系可以用下面一张图简单概括:


我们选择发送的每一个消息MessageA一定会选择发送到某个Topic下,那么对于该Topic,可以有若干个Group进行订阅,当某条消息发送到某个Topic下时,所有订阅该Topic的group都会收到MessageA的一个复制消息。而当消息从Group下发到某个机器时,会根据负载等其他机制选择该group下的某台机器进行处理。也就是对于GroupA 下的Machine 1,Machine 2, Machine 3等机器,只会有一台机器收到MessageA对应的复制消息。那么对于每一条消息的Tag是用来做什么呢? 当某台机器得到MessageA时,可以根据其Tag标来进行选择不同的处理器进行处理,这里其实主要是用来对消息进行处理过滤。例如:对于MessageA 加入有标签:newuser,那么我们可以选择newuser对应的processer进行处理,如果标签为olduser,我们可以选择olduser的processer进行处理。

对于Metaq的消息消费,是客户机拉取的方式进行。

简单的生产者,消费者的Java例子。

自己简单写的一个metaq的生产者例子:

<span style="font-size:14px;">public class MetaqProducer {
//private static final Logger log = LoggerFactory.getLogger(MetaqProducer.class);
	private static MetaqProducer sender = null;
	private static MetaqConsumer receiver = null;
	static {
		try {
			sender = new MetaqProducer();
		} catch (MQClientException e) {
		}
	}
	private MetaProducer producer = new MetaProducer("TestGroup");
	private MetaqProducer() throws MQClientException {
		producer.setInstanceName(UUID.randomUUID().toString());
		producer.start();
	}
	private SendResult send(String topic, String tag, String key, byte[] body) {
		Message msg = new Message(topic, tag, key, body);
		try {
			return producer.send(msg);
		}catch(Exception e) {
			return new SendResult();
		}
	}
	public static SendResult sendMessage(String topic, String tag, String key, byte[] body) {
		return sender.send(topic, tag, key, body);
	}
	/**
	 * 测试用
	 * @throws MQClientException 
	 * @throws InterruptedException 
	 */
	public static void main(String[] args) throws MQClientException, InterruptedException{
		System.out.println("Test Start!");
		int j = 100;
		int i =0 ;
		for( ; i < j ; i++){
		System.out.println("i="+i);
		SendResult r = sendMessage("testTopic", "testTag", "TestOnly"+ UUID.randomUUID().toString(), ("Hello world" + i).getBytes());
		System.out.println(r.getMsgId()+"	");
		System.out.println(r.getSendStatus().toString());
		}
	}
}</span><span style="font-size: 18px;">
</span>

自己简单写的一个metaq的消费者例子:

<span style="font-size:14px;">public class MetaqConsumer {

	private static MetaPushConsumer consumer = null;
	public static MetaPushConsumer getMetaqClient(){
		consumer = new  MetaPushConsumer("TestGroup");
		consumer.setInstanceName(UUID.randomUUID().toString());
		consumer.setConsumeThreadMax(10);
		consumer.setConsumeThreadMin(5);
		try {
			consumer.subscribe("testTopic", "testTag");
		} catch (MQClientException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return consumer;
	}
	public static void receiveMsg() throws MQClientException{

		consumer = getMetaqClient();
		consumer.registerMessageListener(new MessageListenerConcurrently() {
			/**
			 * 1、默认msgs里只有一条消息,可以通过设置consumeMessageBatchMaxSize参数来批量接收消息<br>
			 * 2、如果设置为批量消费方式,要么都成功,要么都失败。<br>
			 * 3、此方法由MetaQ客户端多个线程回调,需要应用来处理并发安全问题<br>
			 * 4、抛异常与返回ConsumeConcurrentlyStatus.RECONSUME_LATER等价<br>
			 * 5、每条消息失败后,会尝试重试,重试5次都失败,则丢弃<br>
			 */
			@Override
			public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
				
				if (msgs == null || msgs.size() == 0) {
					return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
				}
				if (msgs.size() == 1) {// 一个消息
					String data = new String(msgs.get(0).getBody());
					System.out.println("Test");
					System.out.println(data);
					return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
				}else{
					for(MessageExt s : msgs){
						String data = new String(s.getBody());
						System.out.println("Test");
						System.out.println(data);
					}
					return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
				}
			}
		});
		// Consumer对象在使用之前必须要调用start初始化,初始化一次即可
		consumer.start();
	}
	public static void main(String[] args) throws MQClientException{
		receiveMsg();
	}
	
}</span>

一个很好的消息中间件,目前可能对他的了解还很浅薄。希望能够在更多的应用场景中对其有所了解。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值