我要投搞

标签云

收藏小站

爱尚经典语录、名言、句子、散文、日志、唯美图片

当前位置:香港跑狗图 > 调度队列 >

高可靠高性能的消息队列怎么去实现?

归档日期:05-13       文本归类:调度队列      文章编辑:爱尚语录

  我们看看RPC调用的场景。服务A调用如图所示服务。在正常情况下,一般都不会有问题。但是在以下情况,服务A调用会遇到问题。

  问题三:RPC调用,jar依赖问题?服务B升级,调用B的相关服务是否需要升级?

  RPC服务需要依赖生成的接口描述jar,服务接口升级一般很难做到向前兼容,所以相关调用方也需要升级。

  MQ是以消息为载体的可靠异步调用的框架,能很好的应对上面三个问题。流量削峰,MQ是天然支持的,因为MQ有可靠存储,可以落地。解耦合,交给MQ也很合适。因为MQ的接入方处理的是消息,做到向前兼容也是比较容易的。

  MQ很好很强大,是RPC的有效补充,那问题来了怎么实现一个可靠MQ?本文结合二手交易平台的特点,详细介绍转转ZZMQ架构设计实践。

  我们考虑的重点是:可靠,高性能,运维友好,接入方便,可以支持大量堆积,有效缓冲业务高峰,针对这些需求,我们做了一些设计上的考虑和取舍,最终形成了如下的架构方案。

  一个高性能ZZMQ的瓶颈和难点就是存储系统,存储系统关乎到性能,数据可靠存储实现是否简单,数据备份控制,消息状态的表示。

  目前最常见的是以Kafka为代表的Log-append-file,文件顺序写,追求吞吐量,消息消费状态通过offset来控制,还有以各种存储引擎实现的,比如leveldb(activemq),rocksdb等。

  从这张图(),我们能看到磁盘顺序读写的性能甚至超过了内存随机访问的性能,能达到50多M/s。并且,相对来说,Log-append-file简单一些。最后选择了类似kafka的log-append-file。

  Kafkatopic分成partition,顺序读写,partition有一个小的问题,单机不能支撑大量的topic,单机能支持几百分区,随着分区数量的增加,性能有所下降。而我们的场景的是:业务大部分topic的qps并不像kafka处理的日志文件那么高,希望能单机支撑更多的topic数量。

  针对这一点,我们做了一些调整,topic消息本身不再分区,统一存储,使用更加轻量的Consumer Queue实现partition的功能。Consumer Queue存储的只是位置信息,更加轻量,能做到支持更多的topic。

  消息写入pageCache,再Dispatch到对应的Consumer Queue中去,Consumer Queue只有消息Log的offset信息,以及大小和其他的一些元数据,占用很小的空间。这样设计,经过验证,单机能够支持几千队列。

  这样的设计也带来了一个副作用,因为消息本身是统一存储,topic数量多的时候,消息的读取是随机读,性能有些许下降,目前,我们通过优化linuxpageCache和IO调度,开启系统预读,性能相对顺序读没有太大下降。

  Consumergroup A 有两个消费者实例,B也有两个消费者实例,同时订阅了Topic-A,他们之间的消费进度是独立的。Group处理相同topic,消费逻辑一致的一个整体,包含不同的消费实例。

  基于netty实现了网络层的协议。Netty对nio,和reactor做了很好的封装,netty4.x 对direct buffer的利用,以及高效的buffer分配和回收算法,netty也解决了TCP协议的半包问题,使用方不需要自己组TCP包。用netty实现网络层协议,网络层的可靠由netty来做,减少了复杂度。

  这个设计的考虑主要是两个方面:慢消费,以及消费延迟。主动Push能做到低的消费延迟,但是对于慢消费,不能很好的应对,主动Push需要感知消费者的速率,不至于push 太快,把消费者压垮了。Pull模式,由消费者控制拉取的速度,能很好的应对慢消费的问题,但是,Pull模式对消费延迟不敏感,拉取的频率不好控制,处理不好有可能造成CPU使用率飙升。参照kafka的pull,实现了longpull。Consumer 与Broker建立长连接,Consumer发起拉取请求,如果有消息,Broker 返回消息,如果没有消息,broker hold住这个请求一段时间,等有消息再notify这个请求,返回给客户端。基于long pull,消费延迟能降到跟push差不多,同时又能由Consumer 控制拉取速度。

  消息重复在一个复杂网络条件下很难避免的,如果由MQ本身来做去重,代价太大,所以我们要求接入MQ的逻辑做好幂等(状态机或者版本号的一些机制)。顺序消息,跟kafka一样,Consumer queue跟partition类似,一个Queue内部,消费是有序的。如果要做到完全有序,只能一个Producer,一个Consumer。

  Broker组由主从两台机器构成,可以配置的策略有同步双写和异步复制。默认情况,采用的异步复制,由slave去拉取master上面的消息Log和offset。Broker 接入了内部的监控系统,每分钟上报topic的消费情况和broker状态,能做到分钟级别发现异常消费。消息写入PageCache之后,默认是异步刷盘。也可以配置为同步刷盘,只有刷盘成功才会返回。

本文链接:http://mikephotos.net/diaoduduilie/378.html