metaQ

2,619 阅读11分钟

发展历史

1.Notify //使用了5年 //最早是在子柳的书里有介绍
2.metaQ //使用了5年
3.RocketMQ //使用了5年

www.iteye.com/magazines/1… //最初的核心开发者访谈 //作者太牛了,工作五年就可以写分布式中间件,而且是阿里中间件团队的第一个作品

和RocketMQ的区别?

是否有实现注册中心
1.早期版本
没有自己实现,而是依赖第三方注册中心zookeeper
2.新版
自己实现了简单的注册中心

和Notify的区别?

从上面的发展历程其实也就能够比较清晰的找到两个消息队列产品的不同定位了:

  • RocketQ(MetaQ) 主要面向消息有序的场景,能够提供更大的消息堆积能力,客户端pull模式(为什么要和kafka一样,使用客户端pull模式呢?待补充)。
  • Notify,主要面向需要更加安全可靠地交易类场景,无序推模式
    它的核心特性是: 提供事务支持、不保证消息顺序、消息可能会重复、服务器推模型(一般的消息中间件比如ActiveMQ都是基于服务器push,因为实时性高)。

应用场景

总结
一句话,就是非常适合超大型项目,就是分布式互联网项目设计,而不是企业项目,企业项目使用传统的ActiveMQ即可。


使用MetaQ应注意哪些事项?
MetaQ作为一个分布式的消息中间件,需要依赖zookeeper,对于一些规模不大、单机应用的场景,我个人并不是特别支持尝试用MetaQ,因为多一个依赖系统,其实就是多一份风险,在这些简单场景下,可能类似memcacheq、kestrel甚至redis等轻量级MQ就非常合适。而MetaQ一开始就是为大规模分布式系统设计的,如果不当使用,可能没有带来好处,反而多出一堆问题。开发者需要根据自己面对的场景,团队的技术能力,做出一个合适的选择。

集群

架构图


流程
1.生产者或消费者,从注册中心获取服务器集合,而且是每次请求都会获取一次集合数据。然后,会把集合数据存储在本地,再按轮询算法选择一个服务器,再向服务器发送请求(生产者写数据或消费者读数据)。

2.所以,可以发现,生产者和消费者不是不和服务器通信,而是先要从注册中心获取服务器集合。也就是说,生产者和消费者节点,既和注册中心节点通信,又和服务器节点通信。

负载均衡算法

InfoQ:您个人在分布式方面有比较多的经验,而消息系统中一个重要的考虑因素就是分布式的扩展能力,尤其是对于阿里、淘宝的业务,能不能介绍下目前中间件团队在分布式是如何做的?跨域、跨机房方面?

沈询:其实所谓分布式运算,核心的思路就是系统架构无单点, 让整个系统可扩展。

如果要介绍分布式场景的实际经验,那么我就需要先引入一个概念:“有状态存储节点和无状态运算节点”。

无状态运算节点主要是部署 Web 应用、 HSF 服务,消息队列等的机器有状态的存储节点主要是指部署数据库、缓存、配置服务器、 NoSQL 等的机器。

那么针对无状态节点,因为不存储数据,请求分发可以采取很简单的随机算法或者是轮询的算法就可以了,如果需要增加机器,那只需要把对应的运算代码部署到一些机器上,然后启动起来,引导流量到那些机器上就可以实现动态的扩展了,所以一般来说在无状态的节点的扩展是相对的容易的,唯一需要做的事情就是在某个机器承担了某种角色以后,能够快速的广播给需要这个角色提供服务的人说:“我目前可以做这个活儿啦,你们有需要我做事儿的人,可以来找我。”

而针对有状态节点,扩容的难度就相对的大一些,因为每台 Server 中都有数据,所以请求分发的算法不能够用随机或者是轮询了,一般来说常见算法就是哈希或者是使用 Tree 来做一层映射,而如果需要增加机器,那么需要一个比较复杂的数据迁移的过程,而迁移数据本身所需要的成本是非常高的,这也就直接导致有状态节点的扩容难度比无状态节点更大。//两种情况1.无数据,就使用简单的算法:1)按顺序轮询2)随机选一个 2.有数据,就使用hash:1)求余数 2)一致性hash 3)虚拟槽slot。总共是分两种情况,一起加起来五种负载均衡算法。

针对有状态节点的难题,我们提供了一套数据自动扩容(水平扩容)和迁移(复制)的工具来满足用户的自动扩容缩容中所产生的数据迁移类的需求。 于是,无论是有状态的数据节点的扩容,还是无状态的数据节点的自动扩容,我们都可以使用自动化工具来完成了。

在所有的节点都能够实现自动的扩容以后,整个体系就能够水平的进行扩展了。这种架构很好的支持了我们历年的双 11 大促,而且每年都有一些进步。然而,这套模式也不是万能药,在当下,杭州已经很难满足我们对机器的全部需求了。

为此,我们也在尝试进行异地数据中心的尝试,以期能够将一部分运算和存储能力搬运到异地机房进行。

提到异地数据中心,一般第一个会被想到的是 Google 的 Spanner,这套系统是一个跨数据中心的强一致数据库系统,然而我们在经过仔细的考量以后,认为在目前的情况下,使用这种方式并不能够解决一个大规模在线交易类网站对于高并发 TPS 的实际需求,因此我们选择了另外的方式来实现跨数据中心的事务模式。

其核心思想也很简单,即是将数据放置在距离用户最近的机房里面,并尽可能减少应用层的跨机房调用,以充分提高性能,降低延迟。

与kafka的区别?

可不可以说MetaQ是Apache Kafka的Java实现 & 功能增强版本?
可以这样说,因为总体的设计是一致的,但是我们做了很多优化和改进。

可以简单概括下我们重新写metaq的原因:
Kafka是scala写的,我对scala不熟悉,并且在当时kafka整个社区的发展太缓慢了。 有一些功能是kakfa没有实现,但是我们却需要,比如事务、多种offset存储、高可用方案(HA)等 Meta相对于kafka特有的一些功能:

  • 文本协议设计,非常透明,支持类似memcached stats的协议来监控broker
  • 纯Java实现,从通讯到存储,从client到server都是重新实现
  • 提供事务支持,包括本地事务和XA分布式事务
  • 支持HA复制,包括异步复制和同步复制,保证消息的可靠性
  • 支持异步发送消息
  • 消费消息失败,支持本地恢复
  • 多种offset存储支持,数据库、磁盘、zookeeper,可自定义实现
  • 支持group commit,提升数据可靠性和吞吐量。(目前kafka已实现)
  • 支持消息广播模式
  • 一系列配套项目:Python/Ruby/C/C++客户端、Twitter Storm的Spout、Tail4j等

消息中间件最大的瓶颈

而对于MQ来说,最终的瓶颈都是落在IO存储上(磁盘io,因为最终所有的大量的亿级别的消息数据都要存储在磁盘上)。

内部实现

总结
1.没有实现注册中心,而是依赖第三方注册中心zookeeper
2.所有的事务实现,包括数据库mysql,都是基于日志原理


MetaQ的内部是如何实现的?
从实现角度看,MetaQ充分利用zookeeper这个优秀的服务中心,作为服务注册和查找中心、客户端负载均衡和数据偏移量的分布式存储使用。Zookeeper在MetaQ整个集群中扮演非常关键的角色。 //没有实现注册中心,而是依赖第三方注册中心zookeeper

MetaQ的存储实现与kafka是一致的,充分利用传统磁盘顺序读写非常高效的特点,并且利用group commit、sendfile系统调用等技术来充分提高IO效率。

MetaQ的事务实现跟ActiveMQ是类似的,采用redo日志的方式,并遵循JTA协议规范来实现分布式事务。 //所有的事务实现,包括数据库mysql,都是基于日志原理

MetaQ的网络协议跟memcached文本协议类似,因为我本人非常熟悉memcached(开源的xmemcached客户端是我开发的),但是MetaQ的协议引入了opaque的映射字段,提高请求的并行度。正因为采用文本协议,为MetaQ编写其他语言客户端是相对容易,并且管理MetaQ服务器也变的很容易,比如MetaQ提供了stats协议,通过telent就可以获取服务器的运行状况。

关于更多的实现细节可以看Wiki上的文档:

github.com/killme2008/… github.com/killme2008/…

消费者是主动pull还是被动push

总结
1.kafka是pull //为什么是pull? 因为消息中间件和股票实时软件不一样,股票要求的是实时数据,消息中间件一般都是推迟延后一段时间(几毫秒到几秒)的消息推送或拉取。 2.metaQ也是pull //metaQ的设计基本上是照搬kafka

3.其他MQ一般都是push //阿里最早期的notify、ActiveMQ


MetaQ项目的由来?
MetaQ的起源是我从对Linkedin的开源MQ(现在转移到Apache kafka的学习开始的,这是一个设计很独特的MQ系统,它采用pull机制,而不是一般MQ的push模型,它大量利用了zookeeper做服务发现和offset存储,它的设计理念我非常欣赏并赞同,强烈建议有兴趣的同学阅读一下它的设计文档,总体上说MetaQ的设计跟它是完全一致的。


[] FAQ

[] 采用pull模型,消息的实时性有保证吗?

Metamorphosis在消费端采用pull的模型,consumer主动去broker拉取数据,而不是类似notify那样由broker主动push数据给消费者。可能很多人担心采用pull模型后,会不会消息的实时性降低了,从发送到消费的整个时间周期拉长了。

实际上,meta中消息的实时性受很多因素影响,不能简单地说实时性一定会降低,主要影响因素如下:

  • broker上配置的批量force消息的阈值,默认是1000条force一次。这个值越大,则实时性越低。
  • 消费者每次抓取的数据大小,这个值越大,则实时性越低,但是吞吐量越高。
  • Topic的分区数目对实时性也有较大影响,分区数目越多,则磁盘压力越大,导致消息投递的实时性降低。
  • 消费者重试抓取的时间间隔,越长则延迟越严重。
  • 消费者抓取数据的线程数

可见,消息实时性在meta里受到很多因素的影响,meta可以让用户自己决定如何在响应性和吞吐量之间做平衡,通过配置来合理设置参数,达到应用方需要的实时性,实际测试,消息消费的延迟可以在几毫秒到几秒之间。//虽然不是实时,但是这个时间间隔/延迟是非常短的


一般来说,都是服务器push模式,因为实时性高,特别是对实时性要求比较的系统。比如股票软件

因为服务器有数据的话,肯定要实时推送,但是所谓的服务器推,其实现原理,都是由客户端主动拉,即定时拉取数据。

数据一致性

使用消息中间件的时候,适用的场景就是最终一致性。这个最终的时间是多少呢?毫秒级别。所以说,虽然不是实时成功,而是最终成功,但是这个最终的时间间隔是非常短的,就是几毫秒级别到几秒级别。

工作使用

支付系统
部署的时候就是metaQ(服务器) + zookeeper(注册中心)。

性能测试

www.blogjava.net/livery/arti…

参考

github.com/killme2008/… //官方文档

www.iteye.com/magazines/1… //作者,也是memcache客户端的作者

www.infoq.cn/article/201…

my.oschina.net/lmxy1990/bl…

yq.aliyun.com/articles/85…