Kafka高吞吐量的原因

ops/2024/9/20 2:06:38/ 标签: kafka, 分布式

文章目录

  • 生产者(写入数据)
    • 顺序写入
    • Memory Mapped Files
  • 消费者(读取数据)
    • Kafka是如何巧妙设计的?
  • 总结

众所周知kafka的吞吐量比一般的消息队列要高,号称the fastest,那他是如何做到的,让我们从以下几个方面分析一下原因。

生产者(写入数据)

生产者(producer)是负责向Kafka提交数据的,我们先分析这一部分。
Kafka会把收到的消息都写入到硬盘中,它绝对不会丢失数据。为了优化写入速度Kafak采用了两个技术,顺序写入和MMFile。

顺序写入

因为硬盘是机械结构,每次读写都会寻址->写入,其中寻址是一个“机械动作”,它是最耗时的。所以硬盘最“讨厌”随机I/O,最喜欢顺序I/O。为了提高读写硬盘的速度,Kafka就是使用顺序I/O。
在这里插入图片描述

上图就展示了Kafka是如何写入数据的,每一个Partition其实都是一个文件,收到消息后Kafka会把数据插入到文件末尾(虚框部分)。
这种方法有一个缺陷——没有办法删除数据,所以Kafka是不会删除数据的,它会把所有的数据都保留下来,每个消费者(Consumer)对每个Topic都有一个offset用来表示读取到了第几条数据。
在这里插入图片描述

上图中有两个消费者,Consumer1有两个offset分别对应Partition0、Partition1(假设每一个Topic一个Partition);Consumer2有一个offset对应Partition2。这个offset是由客户端SDK负责保存的,Kafka的Broker完全无视这个东西的存在;一般情况下SDK会把它保存到zookeeper里面。(所以需要给Consumer提供zookeeper的地址)。
如果不删除硬盘肯定会被撑满,所以Kakfa提供了两种策略来删除数据。一是基于时间,二是基于partition文件大小。具体配置可以参看它的配置文档。

Memory Mapped Files

即便是顺序写入硬盘,硬盘的访问速度还是不可能追上内存。所以Kafka的数据并不是实时的写入硬盘,它充分利用了现代操作系统分页存储来利用内存提高I/O效率。
Memory Mapped Files(后面简称mmap)也被翻译成内存映射文件,在64位操作系统中一般可以表示20G的数据文件,它的工作原理是直接利用操作系统的Page来实现文件到物理内存的直接映射。完成映射之后你对物理内存的操作会被同步到硬盘上(操作系统在适当的时候)。

在这里插入图片描述

通过mmap,进程像读写硬盘一样读写内存(当然是虚拟机内存),也不必关心内存的大小有虚拟内存为我们兜底。
使用这种方式可以获取很大的I/O提升,省去了用户空间到内核空间复制的开销(调用文件的read会把数据先放到内核空间的内存中,然后再复制到用户空间的内存中。)也有一个很明显的缺陷——不可靠,写到mmap中的数据并没有被真正的写到硬盘,操作系统会在程序主动调用flush的时候才把数据真正的写到硬盘。Kafka提供了一个参数——producer.type来控制是不是主动flush,如果Kafka写入到mmap之后就立即flush然后再返回Producer叫同步(sync);写入mmap之后立即返回Producer不调用flush叫异步(async)。
mmap其实是Linux中的一个函数就是用来实现内存映射的,谢谢Java NIO,它给我提供了一个mappedbytebuffer类可以用来实现内存映射(所以是沾了Java的光才可以如此神速和Scala没关系!!)

消费者(读取数据)

Kafka使用磁盘文件还想快速?这是我看到Kafka之后的第一个疑问,ZeroMQ完全没有任何服务器节点,也不会使用硬盘,按照道理说它应该比Kafka快。可是实际测试下来它的速度还是被Kafka“吊打”。“一个用硬盘的比用内存的快”,这绝对违反常识;如果这种事情发生说明——它作弊了。
没错,Kafka“作弊”。无论是顺序写入还是mmap其实都是作弊的准备工作。
如何提高Web Server静态文件的速度 ?
仔细想一下,一个Web Server传送一个静态文件,如何优化?答案是zero copy。传统模式下我们从硬盘读取一个文件是这样的

在这里插入图片描述

先复制到内核空间(read是系统调用,放到了DMA,所以用内核空间),然后复制到用户空间(1,2);从用户空间重新复制到内核空间(你用的socket是系统调用,所以它也有自己的内核空间),最后发送给网卡(3、4)。

在这里插入图片描述

Zero Copy中直接从内核空间(DMA的)到内核空间(Socket的),然后发送网卡。
这个技术非常普遍,The C10K problem 里面也有很详细的介绍,Nginx也是用的这种技术,稍微搜一下就能找到很多资料。
Java的NIO提供了FileChannle,它的transferTo、transferFrom方法就是Zero Copy。

Kafka是如何巧妙设计的?

想到了吗?Kafka把所有的消息都存放在一个一个的文件中,当消费者需要数据的时候Kafka直接把“文件”发送给消费者。这就是秘诀所在,比如:10W的消息组合在一起是10MB的数据量,然后Kafka用类似于发文件的方式直接扔出去了,如果消费者和生产者之间的网络非常好(只要网络稍微正常一点10MB根本不是事。。。家里上网都是100Mbps的带宽了),10MB可能只需要1s。所以答案是——10W的TPS,Kafka每秒钟处理了10W条消息。
可能你说:不可能把整个文件发出去吧?里面还有一些不需要的消息呢?是的,Kafka作为一个“高级作弊分子”自然要把作弊做的有逼格。Zero Copy对应的是sendfile这个函数(以Linux为例),这个函数接受

  • out_fd作为输出(一般及时socket的句柄)
  • in_fd作为输入文件句柄
  • off_t表示in_fd的偏移(从哪里开始读取)
  • size_t表示读取多少个

没错,Kafka是用mmap作为文件读写方式的,它就是一个文件句柄,所以直接把它传给sendfile;偏移也好解决,用户会自己保持这个offset,每次请求都会发送这个offset。(还记得吗?放在zookeeper中的);数据量更容易解决了,如果消费者想要更快,就全部扔给消费者。如果这样做一般情况下消费者肯定直接就被压死了;所以Kafka提供了的两种方式——Push,我全部扔给你了,你死了不管我的事情;Pull,好吧你告诉我你需要多少个,我给你多少个。

总结

Kafka速度的秘诀在于,它把所有的消息都变成一个的文件。通过mmap提高I/O速度,写入数据的时候它是末尾添加所以速度最优;读取数据的时候配合sendfile直接暴力输出。阿里的RocketMQ也是这种模式,只不过是用Java写的。
单纯的去测试MQ的速度没有任何意义,Kafka这种“暴力”、“流氓”、“无耻”的做法已经脱了MQ的底裤,更像是一个暴力的“数据传送器”。所以对于一个MQ的评价只以速度论英雄,世界上没人能干的过Kafka,我们设计的时候不能听信网上的流言蜚语——“Kafka最快,大家都在用,所以我们的MQ用Kafka没错”。在这种思想的作用下,你可能根本不会关心“失败者”;而实际上可能这些“失败者”是更适合你业务的MQ。


http://www.ppmy.cn/ops/110649.html

相关文章

产品探秘|开物——面向AI原生和云原生网络研究的首选科研平台

在当今高速发展的信息技术领域,特别是对于那些致力于前沿科技探索与实践的高校而言,拥有一款能够支持复杂网络业务研究与开发的平台至关重要。开物™数据网络开发平台(Data Network Development Platform,简称DNDP)&am…

[WEBPWN]BaseCTF week1 题解(新手友好教程版)

WEB A Dark Room 这道题的考点是查看网页源代码 网页源代码这里看到的是网页的html css js在用户浏览器上执行的代码 有时候很多铭感信息,或者关键信息。 查看网页源代码的几种方式 1 右键点击查看网页源代码 2 F12 3 Ctrl U 快捷键 HTTP是什么 HTTP&#x…

ip属地河北切换北京

我们知道,每当电脑或手机连接网络时,都会分配到一个网络IP地址,这个IP地址通常与设备所在的地区网络相关联。然而,出于业务或个人需求,有时我们需要将本机的IP地址切换到其他城市。例如要将IP属地河北切换北京&#xf…

主流日志框架Logback与Log4j2

一、Logback 1、介绍 Logback是由log4j创始人设计的又一个开源日志组件。 Logback当前分成三个模块:logback-core,logback- classic和logback-access logback-core是其它两个模块的基础模块,类似与springframework logback-classic是log…

项目——负载均衡OJ

项目要实现的一个整体的功能: 编写一个在线OJ网络服务器,只实现类似 leetcode 的题目列表在线编程功能 项目宏观结构: Oj服务器在收到提交的代码时,把代码负载均衡的选择发送给其他几个编译与运行服务器去编译运行代码,判断代码的编译运行结…

python打包工具Nuitka使用介绍

首先说一下,为什么我选择Nuitka而不是pyinstaller? Nuitka相对pyinstaller有以下优点: 1. Nuitka能够对 Python 代码进行深度分析,并在此基础上生成优化后的 C 语言代码会针对生成的 C 代码进行更多的优化,这意味着生…

java面试题-Sql 语句的执行顺序

远离八股文,面试大白话,通俗且易懂 看完后试着用自己的话复述出来。有问题请指出,有需要帮助理解的或者遇到的真实面试题不知道怎么总结的也请评论中写出来,大家一起解决。 java面试题汇总-目录-持续更新中 Sql 语句的执行顺序 fr…

Ubuntu22.04安装nginx

1.安装nginx 首先,更新你的包索引: sudo apt update 安装必要的软件包以允许apt通过HTTPS使用仓库: sudo apt install ca-certificates curl gnupg lsb-release 添加Nginx官方的GPG密钥: curl -fsSL https://nginx.org/keys/ng…

简单计算机网络概念

1.浏览器过程 输入url,解析url 1.协议http、https的区别;HTTPS就是在HTTP与TCP之间增加了SSL/TSL安全传输层 2.格式:协议//主机:端口/路径; 3.HTTP版本:1.0和1.1 4.HTTP/1.1:1. 持久连接:为了…

下一代 AI 教育:知识图谱RAG + 多智能体,听老师的话没前途,让老师听你的才是正道

下一代 AI 教育:知识图谱RAG 多智能体,听老师的话没前途,让老师听你的才是正道 下一代 AI 教育:基于最本质的用脑方式学习 理解 记忆?学习的 3 个层次文科:关联理解 关联分析 关联记忆秒背古诗古文商业…

Redis之pipeline与事务

前言 Redis使用的是单reactor网络模型,也就是io多路复用非阻塞io的异步处理流程(注册事件,在事件循环callback处理事件)。我们可以将每个连接抽象看成一个pipe,哪个pipe中的数据先满就先处理。注意,单react…

数组与贪心算法——215、75、324、517(3中1难)

215. 数组中的第K个最大元素(中等) 给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。 请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 解法…

CSP-J 算法基础 排序算法的基本概念

文章目录 前言排序算法的稳定性稳定排序算法的例子不稳定排序算法的例子总结 有序度和逆序度有序度(Sortedness)逆序度(Inversion Count)计算逆序度的例子 总结 满有序度计算公式解释举个例子总结 总结 前言 排序算法是计算机科学…

Ubuntu 常用指令和作用解析

Ubuntu 常用指令和作用解析 Ubuntu 是一种常见的 Linux 发行版,它利用了 Unix 的力量和开源软件的精神。掌握常用指令可以提高我们在使用 Ubuntu 时的效率。本文将介绍一些常见的指令及其用途。 目录 更新与安装软件文件与目录操作系统信息与资源监控用户与权限管…

【贪心算法】贪心算法

贪心算法简介 1.什么是贪心算法2.贪心算法的特点3.学习贪心的方向 点赞👍👍收藏🌟🌟关注💖💖 你的支持是对我最大的鼓励,我们一起努力吧!😃😃 1.什么是贪心算法 与其说是…

认识泛型和包装类

认识泛型和包装类 包装类基本数据类型和对应的包装类装箱和拆箱自动装箱和自动拆箱 什么是泛型引出泛型语法 泛型类的使用语法示例类型推导 裸类型(Raw Type)说明 泛型如何编译的擦除机制 泛型的上界语法示例复杂示例 泛型方法定义方法示例使用类型推导和不用类型推导静态的泛型…

go语言给结构体绑定方法

定义结构体person,里面有一个字段Name。因为person首字母小写,没有暴露,所以定义函数NewPerson,返回一个person指针。 package test_utils import ("fmt" )type person struct{Name string } func (p person) Test(){fmt.Println(…

Leetcode面试经典150题-141.环形链表

题目比较简单,重点是理解思想 解法都在代码里,不懂就留言或者私信 /*** Definition for singly-linked list.* class ListNode {* int val;* ListNode next;* ListNode(int x) {* val x;* next null;* }* }*/ public…

sql severs 递归查询

在sqlsevers 里面 WITH RECURSIVE 语句(在SQL Server中,通常使用 WITH 语句的公用表表达式(CTE)来实现递归查询),来处理这类查询 假设你有一个简单的BOM表结构,它可能包括以下几个字段&#xf…

Python中的“异常”之旅:探索异常处理的艺术

在编程的世界里,错误如同旅途中的意外,总是不期而遇。Python,这门优雅的语言,赋予了我们优雅地处理这些“不速之客”的能力——异常处理机制。本文将带你深入了解Python中的各种异常类型,不仅限于理论上的讲解&#xf…