15 | Kafka如何实现高性能IO?
15 | Kafka如何实现高性能IO?
讲述:李玥
时长12:03大小11.03M
使用批量消息提升服务端处理能力
使用顺序读写提升磁盘 IO 性能
利用 PageCache 加速消息读写
ZeroCopy:零拷贝技术
小结
思考题
赞 38
提建议
精选留言(65)
- 钱2019-09-24课后思考及问题 kafka之所以那么快的秘密 1:消息批处理——减少网络通信开销 2:磁盘顺序写——减少寻道移臂开销 3:缓存页——减少磁盘IO开销 4:零拷贝——减少数据多次拷贝的开销 以上基本是一个快速的数据处理组件或系统的标配了,再加上池化技术、异步化技术、不可变技术、多线程并发编程、事件驱动模型、无锁化技术。展开112
- Peter2019-10-28老师您好,请教个问题:在NIO中创建缓冲区时,可以创建直接缓冲区,即ByteBuffer.allocateDirect(capacity)这里的直接缓冲区是不是就是零拷贝技术?
作者回复: 不是,这只是使用堆外内存。 所谓的零拷贝,Linux的系统调用是sendfile,在java中对应的方法是FileChannel.transferTo
共 3 条评论60 - 微微一笑2019-08-27老师好,有些疑问希望老师解答下: ①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文件,你可以想一下,这两种设计各有什么优点和缺点。 另外,随机读和顺序读并没有严格的区分,不是非黑即白的。即使是最理想的顺序读,那它读第一个字节也是需要寻址的,这是不是一次随机读呢?随机读的时候,只要不是每次只读一个字节,你在读第二个字节的时候不就是顺序读吗? 所以,不用纠结这个概念,只要我们能做到读取数据的时候,尽量读连续的整块的数据,尽量减少寻址次数,性能就会更好。
共 6 条评论37 - 每天晒白牙2019-08-27谢谢老师,今天讲到的点,我会在课下去读源码并写出文章
作者回复: 期待
24 - 龍蝦2019-09-11Kafka Producer 调用同步 send() 成功返回,其实没法保证消息已经成功发送到 Kafka 服务器?
作者回复: 是这样的。 在Kafka中,这个Send是一个异步方法。如果要确保发送成功,你必须在提供的回调方法中去检查发送结果。 或者你也可以调用producer.send(record).get()来同步获取发送结果。
共 2 条评论15 - 长期规划2019-09-24老师,如果Pagecahe在刷入磁盘前系统崩溃了,那数据就丢了吧?这样说来,即使写了文件,也不代表持久化了
作者回复: 如果进程崩溃是不会丢数据的,如果操作系统崩溃了,确实会丢失数据。但实际上,这个几率非常小。
共 8 条评论12 - linqw2019-08-271、老师有个疑问,kafka在发送时,都会在客户端进行攒一波,然后过一定的时间,或者达到一定的大小发送出去,批量发送的时候,是把一批同一个topic下的分区的消息进行批量发送么?还是不管是属于同一分区的消息都进行批量发送,broker端是不会对批消息进行拆分成每一条,那这样消费端消费到的消息不是有可能有不是订阅的分区么? 2、学习到现在,有个感想,很多事情看似很简单,但是实际再做的时候都没那么简单,很多都得持之以恒,多思考、多实践、多动手,不然的话很多都是看懂,真正在使用的时候还是不知道如何下手。把很多小事、简单的事情做好本身就不是个简单的事情,目前有个想法打算把开源rocketmq读完,代码上写上注释和理解。 3、老师我一直有个疑惑点,如何才能当上架构师了,一方面硬核实力技术过硬,有整体的大局观,老师能否以你自身的经历给我们解惑下了展开
作者回复: 只有相同分区的消息才能组成同一个批消息。你的第三个问题太大了,改天有时间可以专题聊一下。
共 8 条评论12 - leslie2019-08-27老师的课程学到现在开始越来越费力了:一堂课学完笔记量已经直线上升了;对于今天的课程读完后有些困惑之处烦劳老师可以指点迷津: 1.客户端发送者的发送给服务器端的时候:其实是写入一个Packge或者说一个log包,然后服务器端处理完这个包之后,作为一个批处理,处理完成后给客户端的消费者消费者解包之后依次获得处理结果;是这样么。 2.关于PageCache:刘超老师的课程中曾经提及其实消息队列主要运作在缓存层,常驻缓存就是为了节约查询时间;老师早先在开课的时候提过不同的消息队列其实特性不同,Kafka擅长或者说充分利用的是PageCache,其它如RockeMQ呢?我们如何扬长避短 主要是基于以下两方面:一方面是-其实现在大量的服务器是在云端的,无论是Amaze云、腾讯云、阿里云其实共同的特性都是CPU和IO稳定性或者使用率并非真实会引发一些看似极高的是使用率真实情况却并非有那么高,另外一方面-其实任何消息队列的推出都是基于当下,如果想基于当下的消息队列做些二次开发或者特性改进需要做些什么或者准备些什么呢?操作系统、计算机组成原理,还有什么?望老师能提点1、2. 跟着老师学到现在发现确实学好这门课可能比老师最初说的要求还要高:老师的课程跟到现在,觉得自己已经在最初的目标的路上了,谢谢老师的提点;期待老师的后续课程。展开
作者回复: 对于第一点,你的理解是没问题的。 第二个问题,我的建议是,平时注重学习积累,哪怕我只是开发一个CRUD,也要认真的做好每个细节,把涉及到的知识搞清楚。而不是照葫芦画瓢跟网上抄一个能work的就行了。对于二次开发这个事儿,先解决目的的问题。不能为了二次开发而二次开发,一定是遇到一个什么问题,经过思考,二次开发是最佳的解决方案,这样才需要做二次开发。 至于涉及到哪些知识,我们这门课中讲的这些基础的东西大概率你会用到,其它的可以靠日常积累和快速学习来解决。
9 - 正本·清源2020-03-20班长确实知识扎实,其实全是大学本科课本的知识在不同技术上的组合。好在这些专业课我没有逃课,哈哈
作者回复: 我怎么记得你都逃了呢?哈哈。
9 - 汤小高2020-01-04老师,如果消息是先写入page cache,再由操作系统写入磁盘的话,如果刚刚写入page cache,操作系统还没来得及写入磁盘,主机宕机了,那岂不是会丢数据? 那这样卡夫卡服务本身岂不是也会存在丢数据的情况? Kafka broker是在写入page cache就给producer 回复ack 还是操作系统将page cache写入磁盘后,如果是后者,就能保证不丢数据
作者回复: 主机宕机了,那岂不是会丢数据?是的,是存在这样的可能。 Kafka的建议是通过复制而不是刷盘来保证消息可靠性,当然你也可以配置成每条消息都同步写入磁盘log.flush.interval.messages=1,但是这样会严重降低写入性能,基本上就没法用了。
8 - 易水寒2019-09-23老师好,我有个问题一直不明白,一个文件的数据应该是分散存储在磁盘上的吧(一般不太可能会是数据的位置都是连续的),读完整个文件的数据,怎么着也是需要移动磁头的吧(假如是机械盘),那么顺序读,所谓的顺序的含义是指什么?
作者回复: 这个取决于文件系统,一般来说文件系统存储数据的单位是block,一个文件包含若干个block,文件系统一般都会尽量把一个文件的block放在一起,所以顺序读依然会比随机读快非常多。
共 4 条评论6 - timmy212019-08-27老师,我有两个疑问想请教一下:1. 我们平常打开文件写入数据是顺序写吗?2. 还有如何进行随机写?是seek到某个位置开始写?但这样的话文件数据不是会被覆盖吗?
作者回复: A1:是的。 A2:是的,不同的编程语言API不太一样,但都提供了类似将指针移动到文件中某个位置的功能。 A3:会被覆盖。
共 2 条评论6 - asdf1002019-09-07应用程序在写入文件的时候,操作系统会先把数据写入到内存中的 PageCache,然后再一批一批地写到磁盘上。读取文件的时候,也是从 PageCache 中来读取数据,这时候会出现两种可能情况。 客户端读取消息是,有个位置信息,这个信息在信息写入时,只在pagecache里出现还没有落盘时,位置信息就已经有了吗?这个位置信息怎么来的,原理又是什么?展开
作者回复: 对于消息队列中的消费位置,不同的MQ实现不一样,有的是在写入磁盘之前生成的,有的是在写入之后生成的,这个位置不是文件中的偏移量,一般是一个逻辑位置,含义是:“这个分区中的第几条消息”。 而数据在文件中的位置,是在写入之前就确定的,不管你用什么语言,写文件最终大多使用的是2个系统调用write或者pwrite,在调用这两个方法之前,其实位置已经是确定了。 PageCache映射的是文件中的一部分数据,那这些数据必然有一个固定地址(无论数据是否已经写到磁盘上了),否则操作系统也没办法做这个映射。
5 - 康师傅2019-09-02请教一下 我的理解是:顺序写是针对某个分区而言的,那么如果单个节点上的topic数量很多,或者分区数很多,从整体来看应该还是会有很多的随机IO,因为会切换写不同的文件,这种情况下整体性能是不是就不高了? 这种场景下,除了增加节点,将分区分布到多个节点上,是否还有其他有效提升性能的办法?展开
作者回复: 是的,所以Kafka在分区非常多的情况下,性能是不如RocketMQ的。这种情况,除了想办法减少一些分区,确实没什么好的办法。
5 - 摩云神雕2019-09-19请教下老师,调用send()方法发送一条消息后,无论是同步还是异步发送,这条消息都会缓存到我本地的内存吗? 然后在合适的时间组成一批,一次发给Broker(kafka服务端)吗? 发送时机是客户端可配的吗?
作者回复: 是的,你可以配置batch.size和linger.ms这两个参数来调整发送时机和批量大小
4 - 海罗沃德2019-08-27Kafka既然是批量處理消息,那麼是怎麼實現Kafka的實時數據流計算呢?
作者回复: 这里面的批量处理和大数据中讲的“流和批”是二个不同的概念。 大数据中的“批量计算”是相对于“流计算”来说的,它指的是,一个计算任务处理一批数据,这批数据处理完了,这个计算任务就结束了。 我们这里的说的批量处理消息,是相对一条一条处理来说的,成批的处理会显著提升性能。 即使是在Flink或Storm这种纯正的流计算平台中,它对流数据进行传输、计算也是批量处理的。
4 - 看不到de颜色2019-09-05有一点疑惑还请老师解答一下。kafka为了保证消息丢失,客户端在发送消息时有三种acks可供选择。那如果kafka消息客户端都采用异步批量发送,那这三种参数还有意义吗?
作者回复: 我在之前的课中讲到过,在发送端,你需要在发送消息之后,检查发送结果,如果发送失败再进行重试或者执行其他的补偿。 这个原则同样适用于Kafka,并且和是否批量发送没关系,也和同步发送还是异步发送也没关系。 即使是异步发送,或者批量发送,只要你检查了发送结果(异步发送需要在回调方法中检查结果),并且发送结果是发送成功,就可以保证消息不丢。
3 - 鲁班大师2020-05-27老师,我理解只要使用了nio就自动使用了零拷贝
作者回复: 所谓零拷贝,主要指的是sendfile这个系统调用。 在*nix上,你都可以用man sendfile来查看详细的说明。 和NIO并不是一回事儿。
2 - Ryoma2020-03-13前面提到发消息时可以利用 key 保证分区有序,之前的想法是消息发到服务端,服务端根据 key 做 hash 来分配到对应分区;但按照批处理消息的说明,明显不会分解消息。 又去看了使用的 node 客户端,果然这部分是在客户端做的 hash。2
- 又双叒叕是一年啊2019-11-06老师请教一下,课程最后说: 这种从文件读出数据后再通过网络发送出去的场景,并且这个过程中你不需要对这些数据进行处理,那一定要使用这个零拷贝的方法,可以有效地提升性能。 可是我理解 kafka消费则消费过程是需要读取数据的内存处理完成后再回复消费成功消息的。为什么还能用到零拷贝技术呢?
作者回复: Kafka在消费时,对于消息体部分的数据,是不做任何处理的,直接发送给消费者,所以可以用zerocopy。
2