网站建站解决方案,北京市网络科技有限公司,东莞智通人才网官网,家电维修怎么自己做网站转自#xff1a;OSC开源社区今天同事用 cp 命令#xff0c;把他给惊到了#xff01;背景是这样的#xff1a;他用 cp 拷贝了一个 100 G的文件#xff0c;竟然一秒不到就拷贝完成了#xff01;用 ls 看一把文件#xff0c;显示文件确实是 100 G。sh-4.4# ls -lh
-rw-r-… 转自OSC开源社区 今天同事用 cp 命令把他给惊到了背景是这样的他用 cp 拷贝了一个 100 G的文件竟然一秒不到就拷贝完成了用 ls 看一把文件显示文件确实是 100 G。sh-4.4# ls -lh
-rw-r--r-- 1 root root 100G Mar 6 12:22 test.txt但是copy起来为什么会这么快呢sh-4.4# time cp ./test.txt ./test.txt.cpreal 0m0.107s
user 0m0.008s
sys 0m0.085s一个 SATA 机械盘的写能力能到 150 M/s 大部分的机械盘都是到不了这个值的就算非常不错了正常情况下copy 一个 100G 的文件至少要 682 秒 ( 100 G/ 150 M/s )也就是 11 分钟。实际情况却是 cp 一秒没到就完成了工作惊呆了为啥呢更诡异的是他的文件系统只有 40 G为啥里面会有一个 100 G的文件呢同事把我找来看看这个诡异的问题。分析文件我让他先用 du 命令看一下却只有 2M 根本不是100G这是怎么回事sh-4.4# du -sh ./test.txt
2.0M ./test.txt再看 stat 命令显示的信息sh-4.4# stat ./test.txtFile: ./test.txtSize: 107374182400 Blocks: 4096 IO Block: 4096 regular file
Device: 78h/120d Inode: 3148347 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2021-03-13 12:22:00.888871000 0000
Modify: 2021-03-13 12:22:46.562243000 0000
Change: 2021-03-13 12:22:46.562243000 0000Birth: -stat 命令输出解释Size 为 107374182400知识点单位是字节也就是 100G Blocks 这个指标显示为 4096知识点一个 Block 的单位固定是 512 字节也就是一个扇区的大小这里表示为 2M划重点Size 表示的是文件大小这个也是大多数人看到的大小Blocks 表示的是物理实际占用空间同事问道“文件大小和实际物理占用这两个竟然不是相同的概念 为什么是这样 ” “看来我们必须得深入文件系统才能理解了来我给你好好讲讲。”文件系统文件系统听起来很高大上通俗话就用来存数据的一个容器而已本质和你的行李箱、仓库没有啥区别只不过文件系统存储的是数字产品而已。我有一个视频文件我把这个视频放到这个文件系统里下次来拿要能拿到我完整的视频文件数据这就是文件系统对外提供的就是存取服务。现实的存取场景例如你到火车站使用寄存服务存行李的时候是不是要登记一些个人信息对吧至少自己名字要写上。可能还会给你一个牌子让你挂手上这个东西就是为了标示每一个唯一的行李。取行李的时候要报自己名字有牌子的给他牌子然后工作人员才能去特定的位置找到你的行李划重点存的时候必须记录一些关键信息记录ID、给身份牌取的时候才能正确定位到。文件系统回到我们的文件系统对比上面的行李存取行为可以做个简单的类比登记名字就是在文件系统记录文件名生成的牌子就是元数据索引你的行李就是文件寄存室就是磁盘容纳东西的物理空间管理员整套运行机制就是文件系统上面的对应并不是非常严谨仅仅是帮助大家理解文件系统而已让大家知道其实文件系统是非常朴实的一个东西思想都来源于生活。空间管理现在思考文件系统是怎么管理空间的如果一个连续的大磁盘空间给你使用你会怎么使用这段空间呢直观的一个想法我把进来的数据就完整的放进去。这种方式非常容易实现属于眼前最简单以后最麻烦的方式。因为会造成很多空洞明明还有很多空间位置但是由于整个太大形状不合适数据大小哪里都放不下。因为你要放一个完整的空间。怎么改进有人会想既然整个放不进去那就剁碎了呗。这里塞一点那里塞一点就塞进去了。对思路完全正确。改进的方式就是切分把空间按照一定粒度切分。每个小粒度的物理块命名为 Block每个 Block 一般是 4K 大小用户数据存到文件系统里来自然也是要切分存储到磁盘上各个角落。图示标号表示这个完整对象的 Block 的序号用来复原对象用的。随之而来又有一个问题你光会切成块还不行取文件数据的时候还得把它们给组合起来才行。所以要有一个表记录文件对应所有 Block 的位置这个表被文件系统称为inode。写文件的流程是这样的先写数据数据先按照 Block 粒度存储到磁盘的各个位置再写元数据然后把 Block 所在的各个位置保存起来即inode我用一本书来表示读文件流程则是先读inode找到各个 Block 的位置然后读数据构造一个完整的文件给到用户inode/block 概念好我们现在来看看inode直观地感受一下这个inode有文件元数据和Block数组长度是15数组中前两项指向Block 3和Block 11表示数据在这两个块中存着。 你肯定会意识到Block数组只有15个元素每个Block是4K 难道一个文件最大只能是 15 * 4K 60 K ? 这是绝对不行的 最简单的办法就是把这个Block数组长度给扩大比如我们想让文件系统最大支持100G的文件Block数组需要这么长(100*1024*1024)/4 26214400Block数组中每一项是4个字节那就需要(26214400*4)/1024/1024 100M 为了支持100G的文件我们的Block数组本身就得100M 并且对每个文件都是如此 即使这个文件只有1K 这将是巨大浪费肯定不能这么干解决方案就是间接索引按照约定把这 15 个槽位分作 4 个不同类别来用前 12 个槽位也就是 0 - 11 我们成为直接索引第 13 个位置我们称为 1 级索引第 14 个位置我们称为 2 级索引第 15 个位置我们称为 3 级索引直接索引能存 12 个 block 编号每个 block 4K就是 48K也就是说48K 以内的文件前 12 个槽位存储编号就能完全 hold 住。一级索引也就是说这里存储的编号指向的 block 里面存储的也是 block 编号里面的编号指向用户数据。一个 block 4K每个元素 4 字节也就是有 1024 个编号位置可以存储。所以一级索引能寻址 4M1024 * 4K空间 。二级索引二级索引是在一级索引的基础上多了一级而已换算下来有了 4M 的空间用来存储用户数据的编号。所以二级索引能寻址 4G (4M/4 * 4K) 的空间。三级索引三级索引是在二级索引的基础上又多了一级也就是说有了 4G 的空间来存储用户数据的 block 编号。所以二级索引能寻址 4T 4G/4 * 4K 的空间。所以在这种文件系统如ext2上通过这种间接块索引的方式最大能支撑的文件大小 48K 4M 4G 4T 约等于 4 T。这种多级索引寻址性能表现怎么样在不超过 12 个数据块的小文件的寻址是最快的访问文件中的任意数据理论只需要两次读盘一次读 inode一次读数据块。访问大文件中的数据则需要最多五次读盘操作inode、一级间接寻址块、二级间接寻址块、三级间接寻址块、数据块。为什么cp那么快接下来我们要写入一个奇怪的文件这个文件很大但是真正的数据只有8K在[0,4K]这位置有4K的数据在[1T , 1T4K] 处也有4K数据中间没有数据这样的文件该如何写入硬盘创建一个文件这个时候分配一个 inode在 [ 04K ] 的位置写入 4K 数据这个时候只需要 一个 block把这个编号写到 block[0] 这个位置保存起来在 [ 1T1T4K ] 的位置写入 4K 数据这个时候需要分配一个 block因为这个位置已经落到三级索引才能表现的空间了所以需要还需要分配出 3 个索引块写入完成close 文件实际存储如图这个时候我们的文件看起来是超大文件size 等于 1T4K 但里面实际的数据只有 8 K位置分别是 [ 04K ] [ 1T1T4K ]。 由于没写数据的地方不用分配物理block块所以实际占用的物理空间只有8K。重点文件 size 只是 inode 里面的一个属性实际物理空间占用则是要看用户数据放了多少个 block 没写数据的地方不用分配物理block块。这样的文件其实就是稀疏文件 它的逻辑大小和实际物理空间是不相等的。 所以当我们用cp命令去复制一个这样的文件时那肯定迅速就完成了。总结好我们再深入思考下文件系统为什么能做到这一点首先最关键的是把磁盘空间切成离散的、定长的 block 来管理然后通过 inode 能查找到所有离散的数据保存了所有的索引最后实现索引块和数据块空间的后分配这三点是层层递进的。推荐阅读专辑|Linux文章汇总专辑|程序人生专辑|C语言我的知识小密圈关注公众号后台回复「1024」获取学习资料网盘链接。欢迎点赞关注转发在看您的每一次鼓励我都将铭记于心~