11 您所在的位置:网站首页 vlone还火吗 11

11

2023-12-21 19:13| 来源: 网络整理| 查看: 265

本文仅作为学习记录,非商业用途,侵删,如需转载需作者同意。

把 Linux 从 ubuntu18.04 升级到 ubuntu20.04 之后,在容器里用 fio 这个磁盘性能测试工具,在 ubuntu 20.04 宿主机上的容器中文件读写的性能只有 ubuntu18.04 宿主机上的 1/8 左右了。

一、问题再现

先启动一个 ubuntu18.04的虚拟机,Linux内核版本是4.15。 虚拟机上用命令 docker run -it ubuntu:18.04 bash 启动一个容器 接着容器里运行fio 命令,看一下容器中读取文件的性能。

# fio -direct=1 -iodepth=64 -rw=read -ioengine=libaio -bs=4k -size=10G -numjobs=1 -name=./fio.test

解释下fio 命令中的几个主要参数:

“-direct=1”,代表采用非 buffered I/O 文件读写的方式,避免文件读写过程中内存缓存对性能的影响。

“-iodepth=64"和”-ioengine=libaio" ,这里指文件读写采用异步I/O(Async I/O)的方式,也就是进程可以发起多个I/O请求,并且不用阻塞地等待I/O 的完成,稍后等I/O 完成之后,进程会收到通知。 这种异步I/O很重要,可以极大提高文件读写性能,这里设置了同时发出64个I/O请求。

“-rw=read,-bs=4k,-size=10G”,这几个参数指这个测试是个读文件测试,每次读4KB大小数据库,总共读10GB的数据

“-nu’mjobs=1”,指只有一个进程、线程运行

这条fio命令表示:通过异步的方式读取10GB的磁盘文件,用来计算文件的读取性能。

在 ubuntu 18.04,内核 4.15 上的容器 I/O 性能是 584MB/s 的带宽,IOPS(I/O per second)是 150K 左右。见下图。 在这里插入图片描述

再在ubuntu 20.04,内核 5.4 的虚拟机上启动一个容器,运行命令docker run -it ubuntu:20.04 bash。 再采用同样的测试方式。 它的 I/O 性能是 70MB 带宽,IOPS 是 18K 左右。实践证明,这的确比老版本的 ubuntu 18.04 差了很多。

在这里插入图片描述

二、知识详解 2.1、如何理解容器文件系统

容器中df 查看磁盘情况,可以看到根目录的类型是"overlay"。 它不是我们在普通Linux节点上看到的Ext4或者XFS之类常见的文件系统。

在这里插入图片描述

容器文件系统的好处

前提解释说明: 假设需要在宿主机上运行100个容器。 每个容器都都需要一个镜像,这个镜像就是把容器中程序需要运行的二进制文件,库文件,配置文件,其他的依赖文件等全部打包成一个镜像文件。

如果没有特别的容器文件系统,只是普通的Ext4或者XFS文件系统,那么每次启动一个容器,就需要把一个镜像文件下载并且存储在宿主机上。

假设一个镜像文件的大小是500MB,100个容器的话,就是50GB左右,占用这么多的磁盘空间。

其中操作系统所需的库文件都是差不多的,只读的。

特别是这样的情况:假如这 100 个容器镜像都是基于"ubuntu:18.04"的,每个容器镜像只是额外复制了 50MB 左右自己的应用程序到"ubuntu: 18.04"里,那么就是说在总共 50GB 的数据里,有 90% 的数据是冗余的。

理想的情况就是,宿主机上只要下载并且存储一份"Ubuntu:18.04",所有基于基于此镜像的容器都可以共享这一份通用的部分。

这样设置的话,不同容器启动的时候,只需要下载自己独特的程序部分就可以了。

在这里插入图片描述

正是为了有效地减少磁盘上冗余的镜像数据和网络上的传输,选择一种针对于容器的文件系统是很有必要的,而这类的文件系统被称为UnionFS。

UnionFS:主要是把多个目录(处于不同分区)一起挂载到(mount)在一个目录下。这种多目录挂载的方式,正好可以解决我们说的容器镜像文件。

容器1的挂载如下图,容器2也是类似。ubuntu18.04/ 都是公用的。 在这里插入图片描述

2.2、OverlayFS

UnionFS 有很多种实现:最早的AUFS,目前使用的 OverlayFS,df命令查看的时候,文件系统类型"overlay" 指的就是 OverlayFS。

在Linux 内核3.18版本中,OverlayFS代码正适合入Linux 内核的主分支,也就逐渐成为各个主流Linux 发行版本里缺省使用的容器文件系统了。

挂载示意图如下: 在这里插入图片描述

OverlayFS一个mount 命令牵涉到四类目录,分别是 lower,upper,merged和work。

“lower/” 被mount 两层目录中底下的这层(lowerdir) OverlayFS中,最底下的一层文件是不会被修改的,可以认为它是只读的。OverlayFS支持多个lowerdir。

“uppder/” 是被mount 两层目录中上面的这层(upperdir),在OverlayFS 中,如果有文件的创建,修改,删除操作。那么都会在这一层反应出来,它是可读写的。

“merged/” ,它是挂载点(mount point)目录,也是用户看到的目录,用户实际文件操作在这里进行。

“work/” 这个目录没有在图中显示,它是一个存放临时文件的目录。OverlayFS中如果有文件修改,就会在中间过程中临时存放文件到这里。

OverlayFS会mount 两层目录,分别是lower层和upper层,这两层目录中的文件都会映射到挂载点上。

从挂载点的视角看,upper层的文件会覆盖lower 层的文件,比如"in_both.txt" 这个文件,在lower层和upper层都有,但是挂载点 merged/ 里看到的只是 upper 层里的 in_both.txt 。

在merged/目录里做文件操作,包括这三种:

新建文件,文件会出现在 upper/ 目录中删除文件,删除"in_upper.txt",这个文件会在 upper/ 目录中消失,如果删除"in_lower.txt" ,在 lower/ 目录里的 “in_lower.txt” 文件不会有变化,只是在 upper/ 目录中增加了一个特殊的文件来告诉 OverlayFS,“in_lower.txt” 这个文件不能出在 merged/ 里了,这就表示它已经被删除了。

见下图: 在这里插入图片描述

修改文件:如果修改了"in_lower.txt" ,那么就会在 upper/ 目录中新建一个 “in_lower.txt” 文件,包含更新的内容,而在 lower/ 中原来的实际文件"in_lower.txt" 不会改变。

系统的mounts 信息中可以看到,Docker 怎么用 OverlayFS挂载镜像文件的。 容器镜像文件可以分成多个层(layer),每个层对应OverlayFS里lowerdir 的一个目录。 lowerdir 支持多个目录,也就可以支持多层的镜像文件。

在容器启动后,对镜像文件的修改就会保存在 upperdir 里。

查看容器上的挂载信息,有四个目录: 在这里插入图片描述

三、解决问题

通过perf 工具来查看下,函数调用的情况。

ubuntu 18.04 (Linux内核4.15)环境下使用perf输出的函数调用结果 ubuntu 18.04 (Linux内核4.15)环境下使用perf输出的函数调用结果

ubuntu 20.04 (Linux内核 5.4)环境下使用perf输出的函数调用结果 ubuntu 20.04 (Linux内核 5.4)环境下使用perf输出的函数调用结果

自下而上是函数的一个调用顺序。

我们从系统调用框架之后的函数 aio_read() 开始比较: Linux 内核4.15里 aio_read() 之后调用的是 xfs_file_read_iter() ,而在内核 5.4 里,aio_read() 之后调用的是 ovl_read_iter() ,之后再调用 xfs_file_read_iter()。

这样我们就可以去查看一下,在内核 4.15 之后新加入的这个函数 ovl_read_iter() 的代码。

代码:https://lwn.net/Articles/755889/

Linux 为了完善OverlayFS,增加了OverlayFS自己的 read/write 函数接口,从而不再直接调用OverlayFS后端文件系统(比如XFS,Ext4) 的读写接口,但是它只实现了同步I/O(sync I/O) 并没有实现异步I/O。

而在 fio 做文件系统性能测试的时候,使用的是异步 I/O ,这样才能得到文件系统的性能最大值。 所以,在内核5.4上就无法对OverlayFS 测出最高的性能指标了。

四、重点总结

为什么要有容器自己的文件系统? 很重要的一点是减少相同镜像文件在同一个节点上的冗余,可以节省磁盘空间,也可以减少镜像文件下载占用的网络资源

作为容器文件系统,UnionFS通过多个目录挂载的方式工作。 OverlayFS就是 UnionFS的一种实现,是目前主流Linux发行版本中缺省使用的容器文件系统。

OverlayFS 也就是把多个目录合并挂载,被挂载的目录分为两大类:lowerdir 和 upperdir。

lowerdir:允许有多个目录,被挂载后,这些目录里的文件都是不会被修改或者删除的,也就是只读的。

upperdir:只有一个,不过这个目录是可读的,挂载点目录中的所有文件修改都会在upperdir中反应出来。

容器镜像文件中各层作为 OverlayFS 的lowerdir 目录,然后加上一个空的upperdir 一起挂载好后,就组成了容器的文件系统。

五、评论

1、 问题:经过实验确认,只会在merge即联合挂载点里生成一个文件名,也就是说overlay文件系统为了省存储空间是做了同名文件合并优化的 回答:是的

2、

实验过程如下,结果是lower1目录中的文件覆盖了lower2中同名的文件。 [root@localhost ~]# cat overlay.sh #!/bin/bash umount ./merged rm upper lower1 lower2 merged work -r mkdir upper lower1 lower2 merged work echo "I'm from lower1!" > lower1/in_lower.txt echo "I'm from lower2!" > lower2/in_lower.txt echo "I'm from upper!" > upper/in_upper.txt # `in_both` is in both directories echo "I'm from lower1!" > lower1/in_both.txt echo "I'm from lower2!" > lower2/in_both.txt echo "I'm from upper!" > upper/in_both.txt sudo mount -t overlay overlay \ -o lowerdir=./lower1:./lower2,upperdir=./upper,workdir=./work \ ./merged [root@localhost ~]# sh overlay.sh [root@localhost ~]# cat merged/in_lower.txt I'm from lower1!

信息补充:

挂载文件系统的基本命令如下: mount -t overlay overlay -o lowerdir=lower1:lower2:lower3,upperdir=upper,workdir=work merged

命令说明: 其中"lower1:lower2:lower3"表示不同的lower层目录,不同的目录使用":"分隔,层次关系依次为lower1 > lower2 > lower3; 然后upper和work目录分别表示upper层目录和文件系统挂载后用于存放临时和间接文件的工作基目录(work base dir); 最后的merged目录就是最终的挂载点目录。 若一切顺利,在执行以上命令后,overlayfs就成功挂载到merged目录下了。

注意 lowerdir的优先级

在这里插入图片描述

3、 问题:和老师探讨一个问题,本文中描述的现象,一个重要的原因是容器镜像里只有rootfs,没有linux内核,宿主机上的所有容器是共用宿主机内核的。所以,当宿主机内核版本升级后,容器镜像并没有相应的升级,也会产生这个问题,文中并没有对这个知识要点说明。不知道我的理解是否正确

回答: 容器镜像中只有rootfs没有Linux内核是对的。

在文章里,宿主机内核升级后,无论容器的镜像是否升级,都会有这个问题。文中的问题是overlayfs引起的,和镜像中的文件没有关系。

4、 容器和宿主机是共享内核的。不通的Linux版本内核不一样。

5、 tmpfs只是用来存放一些临时文件的内存文件系统,比如/tmp目录可以使用tmpfs。

6、 问题: 老师,我想请教一个问题,就是已经创建的容器,怎么能新增一个挂载目录!

回答: 容器不像虚拟机,不能动态的挂载volume.

7、 如果以volume的方式挂载到容器中,那么它就不是以overlayfs的文件系统。 性能是否影响要看volume目录的位置在哪个物理磁盘上,和它共享物理磁盘的有哪些读写进程。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有