字节面试官: 让你设计一个MQ每秒要抗几十万并发,怎么做?

news2024/11/16 9:35:28

目录

  • 1、页缓存技术 + 磁盘顺序写
  • 2、零拷贝技术
  • 3、最后的总结

这篇文章来聊一下Kafka的一些架构设计原理,这也是互联网公司面试时非常高频的技术考点。

Kafka是高吞吐低延迟的高并发、高性能的消息中间件,在大数据领域有极为广泛的运用。配置良好的Kafka集群甚至可以做到每秒几十万、上百万的超高并发写入。

那么Kafka到底是如何做到这么高的吞吐量和性能的呢?这篇文章我们来一点一点说一下。


1、页缓存技术 + 磁盘顺序写

首先Kafka每次接收到数据都会往磁盘上去写,如下图所示。

那么在这里我们不禁有一个疑问了,如果把数据基于磁盘来存储,频繁的往磁盘文件里写数据,这个性能会不会很差?大家肯定都觉得磁盘写性能是极差的。

在这里插入图片描述

没错,要是真的跟上面那个图那么简单的话,那确实这个性能是比较差的。

但是实际上Kafka在这里有极为优秀和出色的设计,就是为了保证数据写入性能,首先Kafka是基于操作系统的页缓存来实现文件写入的。

操作系统本身有一层缓存,叫做page cache,是在内存里的缓存,我们也可以称之为os cache,意思就是操作系统自己管理的缓存。

你在写入磁盘文件的时候,可以直接写入这个os cache里,也就是仅仅写入内存中,接下来由操作系统自己决定什么时候把os cache里的数据真的刷入磁盘文件中。

仅仅这一个步骤,就可以将磁盘文件写性能提升很多了,因为其实这里相当于是在写内存,不是在写磁盘,大家看下图。

在这里插入图片描述

接着另外一个就是kafka写数据的时候,非常关键的一点,他是以磁盘顺序写的方式来写的。也就是说,仅仅将数据追加到文件的末尾,不是在文件的随机位置来修改数据。

普通的机械磁盘如果你要是随机写的话,确实性能极差,也就是随便找到文件的某个位置来写数据。

但是如果你是追加文件末尾按照顺序的方式来写数据的话,那么这种磁盘顺序写的性能基本上可以跟写内存的性能本身也是差不多的。

所以大家就知道了,上面那个图里,Kafka在写数据的时候,一方面基于了os层面的page cache来写数据,所以性能很高,本质就是在写内存罢了。


另外一个,他是采用磁盘顺序写的方式,所以即使数据刷入磁盘的时候,性能也是极高的,也跟写内存是差不多的。

基于上面两点,kafka就实现了写入数据的超高性能。

那么大家想想,假如说kafka写入一条数据要耗费1毫秒的时间,那么是不是每秒就是可以写入1000条数据?

但是假如kafka的性能极高,写入一条数据仅仅耗费0.01毫秒呢?那么每秒是不是就可以写入10万条数?

所以要保证每秒写入几万甚至几十万条数据的核心点,就是尽最大可能提升每条数据写入的性能,这样就可以在单位时间内写入更多的数据量,提升吞吐量。


2、零拷贝技术

说完了写入这块,再来谈谈消费这块。

大家应该都知道,从Kafka里我们经常要消费数据,那么消费的时候实际上就是要从kafka的磁盘文件里读取某条数据然后发送给下游的消费者,如下图所示。

那么这里如果频繁的从磁盘读数据然后发给消费者,性能瓶颈在哪里呢?

在这里插入图片描述

假设要是kafka什么优化都不做,就是很简单的从磁盘读数据发送给下游的消费者,那么大概过程如下所示:

先看看要读的数据在不在os cache里,如果不在的话就从磁盘文件里读取数据后放入os cache。

接着从操作系统的os cache里拷贝数据到应用程序进程的缓存里,再从应用程序进程的缓存里拷贝数据到操作系统层面的Socket缓存里,最后从Socket缓存里提取数据后发送到网卡,最后发送出去给下游消费。

整个过程,如下图所示:

在这里插入图片描述

大家看上图,很明显可以看到有两次没必要的拷贝吧!

一次是从操作系统的cache里拷贝到应用进程的缓存里,接着又从应用程序缓存里拷贝回操作系统的Socket缓存里。

而且为了进行这两次拷贝,中间还发生了好几次上下文切换,一会儿是应用程序在执行,一会儿上下文切换到操作系统来执行。

所以这种方式来读取数据是比较消耗性能的。

Kafka为了解决这个问题,在读数据的时候是引入零拷贝技术

也就是说,直接让操作系统的cache中的数据发送到网卡后传输给下游的消费者,中间跳过了两次拷贝数据的步骤,Socket缓存中仅仅会拷贝一个描述符过去,不会拷贝数据到Socket缓存。

大家看下图,体会一下这个精妙的过程:

在这里插入图片描述

通过零拷贝技术,就不需要把os cache里的数据拷贝到应用缓存,再从应用缓存拷贝到Socket缓存了,两次拷贝都省略了,所以叫做零拷贝。

对Socket缓存仅仅就是拷贝数据的描述符过去,然后数据就直接从os cache中发送到网卡上去了,这个过程大大的提升了数据消费时读取文件数据的性能。

而且大家会注意到,在从磁盘读数据的时候,会先看看os cache内存中是否有,如果有的话,其实读数据都是直接读内存的。

如果kafka集群经过良好的调优,大家会发现大量的数据都是直接写入os cache中,然后读数据的时候也是从os cache中读。

相当于是Kafka完全基于内存提供数据的写和读了,所以这个整体性能会极其的高。


3、最后的总结

通过这篇文章对kafka底层的页缓存技术的使用,磁盘顺序写的思路,以及零拷贝技术的运用,大家应该就明白Kafka每台机器在底层对数据进行写和读的时候采取的是什么样的思路,为什么他的性能可以那么高,做到每秒几十万的吞吐量。

这种设计思想对我们平时自己设计中间件的架构,或者是出去面试的时候,都有很大的帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/164677.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电商项目之如何迁移千万级别的数据表

1 背景 电商系统一般都会有一张表记录买家的浏览器信息,包含但不限于浏览器ip、浏览器cookie信息、浏览器user-agent、当前页面的url、当前页面的refer。买家在电商网站上每一次操作,都会记录到该表。该表的数量量至少达到千万级级别。该表有什么用处&a…

07.优雅地断开套接字连接

优雅地断开套接字连接 本章将讨论如何优雅地断开相互连接的套接字。之前用的方法不够优雅是因为,我们是调用close或closesocket函数单方面断开连接的。 基于TCP的半关闭 TCP中的断开连接过程比建立连接过程更重要,因为连接过程中一般不会出现大的变数…

八、MySQL 常用函数汇总(1)

文章目录一、函数1.1 函数简介1.2 不同DBMS函数的差异二、数学函数2.1 绝对值函数ABS(x)和返回圆周率的函数PI()2.2 平方根函数SQRT(x)和求余函数MOD(x,y)2.3 获取整数的函数CEIL(x)、CEILING(x)和FLOOR(x)2.4 获取随机数的函数RAND()和RAND(x)2.5 函数ROUND(x)、ROUND(x,y)和T…

keytool 工具介绍

使用JDK自带的 keytool 工具: 简介 keytool 命令是一个密钥和证书管理的工具。它允许用户使用数字签名管理自己的公钥/私钥对和相关证书,用于自我身份验证(向其他用户和服务验证自己)或数据完整性和身份验证服务。keytool 命令还允许用户缓存通信对等体…

【七牛云 后端】笔试面

一、选择、填空知识点整理 1. fork() 函数 fork() 函数通过系统调用创建一个与原来进程相同的进程&#xff08;如果初始参数或者传入的变量不同&#xff0c;两个进程也可以做不同的事&#xff09; 示例 —— #include <stdio.h> int main() {for(int i0; i<2; i){…

centos7 安装git

一、查看是否安装过git git --version若出现以上版本号&#xff0c;则代表已经安装了git&#xff0c;不需要再次安装了&#xff0c;git安装&#xff0c;分为用yum安装和下载git源码编译安装&#xff0c;以下两种方法&#xff1a; 二、使用yum安装git yum -y install git安装…

磨金石教育摄影技能干货分享|如何在纪实摄影中体现艺术内涵

纪实摄影往往是摄影师在生活中或者旅行中随手拍下的&#xff0c;记录人们平常的瞬间。这类摄影往往强调真实性&#xff0c;在技巧上不会过多的追求。但有时候摄影师为了体现照片中更多的内涵&#xff0c;或者个人的情感思想&#xff0c;会运用一些摄影技巧来表现。下面就让我们…

动态内存与动态内存函数详解

文章目录前言一、动态内存函数的介绍1.malloc函数2.calloc3.realloc4.free二、两种常见的内存申请方法1.返回指针2.传二级指针三.常见的动态内存错误1.对NULL指针的解引用操作2.对动态开辟空间的越界访问3.对非动态开辟内存使用free释放4.使用free释放一块动态开辟内存的一部分…

6. 描述性统计函数:summary 、Fivenum、describe、describeBy、stat.desc、 Aggregate、summaryBy

b站课程视频链接&#xff1a; https://www.bilibili.com/video/BV19x411X7C6?p1 腾讯课堂(最新&#xff0c;但是要花钱&#xff0c;我花99&#x1f622;&#x1f622;元买了&#xff0c;感觉讲的没问题&#xff0c;就是知识点结构有点乱&#xff0c;有点废话&#xff09;&…

ESP32设备驱动-ADXL345三轴加速计驱动

ADXL345三轴加速计驱动 文章目录 ADXL345三轴加速计驱动1、ADXL345介绍2、硬件准备3、软件准备4、驱动实现1、ADXL345介绍 ADXL345 是一款小型、薄型、低功耗、3 轴加速度计,具有高达 16g 的高分辨率(13 位)测量值。数字输出数据采用 16 位二进制补码格式,可通过 SPI(3 线…

C进阶:动态内存函数 malloc calloc realloc free及常见动态内存开辟错误

本文主要讲解动态内存开辟的有关知识。 目录 一.malloc 与 free 1.malloc 2.free 3.实例&#xff1a; 二.calloc 三.realloc 四.常见的动态内存错误 1.对NULL指针的解引用操作 2.对动态开辟空间的越界访问 3.对非动态开辟内存使用free释放 4.使用free释放一块动态…

springboot 构建多模块项目

新建 spring initializr 父项目 Spring 官方提供了 Spring Initializr 来引导大家快速构建一个应用项目。在此不细说。 idea 创建 1、 new – project 注意jdk版本 和 勾选 default,然后next 2、 填写项目信息 3、选择项目组成部分,也可后期加上 4、选择项目位置 --选…

Docker入门:介绍Docker的常用命令、镜像的加载原理、Dockerfile打包、Docker网络、Docker Compose容器编排+监控

Docker入门 1&#xff09;从面向对象角度来看&#xff0c;Docker利用容器&#xff08;Container&#xff09;独立运行一个或一组应用&#xff0c;应用程序或服务运行在容器里面&#xff0c;容器就类似于一个虚拟化的运行环境&#xff0c;容器是用镜像创建出来的运行实例。就像是…

区块链笔记4--BTC实现

1 UTXO &#xff1a;区块链是一个去中心化的账本&#xff0c;比特币采用了 基于交易的账本模式。然而&#xff0c;系统中并无显示记录账户包含BTC数&#xff0c;实际上其需要通过交易记录进行推算。在比特币系统中&#xff0c;全节点需要维护一个名为 UTXO(UnspentTransaction …

Java抽象类:案例、特点、模板方法模式

一.抽象类的案例 案例&#xff1a;加油站支付卡 系统需求&#xff1a; 某加油站推出了2种支付卡&#xff1a; 1、预存1万元的金卡&#xff0c;后续加油享受8折优惠&#xff1b; 2、预存5千元的银卡&#xff0c;后续加油享受8.5折优惠。 请分别实现2种卡片进入收银系统后的…

记录每日LeetCode 2293.极大极小游戏 Java实现

题目描述&#xff1a; 给你一个下标从 0 开始的整数数组 nums &#xff0c;其长度是 2 的幂。 对 nums 执行下述算法&#xff1a; 设 n 等于 nums 的长度&#xff0c;如果 n 1 &#xff0c;终止 算法过程。否则&#xff0c;创建 一个新的整数数组 newNums &#xff0c;新数组…

分享66个HTMLCSS源码,总有一款适合您

HTML&CSS源码 分享66个HTML&CSS源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;大家下载后可以看到。 源码下载链接&#xff1a;https://pan.baidu.com/s/1AeVqON7byvt-ngB_U…

位段与枚举

目录 1、位段 1、位段的声明 2、位段的内存分配特点 3、位段的跨平台问题 4、位段的应用 2、枚举 1、枚举类型的定义 2、枚举的优点 3、联合体&#xff08;共用体&#xff09; 1、联合类型的定义 2、联合体的特点即大小计算 1、位段 1、位段的声明 位段的位指的是…

Pr初识01

Pr初识1.关于Pr&#xff1a;2.项目序列3.PR工作界面4.导入素材5.制式与素材管理6.剪辑与工具7.剪辑与工具&#xff08;下&#xff09;8.工具面板与时间轴面板进阶9.关键帧动画10.视频特效11.视频特效&#xff08;下&#xff09;12.音频及结合AU去除噪音13.字幕运用1.关于Pr&…

微信小程序自定义组件、组件的生命周期和组件通信(插槽)

文章目录导航路线自定义组件组建的创建和使用1.创建组件2.引用组件3. 局部引用组件4. 全局引用组件5. 全局引用 VS 局部引用6. 组件和页面的区别样式1.组件样式隔离2. 组件样式隔离的注意点3. 修改组件的样式隔离选项4. styleIsolation 的可选值数据、方法和属性1. data 数据2.…