一文详解 JuiceFS 读性能:预读、预取、缓存、FUSE 和对象存储

news2024/11/15 21:57:41

在高性能计算场景中,往往采用全闪存架构和内核态并行文件系统,以满足性能要求。随着数据规模的增加和分布式系统集群规模的增加,全闪存的高成本和内核客户端的运维复杂性成为主要挑战。

JuiceFS,是一款全用户态的云原生分布式文件系统,通过分布式缓存大幅提升 I/O 吞吐量,并使用成本较低的对象存储来完成数据存储,适用于大规模 AI 业务。

JuiceFS 数据读取流程从客户端的读请求开始,然后再经过 FUSE 发送给 JuiceFS 客户端,通过预读缓冲层,接着进入缓存层,最终访问对象存储。为了提高读取效率,JuiceFS 在其架构设计中采用了包括数据预读、预取和缓存在内的多种策略。

本文将详细解析这些策略的工作原理,并分享我们在特定场景下的测试结果,以便读者深入理解 JuiceFS 的性能优势及一些相关的限制,从而更有效地应用于各种使用场景。

鉴于文章内容的深度和技术性,需要读者有一定操作系统知识,建议收藏以便在需要时进行仔细阅读。

01 JuiceFS 架构简介

JuiceFS 社区版架构分为客户端、数据存储和元数据三部分。 数据访问支持多种接口,包括 POSIX 、HDFS API、S3 API,还有 Kubernetes CSI,以满足不同的应用场景。在数据存储方面,JuiceFS 支持几十种对象存储,包括公共云服务和自托管解决方案,如 Ceph 和 MinIO。元数据引擎支持多种常见的数据库,包括 Redis、TiKV 和 MySQL 等。

企业版与社区版的主要区别在图片左下角元数据引擎和数据缓存的处理。企业版包括一个自研的分布式元数据引擎,并支持分布式缓存,社区版只支持本地缓存。

02 Linux 中关于“读”的几个概念

在 Linux 系统中,数据读取主要通过几种方式实现:

  • Buffered I/O:这是标准的文件读取方式,数据会通过内核缓冲区,并且内核会进行预读操作,以优化读取效率;
  • Direct I/O:允许绕过内核缓冲区直接进行文件 I/O 操作,以减少数据拷贝和内存占用,适合大量数据传输;
  • Asynchronous I/O:通常与 Direct I/O 一起使用。它允许应用程序在单个线程中发出多个 I/O 请求,而不必等待每个请求完成,从而提高 I/O 并发性能;
  • Memory Map:将文件映射到进程的地址空间,可以通过指针直接访问文件内容。通过内存映射,应用程序可以像访问普通内存一样访问映射的文件区域,由内核自动处理数据的读取和写入。

几种主要的读取模式及它们对存储系统带来的挑战:

  • 随机读取,包括随机大 I/O 读和随机小 I/O 读,主要考验存储系统的延迟和 IOPS。
  • 顺序读取,主要考验存储系统的带宽。
  • 大量小文件读取,主要考验存储系统的元数据引擎的性能和系统整体的 IOPS 能力。

03 JuiceFS 读流程原理解析

JuiceFS 采用了文件分块存储的策略。 一个文件首先逻辑上被分割成若干个 chunk,每个 chunk 固定大小为 64MB。每个 chunk 进一步被细分为若干个 4MB 的 block,block 是对象存储中的实际存储单元,JuiceFS 的设计中有不少性能优化措施与这个分块策略紧密相关。(进一步了解 JuiceFS 存储模式)。 为了优化读取性能, JuiceFS 采取了预读、预取与缓存等多种优化方案。

预读 readahead

预读(readahead):通过预测用户未来的读请求,提前从对象存储中加载数据到内存中,以降低访问延迟,提高实际 I/O 并发。下面这张图是一张简化的读取流程的示意图。虚线以下代表应用层,虚线以上是内核层。

当用户进程(左下角标蓝色的应用层) 发起文件读写的系统调用时,请求首先通过内核的 VFS,然后传递给内核的 FUSE 模块,经过 /dev/fuse 设备与 JuiceFS 的客户端进程通信。

右下角所示的流程是后续在 JuiceFS 中进行的预读优化。系统通过引入“session” 跟踪一系列连续读。每个 session 记录了上一次读取的偏移量、连续读取的长度以及当前预读窗口大小,这些信息可用于判断新来的读请求是否命中这个 session,并自动调整/移动预读窗口。 通过维护多个 session,JuiceFS 还能轻松支持高性能的并发连续读。

为了提升连续读的性能,在系统设计中,我们增加了提升并发的措施。具体来说,预读窗口中的每一个 block (4MB) 都会启动一个 goroutine 来读数据。 这里需要注意的是,并发数会受限于 buffer-size 参数。在默认 300MB 设置下,理论最大对象存储并发数为 75(300MB 除以 4MB),这个设置在一些高性能场景下是不够的,用户需要根据自己的资源配置和场景需求去调整这个参数,下文中我们也对不同参数进行了测试。

以下图第二行为例,当系统接收到连续的第二个读请求时,实际上会发起一个包含预读窗口和读请求的连续三个数据块的请求。按照预读的设置,接下来的两个请求都会直接命中预读的 buffer 并被立即返回。

如果第一个和第二个请求没有被预读,而是直接访问对象存储,延迟会比较高(通常大于10ms)。而当延迟降低在 100 微秒以内,则说明这个 I/O 请求成功使用了预读,即第三个和第四个请求,直接命中了内存中预读的数据

预取 prefetch

预取(prefetch):当随机读取文件中的一小段数据时,我们假设这段数据附近的区域也可能会被读取,因此客户端会异步将这一小段数据所在的整个 block 下载下来。

但是在有些场景,预取这个策略不适用,例如应用对大文件进行大幅偏移的、稀疏的随机读取,预取会访问到一些不必要的数据,导致读放大。因此,用户如果已经深入了解应用场景的读取模式,并确认不需要预取,可以通过 --prefetch=0 禁用该行为。

缓存 cache

在之前的一次分享中,我们的架构师高昌健详细介绍了 JuiceFS的缓存机制,或查看缓存文档。 在这篇文章中,对于缓存的介绍会以基本概念为主。

页缓存 page cache

页缓存(page cache)是 Linux 内核提供的机制。它的核心功能之一就是预读(readahead),它通过预先读取数据到缓存中,确保在实际请求数据时能够快速响应。

进一步,页缓存(page cache)在特定场景下的应用也非常关键,例如在处理随机读操作时,如果用户能策略性地使用页缓存,将文件数据提前填充至进页缓存,如内存空闲的情况下提前完整连续读一遍文件,可以显著提高后续随机读的性能,从而极大地提升业务整体性能。

本地缓存 local cache

JuiceFS 的本地缓存可以利用本地内存或本地磁盘保存 block,从而在应用访问这些数据时可以实现本地命中,降低网络时延并提升性能。我们通常推荐使用高性能 SSD。数据缓存的默认单元是一个 block,大小为 4MB,该 block 会在首次从对象存储中读取后异步写入本地缓存。

关于本地缓存的配置,如 --cache-dir--cache-size 等细节,企业版用户可以查看文档。

分布式缓存 cache group

分布式缓存是企业版的一个重要特性。与本地缓存相比,分布式缓存将多个节点的本地缓存聚合成同一个缓存池,提高缓存的命中率。但由于分布式缓存增加了一次网络请求,这导致其在时延上通常稍高于本地缓存,分布式缓存随机读延迟一般是 1-2ms,而本地缓存随机读延迟一般是 0.2-0.5ms。关于分布式缓存具体架构,可以查看官网文档。

04 FUSE & 对象存储的性能表现

JuiceFS 的读请求都要经过 FUSE,数据要从对象存储读取,因此理解 FUSE 和对象存储的性能表现是理解 JuiceFS 性能表现的基础。

关于 FUSE 的性能

我们对 FUSE 性能进行了两组测试。测试场景是当 I/O 请求到达 FUSE 挂载进程后,数据被直接填充到内存中并立即返回。测试主要评估 FUSE 在不同线程数量下的总带宽,单个线程平均带宽以及CPU使用情况。硬件方面,测试 1 是 Intel Xeon 架构,测试 2 则是 AMD EPYC 架构。

ThreadsBandwidth(GiB/s)Bandwidth per Thread (GiB/s)CPU Usage(cores)
17.957.950.9
215.47.71.8
320.96.92.7
427.66.93.6
6437.25.3
8556.97.1
1069.66.968.6
1590613.6
201045.218
251024.0822.6
3098.53.2827.4

FUSE 性能测试 1, 基于 Intel Xeon CPU 架构

  • 在单线程测试中,最大带宽达到 7.95GiB/s,同时 CPU 使用量不到一个核;
  • 随着线程数增加,带宽基本实现线性扩展,当线程数增加到 20 时,总带宽增加到 104 GiB/s;

此处,用户需要特别注意的是,相同 CPU 架构下使用不同硬件型号、不同操作系统测得的 FUSE 带宽表现都有可能不同。我们使用过多种机型进行测试,在其中一种机型上测得的最大单线程带宽仅为 3.9GiB/s。

ThreadsBandwidth(GiB/s)Bandwidth per Thread (GiB/s)CPU Usage(cores)
13.53.51
26.33.151.9
39.53.162.8
49.72.433.8
614.02.335.7
817.02.137.6
1018.61.99.4
15211.413.7

FUSE 性能测试 2, 基于 AMD EPYC CPU 架构

  • 在测试 2 中,带宽不能线性扩展,特别是当并发数量达到 10 个时,每个并发的带宽不足 2GiB/s;

在多并发情况下,测试 2( EPYC 架构)带宽峰值约为 20GiBps;测试 1(Intel Xeon 架构)表现出更高的性能空间,峰值通常在 CPU 资源被完全占用后出现,这时应用进程和 FUSE 进程的 CPU 都达到了资源极限。

在实际应用中,由于各个环节的时间开销,实际的 I/O 性能往往会低于上述测试峰值 3.5GiB/s。例如,在模型加载的场景中,加载 pickle 格式的模型文件,通常单线程带宽只能达到 1.5 到 1.8GiB/s。这主要是因为读取 pickle 文件的同时,要进行数据反序列化,还会遇到 CPU 单核处理的瓶颈。即使是不经过 FUSE,直接从内存读取的情况下,带宽也最多只能达到 2.8GiB/s。

关于对象存储的性能

我们使用 juicefs objbench 工具进行测试,测试涵盖了单并发、10 并发、200 并发以及 800 并发的不同负载。用户需要注意的是,不同对象存储的性能差距可能很大。

上传带宽 upload objects- MiB/s下载带宽 download objects MiB/s上传平均耗时 ms/object下载平均耗时 ms/object
单并发32.8940.46121.6398.85ms
10 并发332.75364.8210.0210.96
200 并发5590.263551.650671.13
800 并发8270.284038.410.480.99

当我们增加对象存储 GET 操作的并发数到 200 和 800 后,才能够达到非常高的带宽。这说明直接从对象存储上读数据时,单并发带宽非常有限,提高并发对整体的带宽性能至关重要。

05 连续读与随机读测试

为了给大家提供一个直观的基准参考,我们使用 fio 工具测试了 JuiceFS 企业版在连续读取和随机读场景下的性能。

连续读

从下图可以看到 99% 的数据都小于 200 微秒。在连续读场景下,预读窗口总能很好地发挥作用,因此延迟很低。

同时,我们也能通过加大预读窗口,以提高 I/O 并发,从而提升带宽。当我们将 buffer-size 从默认 300MiB 调整为 2GiB 后,读并发不再受限,读带宽从 674MiB/s 提升到了 1418 MiB/s,此时达到单线程 FUSE 的性能峰值,进一步提高带宽需要提高业务代码中 I/O 并发度。

buffer-size带宽
300MiB674MiB/s
2GiB1418MiB/s

不同 buffer-size 带宽性能测试(单线程)

当提高业务线程数到 4 线程时,带宽能达到 3456MiB/s;16 线程时,带宽达到了 5457MiB/s,此时网络带宽已经达到饱和。

buffer-size带宽
1线程1418MiB/s
4线程3456MiB/s
16线程5457MiB/s

不同线程数量下带宽性能测试 (buffer-size:2GiB)

随机读

对于小 I/O 随机读,其性能主要由延迟和 IOPS 决定,由于总 IOPS 能够通过增加节点线性扩展,所以我们先关注单节点上的延迟数据。

“FUSE 数据带宽”是指通过 FUSE 层传输的数据量,代表用户应用实际可观察和操作的数据传输速率;“底层数据带宽”则指的存储系统本身在物理层或操作系统层面处理数据的带宽。

从表格中可以看到与穿透到对象存储相比,命中本地缓存和分布式缓存的情况下,延迟都更低,当我们需要优化随机读延迟的时候就需要考虑提高数据的缓存命中率。同时,我们也能看到使用异步 I/O 接口及提高线程数可以大大提高 IOPS

不同于小 I/O 的场景,大 I/O 随机读场景还要注意读放大问题。如下表所示,底层数据带宽高于 FUSE 数据带宽,这是因为预读的作用,实际的数据请求会比来自于应用的数据请求多1-3倍,此时可以尝试关闭 prefetch 并调整最大预读窗口来调优。

分类FUSE 数据带宽底层数据带宽
1MB buffered IO92MiB290MiB
2MB buffered IO155MiB435MiB
4MB buffered IO181MiB575MiB
1MB direct IO306MiB306MiB
2MB direct IO199MiB340MiB
4MB direct IO245MiB735MiB

JuiceFS(开启分布式缓存) 大 I/O 随机读测试结果

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

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

相关文章

[240726] Mistral AI 发布新一代旗舰模型 | Node.js 合并 TypeScript 文件执行提案

目录 Mistral AI 发布新一代旗舰模型:Mistral Large 2Node.js 合并 TypeScript 文件执行提案:--experimental-strip-types Mistral AI 发布新一代旗舰模型:Mistral Large 2 Mistral AI 宣布推出新一代旗舰模型 Mistral Large 2,该…

ubuntu20.04 安装vscode 并且配置环境

目录 1.下载 2.安装 3.装插件,配置环境 1.下载 打开浏览器,进入vscode主页 Visual Studio Code - Code Editing. Redefined 2.安装 双击安装包 安装 安装完成后,我们打开vscode 3.装插件,配置环境 打开后我们 ctrlj 打开终…

操作系统的底层管理

一、冯诺依曼体系结构 我们常见的计算机,如笔记本和我们不常见的计算机,如服务器大多都遵循冯诺依曼体系结构。 根据冯诺依曼结构 ,我们可以了解到计算机是由一个个硬件组成,共分为三部分:输入、内存/CPU和输出。 如果…

【odoo17 | Owl】前端js钩子调用列表选择视图

概要 在我们选择多对一或者多对多字段的时候,经常看到可以弹出列表弹窗让人一目了然的效果,效果如下: 那么,这种效果是odoo本身封装好的组件,我们在平时的前端界面开发的时候,既不是后端视图的情况下&#…

title可修改点击展示input

<spanv-if"isEdit"click.stop"headerClick(activityForm.activityName)"><span>課程名稱{{ activityForm.activityName}}</span><el-buttonlinktype"primary"style"color: #1d2129"click"editCourseName&qu…

STM32存储左右互搏 QSPI总线读写64 Mbit容量SRAM VTI7064

STM32存储左右互搏 QSPI总线读写64 Mbit容量SRAM VTI7064 QSPI&#xff08;Quad-SPI&#xff09;设备有两种常见操作模式&#xff0c;一种QSPI设备上电后直接进入QSPI模式&#xff0c;操作时命令&#xff0c;地址和数据都是多线传输。另一种QSPI设备上电后进入常规SPI操作模式…

谷粒商城实战笔记-踩坑-跨域问题

一&#xff0c;When allowCredentials is true, allowedOrigins cannot contain the special value “*” since that cannot be set on the “Access-Control-Allow-Origin” response header. To allow credentials to a set of origins, list them explicitly or consider u…

shell-awk文本处理工具

1、awk概述 AWK 是一种处理文本文件的语言&#xff0c;是一个强大的文本分析工具。 它是专门为文本处理设计的编程语言&#xff0c;也是行处理软件&#xff0c;通常用于扫描、过滤、统计汇总工作 数据可以来自标准输入也可以是管道或文件 在 linux 上常用的是 gawk,awk …

PyTorch+AlexNet代码实训

参考文章&#xff1a;https://blog.csdn.net/red_stone1/article/details/122974771 数据集&#xff1a; 打标签&#xff1a; import os# os.path.join: 每个参数都是一个路径段&#xff0c;将它们连接起来形成有效的路径名。 train_txt_path os.path.join("data"…

Bazaar v1.4.3 任意文件读取漏洞复现(CVE-2024-40348)

0x01 产品简介 Bazarr是Sonarr和Radarr的配套应用程序&#xff0c;可根据您的要求管理和下载字幕。 0x02 漏洞概述 Bazarr存在任意文件读取漏洞&#xff0c;该漏洞是由于Bazaar v1.4.3的组件/api/swaggerui/static中存在一个问题&#xff0c;允许未经身份验证的攻击者可利用…

硅纪元AI应用推荐 | 豆包整容成了浏览器,让你的电脑秒变AI PC

“硅纪元AI应用推荐”栏目&#xff0c;为您精选最新、最实用的人工智能应用&#xff0c;无论您是AI发烧友还是新手&#xff0c;都能在这里找到提升生活和工作的利器。与我们一起探索AI的无限可能&#xff0c;开启智慧新时代&#xff01; 亲爱的技术宅们、办公高手们&#xff0c…

Tomcat项目本地部署

今天来分享一下如何于本机上在不适用idea等辅助工具的前提下&#xff0c;部署多个tomcat的web项目 我这里以我最近写的SSM项目哈米音乐为例&#xff0c;简单介绍一下项目的大致组成&#xff1a; 首先&#xff0c;项目分为4个模块&#xff0c;如下图所示&#xff1a; 其中&…

SQL 语句中的字符串有单引号导致报错的解决

1.问题 SQL 语句执行对象中&#xff0c;本内容的字符串内含有单引号导致查询或插入数据库报错&#xff0c; 例如 str 关键字 AND 附近有语法错误 2.解决 字符串中的 ’ → 替换 ”&#xff0c;则查询语句成功&#xff0c;故程式中要备注替换 单引号。

无法解析插件 org.apache.maven.plugins:maven-war-plugin:3.2.3(已解决)

文章目录 1、问题出现的背景2、解决方法 1、问题出现的背景 最开始我想把springboot项目转为javaweb项目&#xff0c;然后我点击下面这个插件 就转为javaweb项目了&#xff0c;但是我后悔了&#xff0c;想要还原成springboot项目&#xff0c;点开项目结构关于web的都移除了&am…

运放-增益带宽积-datasheet参数

在运放开环增益频率曲线中&#xff0c;在一定频率范围内&#xff0c;运放的开环增益与对应的频率乘积为常数&#xff1a;增益带宽积&#xff08;Gain Bandwidth Product&#xff0c; GBP 或者 GBW&#xff09;&#xff0c;即开环增益*频率增益带宽积。 这里有一个误区&#xf…

CompletableFuture异步线程不执行,卡死问题

1、生产上突然发现大量业务数据没执行&#xff0c;通过日志分析有段代码没执行。 2、分析原因可能是异步线程没执行导致&#xff0c;直接上代码场景 3、异步线程调用远程外部接口 超时或多次异常&#xff0c;导致服务无法再开启异步线程&#xff0c;同时代码中其他用到异步线程…

人人可学的AI与高科技普及视频课,零基础,通俗易懂,深入浅出

课程内容&#xff1a; 1 第0课:开课词&#xff0c;欢迎词 ev.mp4 2 第1课:我们为什么要学习Al ev.mp4 3 第2课:AI算法模型的基本概念MOVev,mp4 4 第3课:什么是生成性Al ev,mp4 5 第4课:人工智能的三驾马车 ev.mp4 6 加餐附加课1-谷歌双子座Gemini ev,mp4 7 第5课:关于Al…

为什么idea建议使用“+”拼接字符串

今天在敲代码的时候&#xff0c;无意间看到这样一个提示&#xff1a; 英文不太好&#xff0c;先问问ChatGPT&#xff0c;这个啥意思&#xff1f; IDEA 提示你&#xff0c;可以将代码中的 StringBuilder 替换为简单的字符串连接方式。 提示信息中说明了使用 StringBuilder 进行…

分布式相关理论详解

目录 1.绪论 2.什么是分布式系统&#xff0c;和集群的区别 3.CAP理论 3.1 什么是CAP理论 3.2 一致性 3.2.1 计算机的一致性说明 1.事务中的一致性 2.并发场景下的一致性 3.分布式场景下的一致性 3.2.2 一致性分类 3.2.3 强一致性 1.线性一致性 a) 定义 a) Raft算法…

数据危机!4大硬盘数据恢复工具,教你如何正确挽回珍贵记忆!

在这个数字化的时代&#xff0c;硬盘里的数据对我们来说简直太重要了。但糟糕的是&#xff0c;数据丢失这种事时不时就会发生&#xff0c;可能是因为不小心删了&#xff0c;硬盘坏了&#xff0c;或者中了病毒。遇到这种情况&#xff0c;很多人可能就慌了&#xff0c;不知道怎么…