`
IXHONG
  • 浏览: 437461 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

RocketMQ高并发读写

    博客分类:
  • MQ
阅读更多

RocketMQ的并发读写能力扛住了2016年双十一,每秒17.5万笔订单的创建(单笔订单衍生出N条消息,实际tps是17.5*n 万),下面对其高并发读写原理进行探讨。主要体现在两方面:客户端收发消息,服务器接收消息并持久化(重点)。

客户端(RocketMQ-client)

1,客户端发送消息有负载均衡,客户端内存中保存着当前所有的服务器列表,每次发送都切换一台服务器发送消息,使得每台服务器接收的消息量尽量均衡,避免热点问题。
2,发送代码为线程安全,当Producer实例就绪之后,完全可以死循环发送消息。一般业务方都会有N个数据源实例,所以从数据源方面就保证高并发写能力。

3,消费者端负载均衡集群消费模式下,同一个ID的所有消费者实例平均消费该Topic的所有队列。

服务器端(Broker)

服务端的高并发读写主要利用Linux操作系统的PageCache特性,通过Java的MappedByteBuffer直接操作PageCache。MappedByteBuffer能直接将文件直接映射到内存,其实就是Map把文件的内容被映像到计算机虚拟内存的一块区域,这样就可以直接操作内存当中的数据而无需操作的时候每次都通过I/O去物理硬盘写文件的。

这里先介绍RocketMQ的消息存储结构:由commitLogconsume queue 两部分组成。

commitLog

1,commitLog是保存消息元数据的地方,所有消息到达Broker后都会保存到commitLog文件。
这里需要强调的是所有topic的消息都会统一保存在commitLog中,举个例子:当前集群有TopicA, TopicB,这两个Toipc的消息会按照消息到达的先后顺序保存到同一个commitLog中,而不是每个Topic有自己独立的commitLog。
2,每个commitLog大小上限为1G,满1G之后会自动新建CommitLog文件做保存数据用。
3,CommitLog的清理机制:

  • 按时间清理,rocketmq默认会清理3天前的commitLog文件;
  • 按磁盘水位清理:当磁盘使用量到达磁盘容量75%,开始清理最老的commitLog文件。

4,文件地址:${user.home}/store/${commitlog}/${fileName}

ConsumerQueue:

1,ConsumerQueue相当于CommitLog的索引文件,消费者消费时会先从ConsumerQueue中查找消息的在commitLog中的offset,再去CommitLog中找元数据。如果某个消息只在CommitLog中有数据,没在ConsumerQueue中, 则消费者无法消费,Rocktet的事务消息就是这个原理。
2,consumequeue的数据结构包含3部分:

  • 消息在commitLog文件实际偏移量(commitLogOffset)
  • 消息大小
  • 消息tag的哈希值

3,文件地址:${user.home}/store/consumequeue/${topicName}/${queueId}/${fileName}

 

得益于以上的数据结构,MQ在写数据过程是顺序写盘,读数据过程是跳跃读盘(尽量命中PageCache)。

消息顺序写

在单台服务器上,MQ元数据都落在单个文件上(即commitLog),大量数据IO都在顺序写同一个commitLog,满1G了再写新的,真正意义上的顺序写盘,再加上MQ默认是累计4K才强制从PageCache中刷到磁盘(缓存),所以高并发写性能突出。

消息跳跃读

MQ读取消息依赖系统PageCache,PageCache命中率越高,读性能越高,Linux平时也会尽量预读数据,使得应用直接访问磁盘的概率降低。

当客户端向Broker拉取消息时,Broker上系统读文件过程如下:

1,检查要读的数据是否在上次预读的cache中;
2,若不在cache,操作系统从磁盘中读取对应的数据页,并且系统还会将该数据页之后的连续几页(一般三页)也一并读入到cache中,再将应用需要的数据返回给应用。此情况操作系统认为是跳跃读取,属于同步预读。
3,若命中cache,相当于上次缓存的内容有效,操作系统认为顺序读盘,则继续扩大缓存的数据范围,将之前缓存的数据页往后的N页数据再读取到cache中,属于异步预读。

系统给cache的定义了一个数据结构,命名为window,window由 当前要读取的内容 + 预读取的内容(group)组成。

下面结合下图举例说明:

  • a状态:操作系统等待应用读请求时的缓存状态。
  • b状态:客户端发起读操作,broker发现所读数据不在Cache中,即不在前次预读的group中,则表明文件访问不是顺序访问(场景有可能是不消费中间的某部分消息,直接消费最新的消息),系统采用同步预读,直接从磁盘中读取页面+缓存页到内存。
  • c状态:客户端继续发起读操作,系统发现所读数据在Cache中,则表明前次预读命中,操作系统把预读group扩大一倍,并让底层文件系统读入group中剩下尚不在Cache中的文件数据块,异步预读。

所以Broker的机器需要大内存,尽量缓存足够多的commitLog,让Broker读写消息基本在PageCache中操作。在运行时,如果数据量非常大,可以看到broker的进程占用内存比较多,其实大部分是被缓存住的commitlog。

 

缓存清理机制(PageCache)

Linux会缓存尽量多的消息数据到内存中,提高读数据缓冲命中率。当内存不够时,还是要清理没用的数据,将清理的空间用以缓存新的内容,这整个过程,Linux用一个双向链表来管理,如下图:

inactive_list代表访问冷数据,active_list代表访问热数据,新分配的数据页先链入到inactive_list头部,当其被引用时再将其移到active_list的头部。

当内存不足时,系统首先从尾部开始反向扫描 active_list并将状态不是referenced的项链入到inactive_list的头部,然后系统反向扫描inactive_list,如果所扫描的项的处于合适的状态就回收该项,直到回收了足够数目的Cache项,这就是系统回收内存的过程。

 

这里需要注意一点,如果内存回收速度比应用写缓存的速度慢,会导致写缓存的线程一直等待,体现到RocketMQ上就是写消息RT很高,这就是 “毛刺问题”。这时就需要结合GC参数和系统内核参数进行调整,此处不对此展开说明了。

 

demo演示:
git clone https://github.com/javahongxi/incubator-rocketmq.git
创建配置文件conf.properties
rocketmqHome=D:\\github\\incubator-rocketmq\\distribution
namesrvAddr=127.0.0.1:9876
mapedFileSizeCommitLog=52428800
mapedFileSizeConsumeQueue=30000

-c conf.properties
依次启动NamesrvStartup,BrokerStartup,Consumer,Producer

 

rocketmq扩展:https://github.com/javahongxi/incubator-rocketmq-externals.git

rocketmq扩展:https://github.com/javahongxi/incubator-rocketmq-externals.git
0
1
分享到:
评论

相关推荐

    java高并发

    本文档主要系统性的总结和阐述了与Java并发相关的知识点

    汪文君高并发编程实战视频资源下载.txt

    │ 高并发编程第二阶段17讲、多线程读写锁分离设计模式讲解-中.mp4 │ 高并发编程第二阶段18讲、多线程读写锁分离设计模式讲解-下.mp4 │ 高并发编程第二阶段19讲、多线程不可变对象设计模式Immutable-上.mp4 │...

    (牛客网C++课程)Linux 高并发Web服务器项目实战(带定时检测代码)

    (牛客网C++课程)Linux 高并发Web服务器项目实战(带定时检测代码) 技术框架: 1. 线程池 + 非阻塞 socket + epoll + 事件处理的并发模型 2. 状态机解析HTTP请求 3. 心跳机制 4. 简易日志系统 主要内容: 1. ...

    Golang实现对map的并发读写的方法示例

    主要介绍了Golang实现对map的并发读写的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    C#解决SQlite并发异常问题的方法(使用读写锁)

    本文实例讲述了C#解决SQlite并发异常问题的方法。分享给大家供大家参考,...作者利用读写锁(ReaderWriterLock),达到了多线程安全访问的目标。 using System; using System.Collections.Generic; using System.Text;

    RocketMQ技术讲解V2.0

    1、讲解commitlog、consumequeue、index、transaction文件等数据结构、数据读写、HA高可用等功能; 2、讲解NameServer的启动、注册Broker、客户端查询Topic的路由信息等功能; 3、讲解Broker的启动、注册、处理...

    手写RocketMq详细操作手册

    消息队列 RocketMQ 是阿里巴巴集团基于高可用分布式集群技术,自主研发的云正式商用的专业消息中间件,既可为分布式应用系统提供异步解耦 和削峰填谷的能力,同时也具备互联网应用所需的海量消息堆积、高吞吐、可靠...

    汪文君高并发编程实战视频资源全集

    │ 高并发编程第二阶段17讲、多线程读写锁分离设计模式讲解-中.mp4 │ 高并发编程第二阶段18讲、多线程读写锁分离设计模式讲解-下.mp4 │ 高并发编程第二阶段19讲、多线程不可变对象设计模式Immutable-上.mp4 │...

    基于SpringBoot + MySQL + Redis + RabbitMQ + Guava开发的高并发商品限时秒杀系统

    基于SpringBoot + MySQL + Redis + RabbitMQ + Guava开发的高并发商品限时秒杀系统 项目经过严格测试,确保可以运行!源码无需做任何更改! 系统介绍 本系统是使用SpringBoot开发的高并发限时抢购秒杀系统,除了...

    redis读写分离可拓展并发

    1、redis读写分离 2、高并发控制 3、可拓展 4、BDRP分部署集群 5、详细介绍安装部署

    互联网高并发解决方法.doc

    企业高并发的成熟解决方案 1 1 整体网站架构分析 1 2 高并发 1 2.1 什么是高并发呢? 1 2.2 高并发原理图 1 2.3 初期解决方案 2 2.3.1 系统或服务器级别的解决方案 2 2.3.2 应用级别的解决方案 2 2.4 能否增加服务器...

    C#使用读写锁三行代码简单解决多线程并发的问题

    本文主要介绍了C#使用读写锁三行代码简单解决多线程并发写入文件时提示“文件正在由另一进程使用,因此该进程无法访问此文件”的问题。需要的朋友可以参考借鉴

    mysql的myisam解决并发读写解决方法

    MyISAM在读操作占主导的...可一旦出现大量的读写并发,同InnoDB相比,MyISAM的效率就会直线下降,而 且,MyISAM和InnoDB的数据存储方式也有显著不同:通常,在MyISAM里,新数据会被附加到数据文件的结尾,······

    5.1大数据高并发-读写分离mssql订阅发布1

    读写分离:场景:1. 适合接口延迟的业务 2.要求及时性的,crud都在一个主库 3. 要求及时性的并且要求降低压力,结合No-sql缓存MSSQLServer

    行业文档-设计装置-在重复数据删除中支持文件并发读写的方法.zip

    行业文档-设计装置-在重复数据删除中支持文件并发读写的方法.zip

    SpringBoot开发的高并发限时抢购秒杀系统

    本系统是使用SpringBoot开发的高并发限时抢购秒杀系统,除了实现基本的登录、查看商品列表、秒杀、下单等功能,项目中还针对高并发情况实现了系统缓存、降级和限流。 开发工具: IntelliJ IDEA + Navicat + ...

    无痕驱动读写-破虚拟读写

    无痕驱动读写-破虚拟读写无痕驱动读写-破虚拟读写无痕驱动读写-破虚拟读写无痕驱动读写-破虚拟读写无痕驱动读写-破虚拟读写无痕驱动读写-破虚拟读写无痕驱动读写-破虚拟读写无痕驱动读写-破虚拟读写无痕驱动读写-破...

    InnoDB怎么应对高并发

    总结 (1)常见并发控制保证数据一致性的方法有锁,数据多版本; (2)普通锁串行,读写锁读读并行,数据多版本读写并行;...(6)InnoDB之所以并发高,快照读不加锁; (7)InnoDB所有普通select都是快照读;

    PHP读写文件高并发处理操作实例详解

    本文实例讲述了PHP读写文件高并发处理操作。分享给大家供大家参考,具体如下: 背景: 最近公司游戏开发需要知道游戏加载的流失率。因为,我们做的是网页游戏。玩过网页游戏的人都知道,进入游戏前要加载一些资源。...

Global site tag (gtag.js) - Google Analytics