消息队列高手课
李玥
京东零售技术架构部资深架构师
立即订阅
8426 人已学习
课程目录
已完结 41 讲
0/4登录后,你可以任选4讲全文学习。
课前必读 (2讲)
开篇词 | 优秀的程序员,你的技术栈中不能只有“增删改查”
免费
预习 | 怎样更好地学习这门课?
基础篇 (8讲)
01 | 为什么需要消息队列?
02 | 该如何选择消息队列?
03 | 消息模型:主题和队列有什么区别?
04 | 如何利用事务消息实现分布式事务?
05 | 如何确保消息不会丢失?
06 | 如何处理消费过程中的重复消息?
07 | 消息积压了该如何处理?
08 | 答疑解惑(一) : 网关如何接收服务端的秒杀结果?
进阶篇 (21讲)
09 | 学习开源代码该如何入手?
10 | 如何使用异步设计提升系统性能?
11 | 如何实现高性能的异步网络传输?
12 | 序列化与反序列化:如何通过网络传输结构化的数据?
13 | 传输协议:应用程序之间对话的语言
14 | 内存管理:如何避免内存溢出和频繁的垃圾回收?
加餐 | JMQ的Broker是如何异步处理消息的?
15 | Kafka如何实现高性能IO?
16 | 缓存策略:如何使用缓存来减少磁盘IO?
17 | 如何正确使用锁保护共享数据,协调异步线程?
18 | 如何用硬件同步原语(CAS)替代锁?
19 | 数据压缩:时间换空间的游戏
20 | RocketMQ Producer源码分析:消息生产的实现过程
21 | Kafka Consumer源码分析:消息消费的实现过程
22 | Kafka和RocketMQ的消息复制实现的差异点在哪?
23 | RocketMQ客户端如何在集群中找到正确的节点?
24 | Kafka的协调服务ZooKeeper:实现分布式系统的“瑞士军刀”
25 | RocketMQ与Kafka中如何实现事务?
26 | MQTT协议:如何支持海量的在线IoT设备?
27 | Pulsar的存储计算分离设计:全新的消息队列设计思路
28 | 答疑解惑(二):我的100元哪儿去了?
案例篇 (7讲)
29 | 流计算与消息(一):通过Flink理解流计算的原理
30 | 流计算与消息(二):在流计算中使用Kafka链接计算任务
31 | 动手实现一个简单的RPC框架(一):原理和程序的结构
32 | 动手实现一个简单的RPC框架(二):通信与序列化
33 | 动手实现一个简单的RPC框架(三):客户端
34 | 动手实现一个简单的RPC框架(四):服务端
35 | 答疑解惑(三):主流消息队列都是如何存储消息的?
测试篇 (2讲)
期中测试丨10个消息队列热点问题自测
免费
期末测试 | 消息队列100分试卷等你来挑战!
结束语 (1讲)
结束语 | 程序员如何构建知识体系?
消息队列高手课
登录|注册

15 | Kafka如何实现高性能IO?

李玥 2019-08-27
你好,我是李玥。
Apache Kafka 是一个高性能的消息队列,在众多消息队列产品中,Kafka 的性能绝对是处于第一梯队的。我曾经在一台配置比较好的服务器上,对 Kafka 做过极限的性能压测,Kafka 单个节点的极限处理能力接近每秒钟 2000 万条消息,吞吐量达到每秒钟 600MB。
你可能会问,Kafka 是如何做到这么高的性能的?
我们在专栏“进阶篇”的前几节课,讲的知识点一直围绕着同一个主题:怎么开发一个高性能的网络应用程序。其中提到了像全异步化的线程模型、高性能的异步网络传输、自定义的私有传输协议和序列化、反序列化等等,这些方法和优化技巧,你都可以在 Kafka 的源代码中找到对应的实现。
在性能优化方面,除了这些通用的性能优化手段之外,Kafka 还有哪些“独门绝技”呢?
这节课,我来为你一一揭晓这些绝技。

使用批量消息提升服务端处理能力

我们知道,批量处理是一种非常有效的提升系统吞吐量的方法。在 Kafka 内部,消息都是以“批”为单位处理的。一批消息从发送端到接收端,是如何在 Kafka 中流转的呢?
我们先来看发送端,也就是 Producer 这一端。
在 Kafka 的客户端 SDK(软件开发工具包)中,Kafka 的 Producer 只提供了单条发送的 send() 方法,并没有提供任何批量发送的接口。原因是,Kafka 根本就没有提供单条发送的功能,是的,你没有看错,虽然它提供的 API 每次只能发送一条消息,但实际上,Kafka 的客户端 SDK 在实现消息发送逻辑的时候,采用了异步批量发送的机制。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《消息队列高手课》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(38)

  • 每天晒白牙
    谢谢老师,今天讲到的点,我会在课下去读源码并写出文章

    作者回复: 期待

    2019-08-27
    9
  • 微微一笑
    老师好,有些疑问希望老师解答下:
    ①rocketMq有consumeQueue,存储着offset,然后通过offset去commitlog找到对应的Message。通过看rocketmq的开发文档,通过offset去查询消息属于【随机读】,offset不是存储着消息在磁盘中的位置吗?为什么属于随机读呢?
    ②rocketMq的某个topic下指定的消息队列数,指的是consumeQueue的数量吗?
    ③性能上,顺序读优于随机读。rocketMq的实现上,在消费者与commitlog之间设计了consumeQueue的数据结构,导致不能顺序读,只能随机读。我的疑惑是,rocketMq为什么不像kafka那样设计,通过顺序读取消息,然后再根据topic、tag平均分配给不同的消费者实例,,这样消息积压的时候,直接增加消费者实例就可以了,不需要增加consumeQueue,这样也可以去除consumeQueue的存在呀?我在想consumeQueue存在的意义是什么呢?
    哈哈,我的理解可能有些问题,希望老师指点迷津~

    作者回复: A1:这个过程就是随机读的过程。所有对文件的读写最终都要指定一个位置,都是按位置去读。随机读和顺序读的区别是,读取的数据是不是在文件中连续的一段。

    A2:是的。

    A3:RocketMQ的consumerQueue文件和Kafka的index file作用是差不多的,都是log文件(保存真正的消息)的索引,消费的时候,都需要先读索引,再读log,这个方面,两者并没有什么不同。它们存储设计的真正的差异的是log文件的设计,RocketMQ每个Broker只有一组log文件,而Kafka是每个分区一组log文件,你可以想一下,这两种设计各有什么优点和缺点。

    另外,随机读和顺序读并没有严格的区分,不是非黑即白的。即使是最理想的顺序读,那它读第一个字节也是需要寻址的,这是不是一次随机读呢?随机读的时候,只要不是每次只读一个字节,你在读第二个字节的时候不就是顺序读吗?

    所以,不用纠结这个概念,只要我们能做到读取数据的时候,尽量读连续的整块的数据,尽量减少寻址次数,性能就会更好。

    2019-08-27
    3
    5
  • godtrue
    课后思考及问题
    kafka之所以那么快的秘密
    1:消息批处理——减少网络通信开销
    2:磁盘顺序写——减少寻道移臂开销
    3:缓存页——减少磁盘IO开销
    4:零拷贝——减少数据多次拷贝的开销
    以上基本是一个快速的数据处理组件或系统的标配了,再加上池化技术、异步化技术、不可变技术、多线程并发编程、事件驱动模型、无锁化技术。
    2019-09-24
    4
  • PeterLu
    老师您好,请教个问题:在NIO中创建缓冲区时,可以创建直接缓冲区,即ByteBuffer.allocateDirect(capacity)这里的直接缓冲区是不是就是零拷贝技术?

    作者回复: 不是,这只是使用堆外内存。

    所谓的零拷贝,Linux的系统调用是sendfile,在java中对应的方法是FileChannel.transferTo

    2019-10-28
    3
  • 长期规划
    老师,如果Pagecahe在刷入磁盘前系统崩溃了,那数据就丢了吧?这样说来,即使写了文件,也不代表持久化了

    作者回复: 如果进程崩溃是不会丢数据的,如果操作系统崩溃了,确实会丢失数据。但实际上,这个几率非常小。

    2019-09-24
    2
    2
  • linqw
    1、老师有个疑问,kafka在发送时,都会在客户端进行攒一波,然后过一定的时间,或者达到一定的大小发送出去,批量发送的时候,是把一批同一个topic下的分区的消息进行批量发送么?还是不管是属于同一分区的消息都进行批量发送,broker端是不会对批消息进行拆分成每一条,那这样消费端消费到的消息不是有可能有不是订阅的分区么?
    2、学习到现在,有个感想,很多事情看似很简单,但是实际再做的时候都没那么简单,很多都得持之以恒,多思考、多实践、多动手,不然的话很多都是看懂,真正在使用的时候还是不知道如何下手。把很多小事、简单的事情做好本身就不是个简单的事情,目前有个想法打算把开源rocketmq读完,代码上写上注释和理解。
    3、老师我一直有个疑惑点,如何才能当上架构师了,一方面硬核实力技术过硬,有整体的大局观,老师能否以你自身的经历给我们解惑下了

    作者回复: 只有相同分区的消息才能组成同一个批消息。你的第三个问题太大了,改天有时间可以专题聊一下。

    2019-08-27
    6
    2
  • timmy21
    老师,我有两个疑问想请教一下:1. 我们平常打开文件写入数据是顺序写吗?2. 还有如何进行随机写?是seek到某个位置开始写?但这样的话文件数据不是会被覆盖吗?

    作者回复: A1:是的。
    A2:是的,不同的编程语言API不太一样,但都提供了类似将指针移动到文件中某个位置的功能。
    A3:会被覆盖。

    2019-08-27
    1
    2
  • linqw
    尝试回答微微一笑的问题,老师有空帮忙看下哦
    老师好,有些疑问希望老师解答下:
    ①rocketMq有consumeQueue,存储着offset,然后通过offset去commitlog找到对应的Message。通过看rocketmq的开发文档,通过offset去查询消息属于【随机读】,offset不是存储着消息在磁盘中的位置吗?为什么属于随机读呢?
    ②rocketMq的某个topic下指定的消息队列数,指的是consumeQueue的数量吗?
    ③性能上,顺序读优于随机读。rocketMq的实现上,在消费者与commitlog之间设计了consumeQueue的数据结构,导致不能顺序读,只能随机读。我的疑惑是,rocketMq为什么不像kafka那样设计,通过顺序读取消息,然后再根据topic、tag平均分配给不同的消费者实例,,这样消息积压的时候,直接增加消费者实例就可以了,不需要增加consumeQueue,这样也可以去除consumeQueue的存在呀?我在想consumeQueue存在的意义是什么呢?
    哈哈,我的理解可能有些问题,希望老师指点迷津~
    ①顺序读写是从头开始进行读写,比随机读比,不需要进行数据的位置定位只要从头开始进行读写,随机读需要进行数据位置的定位,如果能知道位置,通过位置进行随机读也会很快,rocketmq就是这样来优化io的随机读,快速读数据不一定是顺序读,也可以根据位置的随机读。
    ②rocketmq是messageQueue的数量,老师我有个好奇点rocketmq内部为什么要分读写队列,还有messageQueue内部没有存放消息,而是由消息message存放queueId和topic,消费者在消费的时候应该会有个consumerQueue才对,但是我在rocketmq代码里没有找到。
    ③rocketmq在内部用到consumeQueue,因为consumeQueue内部无需存放真正的消息,只要存储消息在commitLog的offset的位置、消息的storeSize,每次要消费的时候只要拿到位置和大小,就可以读到消息,并且无需每次根据topic和tag进行平均分配。

    作者回复: 关于为什么分多个队列,我在之前的课程中提到过,和kafka分区一样,主要是为了能并行消费,提升消费性能。另外还有一个作用是,多个队列(分区)可以分布到多个节点上,提升主题整体的可用性。

    2019-08-28
    1
  • 海罗沃德
    Kafka既然是批量處理消息,那麼是怎麼實現Kafka的實時數據流計算呢?

    作者回复: 这里面的批量处理和大数据中讲的“流和批”是二个不同的概念。

    大数据中的“批量计算”是相对于“流计算”来说的,它指的是,一个计算任务处理一批数据,这批数据处理完了,这个计算任务就结束了。

    我们这里的说的批量处理消息,是相对一条一条处理来说的,成批的处理会显著提升性能。

    即使是在Flink或Storm这种纯正的流计算平台中,它对流数据进行传输、计算也是批量处理的。

    2019-08-27
    1
  • 业余草
    只说了它的优点,其实它的缺点也很明显。把确定也顺便解释解释。

    作者回复: 你可以分享一下,在使用Kafka的时候遇到了哪些问题。

    2019-08-27
    1
  • leslie
    老师的课程学到现在开始越来越费力了:一堂课学完笔记量已经直线上升了;对于今天的课程读完后有些困惑之处烦劳老师可以指点迷津:
        1.客户端发送者的发送给服务器端的时候:其实是写入一个Packge或者说一个log包,然后服务器端处理完这个包之后,作为一个批处理,处理完成后给客户端的消费者消费者解包之后依次获得处理结果;是这样么。
        2.关于PageCache:刘超老师的课程中曾经提及其实消息队列主要运作在缓存层,常驻缓存就是为了节约查询时间;老师早先在开课的时候提过不同的消息队列其实特性不同,Kafka擅长或者说充分利用的是PageCache,其它如RockeMQ呢?我们如何扬长避短
        主要是基于以下两方面:一方面是-其实现在大量的服务器是在云端的,无论是Amaze云、腾讯云、阿里云其实共同的特性都是CPU和IO稳定性或者使用率并非真实会引发一些看似极高的是使用率真实情况却并非有那么高,另外一方面-其实任何消息队列的推出都是基于当下,如果想基于当下的消息队列做些二次开发或者特性改进需要做些什么或者准备些什么呢?操作系统、计算机组成原理,还有什么?望老师能提点1、2.
         跟着老师学到现在发现确实学好这门课可能比老师最初说的要求还要高:老师的课程跟到现在,觉得自己已经在最初的目标的路上了,谢谢老师的提点;期待老师的后续课程。

    作者回复: 对于第一点,你的理解是没问题的。

    第二个问题,我的建议是,平时注重学习积累,哪怕我只是开发一个CRUD,也要认真的做好每个细节,把涉及到的知识搞清楚。而不是照葫芦画瓢跟网上抄一个能work的就行了。对于二次开发这个事儿,先解决目的的问题。不能为了二次开发而二次开发,一定是遇到一个什么问题,经过思考,二次开发是最佳的解决方案,这样才需要做二次开发。

    至于涉及到哪些知识,我们这门课中讲的这些基础的东西大概率你会用到,其它的可以靠日常积累和快速学习来解决。

    2019-08-27
    1
  • 付锐涛
    批量处理
    顺序操作磁盘
    缓存
    减少可减少的流程
    2019-11-11
  • 涛哥迷妹
    老师请教一下,课程最后说: 这种从文件读出数据后再通过网络发送出去的场景,并且这个过程中你不需要对这些数据进行处理,那一定要使用这个零拷贝的方法,可以有效地提升性能。
    可是我理解 kafka消费则消费过程是需要读取数据的内存处理完成后再回复消费成功消息的。为什么还能用到零拷贝技术呢?

    作者回复: Kafka在消费时,对于消息体部分的数据,是不做任何处理的,直接发送给消费者,所以可以用zerocopy。

    2019-11-06
  • 涛哥迷妹
    这篇文章很给力点赞
    2019-11-06
  • Tesla
    老师好,请问一下,kafka利用pageCache减少IO。这样消费端是不是要知道Broker保存到pageCache中的对象的内存地址呢?而它们又是两个不同的进程,内存地址是怎么传递的呢?

    作者回复: PageCache是操作系统来控制的,对应用程序来说,就是访问文件,并不需要操作“访问PageCache”的API。

    比如,你提供了一个Web服务,至于每次请求的数据是从Redis(PageCache)中拿到的,还是从MySQL(文件)拿到的,使用Web服务的客户端确定不了,也并不知道。

    2019-10-14
  • Tesla
    老师好,请问一下kafka使用顺序读写的方式,应该是在有正式数据写入之前,先在硬件上开辟一段连续的存储空间吧?等到有数据了再依次写入存储空间,就像列表需要指定对象类型和列表长度一样。那kafka是如何确定这段空间的大小呢?

    作者回复: 是的,但这个过程是自动的,不需要实现开辟好,随着写随着开辟就好,而且,实际上这片存储空间在磁盘上并不一定是连续的,具体取决于使用的文件系统。

    2019-10-14
  • 长期规划
    Kafk的实现高性能的四个方法中,Pagecache我没明白,Pagecache我知道,但这是OS控制的啊,没明白Kafka怎么利用它的
    2019-09-24
  • 非礼勿言-非礼勿听-非礼勿视
    老师好,我有个问题一直不明白,一个文件的数据应该是分散存储在磁盘上的吧(一般不太可能会是数据的位置都是连续的),读完整个文件的数据,怎么着也是需要移动磁头的吧(假如是机械盘),那么顺序读,所谓的顺序的含义是指什么?

    作者回复: 这个取决于文件系统,一般来说文件系统存储数据的单位是block,一个文件包含若干个block,文件系统一般都会尽量把一个文件的block放在一起,所以顺序读依然会比随机读快非常多。

    2019-09-23
  • 摩云神雕
    请教下老师,调用send()方法发送一条消息后,无论是同步还是异步发送,这条消息都会缓存到我本地的内存吗? 然后在合适的时间组成一批,一次发给Broker(kafka服务端)吗? 发送时机是客户端可配的吗?

    作者回复: 是的,你可以配置batch.size和linger.ms这两个参数来调整发送时机和批量大小

    2019-09-19
  • 龍蝦
    Kafka Producer 调用同步 send() 成功返回,其实没法保证消息已经成功发送到 Kafka 服务器?

    作者回复: 是这样的。
    在Kafka中,这个Send是一个异步方法。如果要确保发送成功,你必须在提供的回调方法中去检查发送结果。

    或者你也可以调用producer.send(record).get()来同步获取发送结果。

    2019-09-11
收起评论
38
返回
顶部