Ext4日志优化-iJournaling

news/2024/3/29 5:35:37/文章来源:https://blog.csdn.net/lzw06061139/article/details/130310152

背景

这几年随着SSD等高性能介质的普及,及其在大规模分布式存储系统上的应用。基于Append only的日志写入技术也应用得越来越多,这几天刚好有空,重读了Ext4文件系统的日志部分的内容,也正好看到一篇对Ext4日志技术进行优化的论文,该论文中的优化方案,作为Ext4经典日志技术的补充,随着Linux 5.10内核一起发布,Geek玩家,可以尝尝鲜。

Ext4日志及不足

基础知识

  1. Ext4日志,第一要义是保证文件系统的一致性,第二才是数据的完整性。(言外之意:开启日志,数据也可能会丢)。
  2. Ext4日志,在文件系统中是一个文件,默认Inode号为8,大小为一个块组(128MiB),日志文件通常存储在文件系统分区的中部;当然在格式化文件系统时,可以通过-J参数设置日志的大小。
  3. Ext4支持三种日志模式
  • ordered,日志中只记录元数据,数据写入磁盘后才会提交日志。这是默认模式。
  • journal,日志中同时记录元数据及数据内容,最安全也是最慢的模式,同时会导致延迟分配及Direct-I/O失效。
  • writeback,日志中只记录元数据,但是不保证元数据和数据的写入顺序。(言外之意:元数据提交了,数据可能还没有落盘)。
  1. Ext4日志,可以关闭,即采用无日志模式运行
  2. Ext4日志文件,默认放在文件系统的中部区域,称为内部日志;为提升日志的可靠性,也可以将日志配置在独立的设备上,称为外部日志,你可以在配置及挂载ext4文件系统时,通过-journal-dev参数设置外部日志设备

日志结构

Ext4采用JBD2进行日志管理,日志的详细磁盘结构, 总结如下:

  1. 内部日志
    日志文件由一个超级块和若干日志事务组成,每个日志事务包含一个描述块,若干撤销块和(或)若干数据块,以及一个提交块
    内部日志
  • Block Header: 日志中的每个块都包含一个12字节的通用块头,包括:4字节的魔数,4字节的类型,4字节的事务ID。
  • Superblock:日志超级块(内嵌Block Header),存放在日志文件的头部,占用1024字节,用来记录日志文件的结构信息。
  • Descriptor Block: 描述块(内嵌Block Header),至少36字节,占用一个block,包含一组块标签用来记录事务中数据块的位置,块标签内容会因为JBD2的标志设置的不同而不同,通常包含一个标识,一个块地址以及校验码。
  • Revocation Block:撤销块(内嵌Block Header),至少16字节,占用一个block,包含一组需要撤销的块ID,撤销块用来表明之前的某个日志事务中的块不再需要重放
  • Commit Block:提交块(内嵌Block Header),32字节,占用一个block,通常包含校验码和时间。提交块,作为一个哨兵块,表明日志事务已经落盘
  1. 外部日志
    外部日志与内部日志很类似,只是因为放在了外部设备上,多了一个标准的Ext4超级快(及前置填充)
    外部日志

日志原理

JBD2的操作单位是块(block),提交一个日志的时候,会包含日志事务中的所有块,因此一个逻辑操作可能影响多个块。(言外之意:一个日志事务中可能包含多个变更,也可能包含与本次逻辑操作不相干的变更内容)

背景知识

  • 在Linux系统中,一个典型的文件系统I/O要经过App -> VFS(Page Cache)-> (文件系统)JBD2 -> 块I/O子系统 -> 磁盘。Page Cache中的文件数据由系统在必要时通过回写线程(BDI设备的kworker线程)或者用户fsync回写,JBD2日志缓存中的数据由JBD2线程定时或者用户fsync回写。
  • 在调度层,回写线程(flush)和fsync的I/O优先级不同,fsync调用携带了SYNC标志,优先级更高,所以fsync的I/O会加入到CFQ的同步队列,回写flush的I/O会加入CFQ的异步队列。

下图展示了日志提交,及回写(flush),用户fsync的相关过程
Ext4日志提交

  1. 图(a):用户进程Process1,Process2,Process3分别向文件fileA,fileB,fileC写入内容(缓存在Page Cache),回写线程为脏数据分配数据块(Ext4开启了延迟分配的话,在回写的时候才分配数据块),将相关的inode注册到running状态的日志事务中(如果当前没有running状态的事务,创建一个新的日志事务,然后设置为runing状态),然后flush数据块(1231)到异步队列。
  2. 图(b):图(a)回写继续进行,用户进程Process2更新文件fileB,然后发起了fsync,用户进程被block,fsync做了两个动作:首先更新相应的元数据块并添加到running的日志事务中,然后回写fileB的数据块(2)到同步队列。图(a)中的回写还在继续,fileA的数据块(12)已经持久化到磁盘,fileC的数据块(12)添加到了异步队列。
  3. 图(c):图(b)中的fsync继续进行(还未返回),系统发起了JBD2日志提交,事务状态修改为commiting(如果之前已经有事务处于commiting状态,那么当前的提交会被block), 并等待返回。由于日志事务中包含fileA,fileB,fileC的信息,所以三个文件的脏数据都会被回写。
  4. 图(d):图(c)中的数据回写完成后,日志事务写入到磁盘,状态修改为checkpoint。fsync返回,用户进程Process2返回。

总结

根据上文的分析,我们归纳出Ext4的日志机制有如下的不足,并导致I/O延迟增加

  • JBD2串行事务依赖,为了避免并发提交重叠事务带来的一致性风险,每个时刻只能有一个事务处于commiting状态。
  • JBD2组合事务提交,JBD2事务中可能包含多个不相干的inode,当发起事务提交时,会将所有文件的数据块都提交。
  • JBD2组合事务可能使延迟分配失效,因为组合事务提交的原因,不相干的文件也被提交,导致延迟分配策略失效。

iJournal日志技术

与JBD2块级的日志机制不同,iJournal是一种文件级的日志技术。iJournal已经应用到Linux 5.10,作为JBD2的一个补充,JBD2日志称为标准提交日志,没有变化,新增的iJournal日志称为快速提交日志,核心目的是提升fsync的性能。下面我们一起来看下iJournal的工作原理

核心思想

iJournal用来提升fsync的性能,因此只在调用fsync的时候才会触发。iJournal日志事务保存在iJournal日志区,iJournal将生成的日志事务保存在iJournal日志区,但并不会提交/影响JBD2中的running日志事务,同时iJournal中提交的元数据块,也会继续提交到JBD2日志事务中。iJournal日志事务只包含最基本的用于恢复的文件级元数据,如:Inode项,外部extent结构(非内联在inode的extent)以及相关的目录项,因此比JBD2日志要小得多。

下图展示了通过iJournal恢复块位图的一个示例:通过日志事务中的inode项或者外部extent中记录的extent信息恢复块位图,如图,extent中包含30和31两个数据块,因此可以用于恢复块位图中的第30和31号位。
恢复块问题

日志事务

iJournal用独立于JBD2的区域来保存日志,为了支持多核,采用per-core的设计,即:每个核一个iJournal日志区。下图是iJournal日志事务的格式,包括两种日志事务:

  • 文件日志事务, 包含的是fsync的文件的元数据,
  • 目录日志事务, 包含的是与fsync相关的父目录的元数据。
    iJournal事务

iJournal header:

iJournal日志事务头,占4K,包含一个JBD2日志头(Block Header),4字节的Inode号,256字节的文件Inode结构以及若干块标签。

  • iJournal日志事务与包含同一个文件的JBD2日志事务有相同的事务号,iJournal日志分布在多个日志区,恢复模块根据事务号来鉴别事务顺序。另外,在一个JBD2的running日志事务过程中,可能发生多个文件fsync,因此可能存在多个有相同事务号的iJournal事务,为了解决这些事务的顺序问题,iJournal引入了全局子事务号,该子事务号随着fsync的调用而线性递增。
  • 文件inode号,用来恢复inode表,inode位图及块组描述表。
  • 块标签,每个块标签表示的是日志文件中一个external extent到文件块的映射。进行一致性恢复时,会使用inode结构中的internal extent,块标签,以及external extent来恢复块位图。

文件日志事务

文件日志事务包含的是fsync的文件的元数据,由一个iJournal日志头,若干external extent(如果有)以及一个提交块组成。
文件日志事务中,只包含脏的external extent,为了减少搜索extent树的开销,iJournal的引入,需要对文件系统进行如下的修改:为每个文件维护一个未提交的脏extent列表,在extent创建/删除时对列表进行更新。【每个列表元素占用20字节,看起来开销可接受】。

目录日志事务

目录日志事务,记录的是fsync文件的父目录的更新,有一个iJournal日志头,若干目录项(DE)以及一个提交块组成。举个例子:

创建目录/A,子目录/A/B, fsync文件/A/B/c,这个时候iJournal需要记录目录/A, /A/B,
以及文件/A/B/c的变化。提交日志的时候,也需要将目录也一并提交。

为了跟踪未提交的目录,需要在文件的Inode中添加uncommitted_DE标志。创建文件时,设置该标志,表示文件目录项还未记录在父目录块中。父目录块被JBD2提交后,清除该标志。iJournal在创建fsync日志记录时,会先检查文件inode中的uncommitted_DE标志,如果标志被设置,就会递归的查找未提交的父目录,然后创建目录日志事务,并按照最顶级目录,下一级目录…的顺序将目录记录在目录日志事务中,最后才创建文件日志事务。【注:为了减少解码目录块的时间消耗,目录日志事务中每个DE项会记录完整的目录块】

如果一个fsync的文件,没有外部extent以及父目录DE块被修改,那么所有的信息可以保存在iJournal日志头中,只占用一个块大小。

故障恢复

与JBD2日志不同,iJournal日志只用于恢复与fsync相关的目录和文件。为了简化iJournal的实现,某些场景也是用JBD2日志来实现

  • 对于目录的fsync,用JBD2日志来实现;
  • 对于包含文件硬链接的目录,用JBD2日志来实现;为了处理这种情况,在文件的inode中添加uncommitted_HL标志,当inode中的i_link_count计数因为硬链接增加时,设置该标志。JBD2提交了日志后,清除该标志。fsync调用会检查这个标志,如果该标志被设置,就调用JBD2日志。

进行故障恢复时,恢复模块先扫描JBD2标准日志区,提交那些还未checkpoint的日志事务,同时找到最后提交的日志事务号Max_TxID。然后,扫描iJournal快速日志区,只恢复那些合法的iJournal日志事务:合法的iJournal日志事务是指那些事务号大于Max_TxID的事务,如果一个inode有多个iJournal事务,那么拥有最大子事务号的事务才是合法的。怎么理解,请看下文:

下图(a)显示了一个日志提交场景
日志提交
下图(b)显示了一个文件恢复场景
文件恢复

  1. 图(a),在时刻30,JBD2事务号TxID=n的日志事务被提交,事务号+1,变成TxID=n+1;在事务号TxID=n+1的事务周期内,文件fileB,fileC,fileD发生变化,两个进程分别发起了针对文件fileC,fileD的fsync。
  2. 图(b),iJournal事务号(TxID, sub-TxID)= (n+1, 0)和(n+1, 1)的日志事务分别包含fileC和fileD的已提交日志事务。
  3. 图(a),在事务号TxID=n+1的事务提交前,系统Crash。图(b),因为JBD2事务号TxID=n的事务已提交,所以iJournal事务号TxID=n的事务不合法,所以恢复时,iJournal恢复从事务号TxID=n+1的事务开始。图(a),在TxID=n+1事务期间的文件fileB的变更丢失。

iJournal恢复

因为每个fsync调用会生成一个文件日志事务和若干目录日志事务,如果在处理fsync过程中,发生系统Crash,fsync生成的多个日志事务无法实现原子提交。此外,目录事务中的DE块也包含不相干文件的信息,因此,在进行故障恢复时,并没有直接将DE块复制到文件系统上,而是先识别出发生变化的目录项,如果上述目录项指向的inode可以访问,就用DE块更新文件系统。

图(a)显示了iJournal恢复的初始状态,inode号等于3的文件,包含3个external extent,包含24个数据块;图(b)进行了一些文件操作,首先10个数据块(50-59)及在12号块的external extent结构被删除;接着,追加6个数据块(74-79),在13号块的external extent结构被更新;最后发起fsync。
iJournal恢复-a
iJournal恢复-b
图(c),假定在JBD2提交前,发生了系统Crash。恢复模块,根据iJournal日志,生成inode结构以及external extent树。将生成的inode与文件系统中的inode进行比较,恢复模块通过记录的fsync日志能够识别出文件系统的变化,并应用这些变更恢复系统。12号块的external extent被删除时,JBD2日志记录一个撤销块,用于跳过该日志事务的恢复。同时iJournal也会跳过撤销块的写入。
iJournal恢复-c

效果

根据论文中的测试数据,iJournal在桌面应用,移动应用两个场景下,fsync延迟以及多核带宽性能都有非常显著的改善。

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《编码——隐藏在计算机软硬件背后的语言》精炼——第11章(门)

“The only source of knowledge is experience.” - Albert Einstein 引言 编码是一种处理并表达信息的方式,它包括摩斯电码、盲文、二进制语言等等,当然作为计算机类的经典书籍,这本书简述了计算机中以二进制数为基础的编码方式&#xff0…

nginx简单介绍

文章目录 1. 下载并解压2. 80端口被占用,更改nginx默认的监听端口3. 访问nginx4. 在linux上安装nginx5. nginx常用命令6. nginx.conf 1. 下载并解压 官网下载 2. 80端口被占用,更改nginx默认的监听端口 更改conf/nginx.conf文件 3. 访问nginx ht…

【Linux】popen pclose接口介绍

本篇文章简单讲述了c语言接口popen/pclose的用法 1.函数作用 函数定义如下 #include <stdio.h>FILE *popen(const char *command, const char *type); int pclose(FILE *stream);1.1 popen popen函数会创建一个管道&#xff0c;fork后调用shell来打开进程。由于管道的…

射频封装技术:层压基板和无源器件集成

射频和无线产品领域可以使用非常广泛的封装载体技术&#xff0c;它们包括引线框架、层压基板、低温共烧陶瓷&#xff08;LTCC&#xff09;和硅底板载体&#xff08;Si Backplane&#xff09;。由于不断增加的功能对集成度有了更高要求&#xff0c;市场对系统级封装方法&#xf…

Qt 项目Mingw编译器转换为VS编译器时的错误及解决办法

错误 在mingw生成的项目&#xff0c;转换为VS编译器时通常会报些以下错误&#xff08;C4819警告&#xff0c;C2001错误&#xff0c;C2143错误&#xff09; 原因及解决方式 这一般是由于字符编码引起的&#xff0c;在源代码文件中包含了中文字符导致的。Qt Creator 生成的代码文…

iptables防火墙和Firewalld

引言 在 Internet 中&#xff0c;企业通过各种应用系统来为用户提供各种服务&#xff0c;如 Web 网站、电子邮件系统、FTP 服务器、数据库系统等&#xff0c;那么&#xff0c;如何来保护这些服务器&#xff0c;过滤企业不需要的访问甚至是恶意的入侵呢&#xff0c;接下来&#…

【Linux】生产者消费者模型——环形队列RingQueue(信号量)

文章目录 铺垫信号量信号量概念信号量PV操作信号量基本接口 环形队列的生产消费模型引入环形队列访问环形队列代码实现代码改造多生产者多消费者代码 总结 铺垫 之前写的代码是存在不足的地方的&#xff1a; 我们使用线程操作临界资源的时候要先去判断临界资源是否满足条件&am…

最新动态 | 大势智慧参加广东省应急测绘保障与安全生产演练

4月20日&#xff0c;2023年度广东省应急测绘保障与安全生产演练在台山市赤溪镇鱼塘湾举行。本次演练由广东自然资源厅主办&#xff0c;广东省国土资源测绘院、江门市自然资源局和台山市人民政府承办。在省市各指导单位与参演单位的多方协同与指挥下&#xff0c;应急测绘保障与安…

【三十天精通Vue 3】第十四天 Vue 3 的单元测试详解

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录 引言一、为什么要进行单元测试1.1 单元测试的概念1.2 单元测试的优…

ctfshow_WEB_web2 wp

前言 写这个是因为。。。我想摆烂&#xff0c;就去从最简单的题开始做了&#xff0c;想着交一道题是一道嘛&#xff0c;总之觉得这样做很适合欺骗安慰自己&#xff08;逃 然后我发现我错了&#xff0c;我第二道题就做了好久还没做出来&#xff0c;甚至最后去点开了hint…… ps…

Java网络编程系列之NIO

Java网络编程系列之NIO 1.Java NIO概述1.1 阻塞IO1.2 非阻塞IO1.3 NIO概述1.3.1 Channels1.3.2 Buffer1.3.3 Selector 2.Java NIO(Channel)2.1Channel概述2.2 Channel实现2.3 FileChannel 介绍与示例2.4 FileChannel 操作详解2.4.1 打开FileChannel2.4.2 从FileChannel读取数据…

自定义测试平台搭建

体验地址&#xff1a;TestManagePlatform 首次加载会比较慢... 功能点 1.数据工具生成&#xff0c;增删改查 2.测试用例以及测试套件生成&#xff0c;测试执行测试基础用例增删改查。 3.Jacoco 代码增量扫描 4.文章管理 欢迎私聊&#xff0c;支撑自定义开发。

Java基础(十)字符串相关类

1 字符串相关类之不可变字符序列&#xff1a;String 1.1 String的特性 java.lang.String 类代表字符串。Java程序中所有的字符串文字&#xff08;例如"hello" &#xff09;都可以看作是实现此类的实例。 字符串是常量&#xff0c;用双引号引起来表示。它们的值在创…

对数据结构的初步认识

前言: 牛牛开始更新数据结构的知识了.本专栏后续会分享用c语言实现顺序表,链表,二叉树,栈和队列,排序算法等相关知识,欢迎友友们互相学习,可以私信互相讨论哦! &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&a…

Allegro PCB后处理

Allegro PCB后处理&#xff0c;主要是完成线路设计以后&#xff0c;输出生产文件之前的处理。这是看教程做的记录&#xff0c;方便以后自己参考。 教程&#xff1a; [小哥Cadence Allegro 132讲字幕版PCB视频教程]_哔哩哔哩_bilibili 感觉关键是多看右边Options菜单&#xff0…

Simulation Extractable Versions of Groth’s zk-SNARK Revisited学习笔记

1. 引言 等人2020年论文《Simulation Extractable Versions of Groth’s zk-SNARK Revisited》&#xff0c;开源代码实现见&#xff1a; https://github.com/Baghery/ABPR22&#xff08;Rust&#xff0c;基于arkworks开发。使用了Multi-Scalar Multiplication (MSM)技术来优化…

linux下使用ftp下载服务器数据

首先确认服务器地址 比如我要从uniprot获取数据&#xff0c;需要先ping服务器地址&#xff1a; 可见&#xff0c;ftp地址不需要前面的https 匿名登录 匿名&#xff1a;anonymous 密码&#xff1a;任意邮箱&#xff0c;如123163.com 这里的传输模式我使用的是二进制&#xff…

Revit进入Unity教程

一、背景 小伙伴们是否有Revit进入Unity交互的需求呢&#xff1f; 二、实现功能 1.Revit进入Unity,包含模型属性&#xff0c;材质&#xff0c;轻量化等 2.实现BIM构件点选&#xff0c;高亮&#xff0c;属性展示 3.实现BIM模型分层显示&#xff0c;爆炸等效果 学习教程&…

xilinx zynq+vitis实现命令行编译输出xsa以及bin文件

执行菜单命令【开始】—【所有程序】—【Xilinx Design Tools】—【Vivado2020.1】—【Vivado2020.1Tcl Shell】,弹出命令界面 或者cmd命令下输入call D:\soft_install\vivado2020.1\Vivado\2020.1\bin\vivado.bat -mode tcl 2.输入打开工程指令&#xff1a; open_project …

SpringBoot整合Redis,一篇带你入门使用Redis

本文介绍如何将Redis整合到SpringBoot项目中&#xff0c;以及如何配置、封装和使用 文章目录 前言环境搭建项目结构添加依赖 Module封装RedisConfig配置封装常见操作为ServiceRedisServiceRedisLockUtil 测试 前言 参考链接&#xff1a; 英文官网链接中文官网链接Redis githu…