当前位置: 首页 > 科技观察

让Node.js“偷懒”的COW技术

时间:2023-03-20 16:08:56 科技观察

COW并不是牛,它是Copy-On-Write的缩写,是一种不完全复制的技术。一般来说,复制就是创建两个完全相同的副本,这两个副本是独立的:但是,有时复制是不必要的,可以重复使用之前的副本。写内容时只复制相应的部分内容。这样,如果内容是用来阅读的,就杜绝了复制,如果需要写的话,实际上是复制了一部分内容进行修改。这称为“写时复制”或“写时复制”。原理很简单,但是在操作系统的内存管理和文件系统中却很常见。Node.js也因为这项技术变得“偷懒”了。在这篇文章中,我们将探讨Copy-On-Write在Node.js进程创建和文件复制中的应用:文件复制最常见的想法是将完全相同的文件内容写入另一个位置,但是这有两个问题:写完全一样的内容。如果同一个文件被复制数百次,同样的内容会被创建数百次吗?这是对硬盘空间的浪费。写到一半突然断电怎么办?覆盖如何恢复内容?该怎么办?这时,操作系统设计者想到了COW技术。使用COW技术实现文件复制完美解决了以上两个问题:复制只是对之前的内容添加一个引用,如果没有修改则不会复制,只有第一次修改内容时才会对应数据被复制。block,从而避免了大量硬盘空间的浪费。写入文件时,会先修改另一个空闲磁盘块,修改完成后再复制到目标位置,这样就不会出现断电回滚的问题。Node.js的fs.copyFileapi可以使用Copy-On-Write模式:copyFile默认会写入目标文件并覆盖原来的内容constfsPromises=require('fs').promises;(asyncfunction(){try{awaitfsPromises.copyFile('source.txt','destination.txt');}catch(e){console.log(e.message);}})();但是可以通过第三个参数指定复制策略:constfs=require('fs');constfsPromises=fs.promises;const{COPYFILE_EXCL,COPYFILE_FICLONE,COPYFILE_FICLONE_FORCE}=fs.constants;(asyncfunction(){try{awaitfsPromises.copyFile('source.txt','destination.txt',COPYFILE_FICLONE);}catch(e){console.log(e.message);}})();支持的flags有3个:COPYFILE_EXCL:如果目标文件已经存在,会报错(默认是覆盖)COPYFILE_FICLONE:以copy-on-write方式复制,如果操作系统不支持,会转换为真正的拷贝(默认为直接拷贝)COPYFILE_FICLONE_FORCE:以copy-on-write方式拷贝,如果操作系统不支持,会报错。合并后,传入:constflags=COPYFILE_FICLONE|COPYFILE_EXCL;fsPromises.copyFile('source.txt','destination.txt',flags);Node.js支持操作系统的copy-on-write技术,可以在某些场景下使用提高性能,推荐使用COPYFILE_FICLONE,会比默认的好创建一些进程的方式比较好。Fork是一种常用的创建进程的方式,其实现是一种写时复制技术。我们知道一个进程在内存中分为三部分:代码段、数据段和堆栈段:代码段:存放要执行的代码数据段:存放一些全局数据堆栈段:存放执行状态process是基于这个process进程创建的,那么这3部分内存都要拷贝过来。而如果这三部分内存的内容相同,那么内存空间就被浪费了。因此,fork实际上并没有复制内存,而是创建了一个引用父进程内存的新进程。修改数据时,实际上会复制这部分内存。这就是为什么进程创建被称为fork,即fork,因为它不是完全独立的,而是有些部分被fork出来,变成了两部分,但大部分还是一样的。但是如果要执行的代码不一样怎么办,这时候就必须使用exec,它会新建一个代码段,数据段,栈段,执行新的代码。Node.js也可以使用fork和execapi:fork:constcluster=require('cluster');if(cluster.isMaster){console.log('Iammaster');cluster.fork();cluster.fork();}elseif(cluster.isWorker){console.log(`Iamworker#${cluster.worker.id}`);}exec:const{exec}=require('child_process');exec('my.bat',(错误,标准输出,标准错误)=>{if(错误){console.error(错误);返回;}console.log(标准输出);});fork是linux进程创建的基础,可见copy-on-write技术的重要性。总结复制多份相同的内容无疑是一种空间浪费,所以操作系统在进程创建过程中进行文件复制和内存复制时使用了Copy-On-Write技术。只有在实际修改时才进行复制。Node.js支持设置fs.copyFile的flags。您可以指定COPYFILE_FICLONE以使用Copy-On-Write方法复制文件。还建议您使用此方法来节省硬盘空间并提高文件复制性能。该进程的fork也是Copy-On-Write的实现。它并没有直接将进程的代码段、数据段、堆栈段复制到新的内容中,而是引用了之前的内容。只有当它被修改时,才会进行真正的内存拷贝。.另外,Immutable中Copy-On-Write的实现在分布式读写分离等领域也有很多应用。COW使Node.js变得“懒惰”,但性能更高。