阿里巴巴中间件性能挑战赛(MOM篇)

来源:互联网 发布:重生之网络女主播 编辑:程序博客网 时间:2024/05/16 17:04

先贴一下赛题:

实现一个基于发布-订阅模型的消息中间件(broker+client)

必选特性:

提供可靠消息服务,broker要保证数据同步落盘才能向生产者返回发送成功的ack,并保证投递给所有的消费者,直至所有的消费者都消费成功(消费者消费成功或者失败都会返回对应的ack)。一旦消费者对一条消息发生订阅后,那么该消费者消费失败,消费超时(如果消息推送给消费者后,10秒没有返回响应,那么认为消费超时),或者不在线,消息不能丢失,需要尽快重投,让消费者在恢复后可以尽快消费完堆积的消息。

采用实时推送模型(只能push,push完后等待消费者ack,不能使用长轮询),消息一旦到达broker,要立马推送给消费者,消息延迟不能高于50ms。

消息支持自定义属性,能够支持简单的消息属性过滤订阅,broker只能投递符合属性条件的消息给订阅者。例如订阅者发起topic为trade,filter为area=hz的订阅,那么只有topic为trade,并带有area属性值为hz的消息才会投递给订阅者。client要实现提供的api,发送接口必须消息持久化成功才能返回成功。

消息存储必须基于文件系统自己实现,不能使用现成的存储系统,数据存储的根目录为$userhome/store/。系统运行过程中如果突然宕机或者断电(一定要保障消息数据落盘后才能向发送者响应发送成功),重启后消息数据不能丢失。(数据丢失的定义:生产者消息发送返回成功ack后,如果broker出现宕机或者断电后重启,消息丢失了,无法投递给所有的订阅者,直至所有订阅组都消费成功)

消费者和生产者启动的时候可以指定需要连接的broker ip,也就是实现broker单机的模式,前期跑分主要看broker的单机能力。

支持消费者集群,消费负载均衡。比如消费者A是一个集群,订阅了topicA。broker收到topicA的某条消息后,只投递给消费者A集群的某台机器,消费者集群的每台机器每秒消息消费量是均衡的。

加分特性(如果最后实现了必选特性,性能脱颖而出的几个团队,则还会综合考虑系统设计是否能支持以下的特性):

服务高可用,broker可以集群化部署,统一对外提供服务。broker集群中部分机器当机,不会导致消息发送失败,或者无法消费,对消息服务的影响越小越好。

数据高可用,消息存储多份,单一数据存储损坏,不会导致消息丢失。

具备良好的在线横向扩容能力。

支持大量的消息堆积,在大量消费失败或者超时的场景下,broker的性能和稳定不受影响,有良好的削峰填谷能力。

高性能、低成本。

考核方式

从系统设计角度和运行功能测试用例来评判必选特性,不满足必选特性,直接淘汰。

服务高可用、数据高可用、在线横向扩容能力从系统设计角度来评判

性能指标包括:每秒消息接收量,每秒消息投递量,消息投递延迟,消息发送的rt,消息堆积能力,削峰填谷能力。

性能压测场景

4k消息,一个发布者发布topicA,一个订阅者订阅这个topicA的所有消息,订阅者健康消费每条消息,无堆积

4k消息,一个发布者发布topicA,20个订阅者分别订阅topicA不同属性的消息,消费者健康消费,无堆积

4k消息,一个发布者发布topicA,一个订阅者订阅这个topicA的所有消息,订阅者消费超时,大量堆积

4k消息,一个发布者发布topicA,20个订阅者分别订阅topicA不同属性的消息,20个订阅者只有一个订阅者消费成功,其他订阅者消费超时、失败以及不在线,消息出现大量堆积。

4k消息,20个发布者发布20个不同的topic,每个topic都有20个订阅者,他们分别订阅不同属性值的消息,消费健康,无堆积

4k消息,20个发布者发布20个不同的topic,每个topic都有20个订阅者,他们分别订阅不同属性值的消息,所有消费均超时,大量堆积。堆积持续一段时间后,减少90%的发送量,并让消费者恢复正常,broker需要尽可能快的投递堆积的消息。


由于代码细节比较多,如果都讲的话估计三天三夜都讲不完。因此只介绍一些关键的部分。(图片截取自答辩的PPT,图画得渣勿怪)


程序的结构:

Consumer订阅消息的流程:


Producer发送消息的流程:





主要模块以及主要的类:

ProducerConsumer端:
      Connection:网络连接通道,Producer和Consumer通过Connection与Broker交互
      ConnectionFactory获得Connection,配置netty参数
Broker端:
      BrokerHandler:用于网络通信,接受和发送消息
      BrokerController:解析消息类型,根据消息类型调用相应处理模块
      GroupConnection:代表消费者的集群的状态,负责维护消费进度、选择Channel
     TopicQueue:主题队列,负责消息持久化,并且有多个GroupConnection注册在它之上
Message模块:
      Message:基本的消息
      MessageRequest:消息+消费状态
      SendMessageRequest:同上
      SendResultSendState:消费状态
序列化模块:
      Protobufutil:使用Protobuf进行消息序列化和反序列化


一些主要功能的实现思路:

1、重连的实现:consumer&broker&producerpipeline中添加一个handler监听channelInactive事件,不正常关闭时会启动一个定时重连的线程

2、消费进度的恢复:Broker会对每个Consumer集群维护一个记录了消费进度的偏移量,Consumer可以重新连接上来的时候可以根据这个偏移量来恢复消费进度

3、如何处理消息大量堆积的情况:一句话总结就是合理利用磁盘

4、Consumer集群的实现:由于消费进度是在Broker端记录,因此Consumer集群是无状态的,只要设定同个group-id就被视为是同一集群中的机器

5、Broker集群的实现:本功能涉及内容过于复杂,没实现。

6、消息是否重复:消息至少会被收到一次,但是不保证消息不重复。如果需要去重,客户端需要实现幂等操作或者自己实现端到端的去重

7、消息是否有序:不保证消息在消息队列中有序,不过客户端和服务器可以实现端到端的有序


性能优化思路:

1、磁盘io优化:

     1.1、内存映射文件技术(MBB)

     1.2、累积满一页的消息批量写入

     1.3、对文件进行预写

2、tcp参数设置

     2.1、TCP_NODELAY设置为false

     2.2、合理设置TCP  SendBuf和RecvBuf的大小

3、内存优化

     3.1、Netty接收缓冲区内存分配设置为动态分配

     3.2、ByteBuf分配使用内存池,减少GC压力

     3.3、启动定时线程,定时扫描并关闭无效资源,关闭消息大量堆积的GroupConnection


详细代码见:

https://github.com/xiefan46/mom


0 0
原创粉丝点击