本文 首发于 🍀 永浩转载 请注明 来源

19、【对线面试官】kafka基础

今天要不来聊聊消息队列吧?我看你项目不少地方都写到Kafka了.你简单说明下你使用Kafka的场景吧

  1. 使用消息队列的目的总的来说可以有三种情况:解耦、异步和削峰

  2. 比如举我项目的例子吧,我现在维护一个消息管理平台系统,对外提供发送接口给各个业务方调用

  3. 他们调用接口之后,实际上『不是同步』下发了消息。

  4. 在接口处理层只是把该条消息放到了消息队列上,随后就直接返回结果给接口调用者了。

  5. 这样的好处就是:

    1)接口的吞吐量会大幅度提高(因为未做真正实际调用,接口RT会非常低)【异步】

    2)即便有大批量的消息调用接口都不会让系统受到影响(流量由消息队列承载)【削峰】

有点抽象,再举个实际案例?

  1. 又比如说,我这边还有个项目是广告订单归因工程,主要做的事情就是得到订单数据,给各个业务广告计算对应的佣金。

  2. 订单的数据是从消息队列里取出的

  3. 这样设计的好处就是:

    1)交易团队的同学只要把订单消息写到消息队列,该订单数据的Topic由各个业务方自行消费使用【解耦】【异步】

    2)即便下单QPS猛增,对下游业务无太大的感知(因为下游业务只消费消息队列的数据,不会直接影响到机器性能)【削峰】

那我想问下,你觉得为什么消息队列能削峰?或者换个问法,为什么Kafka能承载这么大的QPS?

  1. 消息队列「最核心的功能就是把生产的数据存储起来,然后给各个业务把数据再读取出来。

  2. 跟我们处理请求时不一样,我们在业务处理时可能会调别人的接口,可能会需要去查数据库…等等等一系列的操作才行

  3. 这些业务操作都是非常耗时的,像Kafka在「存储」和「读取」这个过程中又做了很多的优化

  4. 举几个例子,比如说:

    1)我们往一个Topic发送消息或者读取消息时,实际内部是多个Partition在处理【并行】

    2)在存储消息时,Kafka内部是顺序写磁盘的,并且利用了操作系统的缓冲区来提高性能【append+cache】

    3)在读写数据中也减少CPU拷贝的次数【零拷贝】

嗯,你既然提到减少CPU拷贝的次数,可以给我说下这项技术吗?

  1. 嗯,可以的,其实就是零拷贝技术。

  2. 比如我们正常调用read函数时,会发生以下的步骤(以读磁盘的数据为例):

    1)DMA把磁盘数据拷贝到读内核缓存区

    2)CPU把读内核缓冲区的数据拷贝到用户空间

  3. 正常调用write函数时,会发生以下的步骤(数据写到网卡为例):

    1)CPU把用户空间的数据拷贝到Socket内核缓存区

    2)DMA把Socket内核缓冲区的数据拷贝到网卡

  4. 可以发现完成「一次读写」需要2次DMA拷贝,2次CPU拷贝。

  5. 而DMA拷贝是省不了的,所谓的零拷贝技术就是把CPU的拷贝给省掉

  6. 并且为了避免用户进程直接操作内核,保证内核安全,应用程序在调用系统函数时,会发生上下文切换(上述的过程一共会发生4次)

  7. 目前零拷贝技术主要有:mmap和sendfile

  8. 比如说:mmap是将读缓冲区的地址和用户空间的地址进行映射,实现读内核缓冲区和应用缓冲区共享

  9. 从而减少了从读缓冲区到用户缓冲区的一次CPU拷贝

  10. 使用mmap的后一次读写就可以简化为:、

    一、DMA把硬盘数据拷贝到读内核缓冲

    二、CPU把读内核缓存区拷贝至Socket内核缓冲区。

    三、DMA把Socket内核缓冲区拷贝至网

  11. 由于读内核缓冲区与用户空间做了映射,所以会省了一次CPU拷贝

  12. 而sendfile+DMA Scatter/Gather!则是把读内核缓存区的文件描述符/长度信息发到Socket内核缓冲区,实现CPU零拷贝

  13. 使用sendfile+DMA Scatter/Gather一次读写就可以简化为:

    1)DMA把硬盘数据拷贝至读内核缓冲区

    2)CPU把读缓冲区的文件描述符和长度信息发到Socket缓冲区。

    3)DMA根据文件描述符和数据长度从读内核缓冲区把数据拷贝至网卡

  14. 回到kafka上吧

  15. 从Producer-》Broker,Kafka是把网卡的数据持久化硬盘,用的是mmap(从2次 CPU拷贝减至1次)

  16. 从Broker-》Consumer,Kafka是从硬盘的数据发送至网卡,用的是sendFile(实 现CPU零拷贝)

总结

Kafka能这么快的原因就是实现了并行、充分利用操作系统cache、顺序写和零拷贝