当前位置: 首页 > news >正文

腾讯三面:写文件时进程宕机,数据会丢失吗?

在计算机系统的运行过程中,我们时常会面临各种突发状况,其中进程宕机就是一个令程序员们头疼的问题。当我们在进行写文件这一关键操作时,如果进程突然宕机,大家心中想必都会涌起一个巨大的疑问:辛辛苦苦准备写入文件的数据到底会不会丢失呢?这就像是在搭建一座知识大厦,突然遭遇地震,我们不知道其中最关键的基石 —— 数据,是否还安然无恙。这个问题不仅关乎数据的完整性和安全性,更对我们理解文件系统、I/O 操作以及系统稳定性有着重要意义。

今天,我们就一同深入探讨这个充满悬念的话题,为大家解开写文件时进程宕机与数据丢失之间的谜团。

一、问题引入与背景

在当今数字化的时代,文件的编写和存储对于个人和企业来说都至关重要。无论是日常办公中的文档撰写,还是企业的重要数据记录,文件的完整性和安全性都是不可忽视的问题。而在文件编写过程中,一个令人担忧的情况就是写文件时进程突然宕机。这可能发生在各种场景下,比如正在撰写重要报告时电脑突然死机,或者服务器在处理大量文件写入请求时出现故障。这个问题的重要性在于,如果数据丢失,可能会导致大量的时间和精力浪费,甚至可能对企业的业务造成严重影响。例如,在金融领域,交易数据的记录如果因为进程宕机而丢失,可能会引发严重的财务风险和法律问题。在科研领域,实验数据的丢失可能意味着长时间的研究成果付诸东流。因此,了解写文件时进程宕机数据是否会丢失以及如何避免数据丢失,对于保障数据的安全和完整性具有重要的现实意义。

二、相关函数解析

2.1Page Cache 详解

Page Cache 的本质是由 Linux 内核管理的内存区域。它由多个 page 构成,page 在操作系统中通常为 4KB 大小(32bits/64bits),而 Page Cache 的大小则为 4KB 的整数倍。我们可以通过读取 /proc/meminfo 文件查看系统的 Page Cache,如 Buffers:1224 kB、Cached:111472 kB、SwapCached:36364 kB等信息。可得公式:Buffers + Cached + SwapCached = Active(file) + Inactive(file) + Shmem + SwapCached,等式两边的内容就是 Page Cache。Page Cache 与其他内存区域的关系在于,它不属于用户空间,是内核管理的用于缓存文件的逻辑内容的区域,从而加快对磁盘上映像和数据的访问。

age Cache是内核管理的内存,也就是说,它属于内核,而不属于用户。在Linux上,可以直接查看Page Cache的方式有很多, 包括/proc/meminfo、free 、/proc/vmstat 命令,它们的内容实际上是一致的。

以/proc/meminfo命令来说:

# cat /proc/meminfo
...
Buffers:               0 kB
Cached:          1286056 kB
SwapCached:            0 kB
Active:         14567748 kB
Inactive:         590956 kB
Active(anon):   14328396 kB
Inactive(anon):   278896 kB
Active(file):     239352 kB
Inactive(file):   312060 kB
...
Shmem:            734644 kB
Slab:              88756 kB
SReclaimable:      38556 kB
...

其中:Buffers + Cached + SwapCached = Active(file) + Inactive(file) + Shmem + SwapCached
等式两边的内容就是平时说的Page Cache,两边都有SwapCached,只是为了说明它也是Page Cache的一部分。在Page Cache中,Active(file) + Inactive(file) 是File-backed page(与文件对应的内存页),是最需要关注的部分,因为平时用的mmap()内存映射方式和buffered I/O来消耗的内存就是这部分。

SwapCached是打开了Swap分区后,把Inactive(anno) + Active(anno)两项匿名页交换到磁盘(swap out)之后,然后在读入到内存(swap in)之后分配的内存。由于读入到内存后,原来的Swap File还存在,所以SwapCached也可以认为是File-backed page,属于Page Cache。注意:SwapCached只有在Swap分区打开的请求下才会有,但是Swap过程产生的I/O很容易引起性能抖动,因此,线上环境Swap分区一般是关闭的。
Shmen是指匿名共享映射这种方式分配的内存(free 命令中的shared一项)。

⑴读Cache

当内核发起一个读请求时,会先检查请求的数据是否缓存到了page cache中,如果有则直接从内存中读取,不需要访问磁盘。如果cache没有请求的数据,就必须从磁盘中读取数据,然后内核将数据缓存到cache中。这样后续读请求就可以命中cache了。page可以只缓存一个文件部分的内容,不需要把整个文件都缓存进来。

⑵写Cache

当内核发起一个写请求时,同样直接写入到cache中。内核会将被写入的page标记为dirty,并将其加入到dirty list中。内核会周期性的将dirty list中的page回写到磁盘上。从而使磁盘上的数据和内存中缓存的数据一致。

⑶Page Cache 产生

Page Cache的产生有两种不同的方式:

  • Buffered I/O(标准I/O)

  • Memory-Mapped I/O(存储映射I/O)

两种方式产生如下图:

图片

对于标准I/O的写,是写用户缓冲区,然后再讲用户缓冲区的数据拷贝到内核缓冲区。如果是读的话,则先从内核缓冲区拷贝到用户缓冲区,再从用户缓冲区中读数据。对于存储映射I/O,是直接将Pagecache 的Page 给映射到用户地址空间,用户直接读写Pagecache Page中的内容。

  • 以标准I/O为例,解释一下,Page Cache如何产生。具体如下图:

  • 往用户缓冲区buffer写入数据。然后buffer中的数据拷贝到内核缓冲区(Pagecache page)。

  • 如果内核缓冲区中没有这个Page,就会发生Page Fault,会去分配一个Page。

  • 拷贝数据,该Pagecache Page就是一个Dirty Page(脏页)。

  • 然后Dirty Page的内容会同步到磁盘,同步到磁盘后,该Pagecache Page就会变成Clean Page并且继续存在系统中。

图片

如果是读文件产生的PageCache ,它的内容和磁盘内容一样,所以它一开始就是Clean Page,除非改写了里面的内容才会变成Dirty Page。

查看脏页:cat /proc/vmstat | egrep "dirty|writeback“

nr_dirty 表示当前系统中积压了多少脏页,nr_writeback 则表示有多少脏页正在回写到磁盘中,他们两个的单位都是 Page(4KB)。

⑷Page Cache回收

先看写内存分配的图:

图片

以得出,应用在申请内存的时候,即使没有free内存了,只要还有足够的可回收逇Page Cache,也可以通过回收Page Cache的方式来申请到内存,所以,回收的方式主要有两种:直接回收和后台回收。

也就是对应的两种页面回收机制:

1)周期性的检查:后台运行的守护进程kswapd完成。该进程定期检查当前系统的内存使用情况,发现系统内空闲的物理内存数目少于特定的阈值(参数是什么?),该进程就会发起页面回收的操作。

2)“内存严重不足”事件触发:如果需要很大内存,而当时系统的内存没有办法提供足够多的物理内存以满足内存请求。这时,操作系统就必须尽快进行页面回收,以便释放一些内存空间从而满足内存请求。

可以通过命令sar来观察内存回收行为,也可以通过查看/proc/vmstat里面的指标进行查看。

★回收算法

Linux中的页面回收是基于LRU(Lease recently used ,最近最少使用)算法。Linux操作系统对LRU的实现是基于一对双向链表,active链表和inactive链表。经常被访问的处于活跃状态的页面会被放到activre链表上,并不经常使用的页面则会放到inactive聊表上。页面会在两个双向链表中移动。页面可能从active链表移动到inactive链表,反之也有可能。但是移动并不是每次页面访问都会发生(要通过自旋锁来保证对链表并发访问操作不会出错,为了降低锁竞争,LInux提供了一种特殊的缓存,LRU缓存,用于批量的向LRU链表中快速的添加页面。有了 LRU 缓存之后,新页不会被马上添加到相应的链表上去,而是先被放到一个缓冲区中去,当该缓冲区缓存了足够多的页面之后,缓冲区中的页面才会被一次性地全部添加到相应的 LRU 链表中去),页面的移动发生的间隔有可能比较长。对于最近最少使用的页面会被逐个放到inactive链表的尾部。进行页面回收时,Linux操作系统会从inactive链表的尾部开始回收。

★Active和Inactive

而第一次读取文件后,文件内容都是Inactive的,只有再次读取这些内容后,才会把它放到active链表上。处于Inactive链表上的pagecache在内存紧张的时候,是会首先被回收掉。有很多情况下,文件内容往往只被读取一次,它们占用的pagecache需要首先被回收掉;对于业务数据,往往都会读取几次,那么他们就会被放到active链表上,以此来达到保护的目的。

在内存紧张的情况下,会进行内存回收,回收会把Inactive list的部分page给回收掉。为了维护inactive和active的平衡,就需要把active list的部分page给demote到inactive list,demote的原则也是LRU。

疑问:active list和inactive list的比例是多少?,线上环境看,这里两个的比例还是比较大,超过1:2

匿名页:不是file-backed pages,即为匿名页(anonymous page),如堆、栈和数据段等,不是以文件形式存在,因此无法和磁盘文件交换,但可以通过磁盘上划分额外的swap分区或使用swap文件进行交换。

回收机制

★水位(watermark)控制

  • min:如果剩余内存减少到触及这个水位,可认为内存严重不足,当前进程就会被阻塞,kernel会直接在这个进程的进程上下文做内存回收(direct reclaim)。

  • low:当剩余内存慢慢减少,触及到这个水位,就会触发kswapd线程进行内存回收。(后台回收)

  • high:进行内存回收时,内存慢慢增加,触及到这个水位时,就停止回收。

  • 由于每个ZONE是分别管理各自的内存的,因此每个ZONE都有这个三个水位。

水位计算:/proc/sys/vm/min_free_kbytes 是一个用户可配置的值,默认值是min_free_kbytes = 4 * sqrt(lowmem_kbytes)。然后根据min算出来low和high水位的值:low=5/4min,high=6/4min。(计算不是这里的重点,如果有需要见参考资料7)

★swapness

回收的时候,会回收file-backed page和 anonymous page ,但是谁回收的多一些,可以通过/proc/sys/vm/swapness来控制谁回收多一些。swapness的值越大,越倾向于回收匿名页。值越小,越倾向于税后file-backed的页面。回收方法都是LRU算法。

⑸Page Cache 回写

Page cache毕竟是为了提高性能占用的物理内存,随着越来越多的磁盘数据被缓存到内存中,Page Cache也变得越来越大,如果一些重要的任务需要被Page cache占用的内存,内核将回收page cache以此来支持。

page write back的触发条件

★空间层面

  • 当系统的“dirty”的内存大于某个阈值,该阈值是在总共的“可用内存”(包括free pages 和reclaimable pages)中的占比。

  • 参数“dirty_background_ratio”(默认值10%),或者是绝对字节数“dirty_background_bytes”(默认值为0,表示生效)。两个参数只要谁先达到即可执行,此时就会交给专门负责writeback的background线程去处理。

  • 参数“dirty_ratio”(默认值30%)和“dirty_bates”(默认值为0,表示生效),当“dirty”的内存达到这个比例或数量,进程则会停下write操作(被阻塞),先把“dirty”进行writeback。

★时间层面

周期性的扫描,扫描间隔用参数:dirty_writeback_interval表示,以毫秒为单位。发现存在最近一次更新时间超过某个阈值(参数:dirty_expire_interval,单位毫秒)的pages。如果每个page都维护最近更新时间,开销会很大且扫描会很耗时,因此具体实现不会以page为粒度,而是按inode中记录的dirtying-time来计算。

  • 用户主动发起。

  • 调用sync()/msync()/fsync()。

  • 参数设置可以在:/proc/sys/vm下。

  • 其中dirty_writeback_interval实际的参数为:dirty_writeback_centisecs(默认值为500,单位为1/100秒,也就是5秒)

  • dirty_expire_interval实际的参数为:dirty_expire_centisecs(默认值为3000,单位为1/100秒,也就是30秒)

★执行线程

2.4内核,用一个叫bdflush的线程专门负责writeback操作。因为磁盘I/O操作很慢,而线程操作系统有多个块设备,如果bdflush在其中一个块设备上等待I/O操作的完成,可能会需要很长的时间,此时单线程模式的bdfoush就会成为影响性能的瓶颈。而且bdflush没有周期扫描功能。

在2.6内核中,bdflush和kupdated一起被pdflush(page dirty flush)取代了。pdflush是一组线程,根据块设备的I/O负载情况,数量从最少2个到最多8个不等。如果1秒内没有空闲的pdflush线程,则会创建一个;如果pdflush线程的空闲时间超过1秒,则会被销毁。一个块设备可能有多个可以传输数据的队列,为了避免在队列上的拥塞(congestion),pdflush线程会动态的选择系统中相对空闲的队列。

在2.6.32版本上,直接一个块设备对应一个thread(算法效果不明显),这种内核线程被称为flusher threads。
无论是内核周期性的扫描,还是用户手动触发,flusher threads的write back都是间隔一段时间才进行的。如果这段时间内系统掉电了,那么还没有来得及write back的数据修改就面临丢失的风险,算是page cache机制存在的一个缺点。

2.2内存管理与回收机制

内存管理中的 swap 机制指的是当物理内存不够用时,内存管理单元(Memory Mangament Unit)需要提供调度算法来回收相关内存空间,然后将清理出来的内存空间给当前内存申请方。当进程发现需要访问的数据不在内存时,操作系统可能会将数据以页的方式加载到内存中,这个过程被称为缺页中断。如果主内存中不包含可以使用的空间时,操作系统会从选择合适的物理内存页驱逐回磁盘,为新的内存页让出位置,这一过程叫做页面替换。这些机制对数据存储的影响在于,当内存不足时可能会导致数据被换出到磁盘,如果在这个过程中发生进程宕机,可能会影响数据的完整性。例如,对于 Anonymous pages 的内存回收代价较高,无论是否有写操作,在 swap 时必须持久化到磁盘,而 File-backed pages(Page Cache)的内存回收代价较低,若没有脏页甚至不会将 Page Cache 回盘。

现代计算机系统的内存层次结构是一个多级存储体系,从速度最快、容量最小的寄存器,到高速缓存(L1、L2、L3 等),再到主存储器(内存),最后是速度最慢、容量最大的磁盘存储。内存管理机制需要在这个复杂的体系中协调数据的存储和访问。寄存器由 CPU 直接控制,用于存放当前正在执行的指令和操作数,其速度与 CPU 内核同步。高速缓存则是为了弥补 CPU 和内存之间的速度差距,存储了近期可能会被频繁访问的数据和指令。内存作为程序运行的主要存储空间,存放着进程的代码、数据和运行时环境。

2.3缓冲机制与数据写入磁盘流程

文件读写的缓冲机制包括全缓冲、行缓冲和无缓冲。全缓冲对于那些能够定位(如磁盘文件)的文件,默认情况下使用全缓冲,缓冲区的大小通常较大,只有在缓冲区满时才刷新到内核缓冲区;行缓冲对于标准输入 / 输出(如 stdin、stdout),默认使用行缓冲,当遇到换行符时,缓冲区中的内容会被刷新到内核缓冲区;无缓冲对于标准错误输出(如 stderr),默认情况下不使用缓冲,每次写入操作都会直接写入到磁盘。数据写入磁盘完整流程:第一步,数据首先写入到用户空间缓冲区;第二步,当缓冲区满或显式调用刷新函数时,数据被复制到内核缓冲区;第三步,要确保数据实际写入到物理磁盘,需要使用 fsync()(POSIX)或 FlushFileBuffers()(Windows)来同步内核缓冲区。如果在数据写入过程中进程宕机,使用 stdio 函数库,在进程宕机的时候,如果没有调用 fflush 或者 fclose 函数,那么数据可能丢失,如果调用了,就要看机器是否掉电,如果机器没掉电,那么数据不会丢失,如果机器掉电了,那么数据有可能丢失。使用系统级别函数库,在调用 write 函数后进程宕机,如果机器没掉电,因为数据已经到了内核缓冲区,此时数据不会丢失;如果机器掉电,那么数据有可能丢失。

三、不同情况分析

3.1使用stdio函数库的情况

当使用 stdio 函数库时,如果没有调用 fflush 和 fclose 函数,数据就还在用户态缓冲区里面,此时若进程宕机,那么进程所对应的数据就会丢失,这是肯定的。因为数据尚未被转移到更安全的区域,一旦进程出现问题,这些数据就无法被保存下来。

例如,假设我们正在使用一个文本编辑软件,软件使用 stdio 函数库进行文件写入操作。如果在编辑过程中,软件突然崩溃,而在此之前我们没有手动保存(相当于没有调用 fflush 或 fclose),那么我们正在编辑的内容很可能就会丢失。

如果调用了 fflush 和 fclose 函数,数据会被刷到 page cache。这时如果机器没掉电,那么数据一般不会丢失,因为数据已经从用户态缓冲区转移到了内核缓冲区,相对来说更加安全。但是,如果机器断电了,数据还是有可能丢失。因为虽然数据在 page cache 中,但尚未真正写入到物理磁盘,断电可能导致内存中的数据丢失。

比如,在服务器环境中,使用 stdio 函数库进行日志写入操作。如果服务器在写入日志后,调用了 fflush 和 fclose 函数,但随后发生了意外断电,那么这些日志数据就有可能丢失。根据一些实际案例统计,在没有采取额外数据保护措施的情况下,机器断电后数据丢失的概率可能在 30% 左右。

3.2使用系统级别函数库的情况

使用系统级别函数库,在调用 write 函数后进程宕机,如果机器没掉电,因为数据已经到了内核缓冲区,此时数据一般不会丢失。这是因为内核缓冲区相对用户空间缓冲区更加稳定,即使进程出现问题,数据也暂时保存在内核中。

例如,在一些高性能的数据库系统中,可能会使用系统级别函数库进行数据写入操作。如果在写入过程中进程宕机,但服务器没有断电,那么数据很可能不会丢失,因为数据已经在内核缓冲区中,后续可以通过恢复进程或其他方式将数据写入到物理磁盘。

然而,如果机器掉电,那么数据也有可能丢失。虽然数据在内核缓冲区中,但断电会导致内存中的数据无法保存到物理磁盘。

比如,在一些关键业务系统中,如果服务器突然断电,而此时使用系统级别函数库写入的数据还在内核缓冲区中,那么这些数据就有可能丢失。根据实际情况分析,在机器断电的情况下,数据丢失的概率可能因系统架构、数据写入频率等因素而有所不同,但一般来说,丢失的风险是比较高的。

四、总结

写文件时进程宕机数据是否丢失取决于多种因素。使用 stdio 函数库时,若未调用 fflush 或 fclose 函数,数据肯定会丢失;调用了这些函数后,若机器未掉电,数据一般不会丢失,但机器掉电仍可能导致数据丢失。使用系统级别函数库,在调用 write 函数后进程宕机,若机器未掉电,数据一般不会丢失,然而机器掉电也可能使数据丢失。

⑴直接文件 IO

直接 I/O(Direct I/O)是一种允许应用程序直接与存储设备通信的 I/O 操作方式,绕过内核的页缓存。

优点包括减少缓存占用、提高数据一致性、减少脏页数量、在某些情况下有更好的 I/O 性能以及向应用程序提供更大的控制。例如在数据库管理系统中,直接 I/O 可以确保数据写入的及时性和一致性。

缺点有性能波动、对齐要求严格、需要更多的应用程序开发支持和错误处理复杂度高,通用性较低。

⑵fflush 和 fsync 的区别

fflush 是 libc.a 中提供的方法,接受一个参数 FILE *,将 C 库中的缓冲调用 write 函数写到磁盘(其实是写到内核的缓冲区)。

fsync 是系统提供的系统调用,接受一个 int 型的文件描述符,将内核缓冲刷到磁盘上。

fflush 只是将流中未写的数据传送到内核,而 fsync 确保数据写到磁盘上。

⑶fsync 和 fdatasync 的区别

fsync 负责将一个文件描述符打开的文件写到物理设备,而且是真正的同步写,没有写完成就不会返回,并且会更新文件的元数据。

fdatasync 只保证打开文件的数据全部被写到物理设备上,一些元数据不一定会被更新。

这两个函数都是根据不同的应用需求而设计的,fsync 更注重数据和元数据的完整性,fdatasync 则在某些情况下可以提高性能,因为它不更新所有元数据。

相关文章:

  • 基于springboot+vue3图书借阅管理系统
  • MySQL笔记---Ubuntu环境下从零开始的MySQL
  • 【0013】HTML超链接标签详解
  • 【go语言】——方法集
  • 开源工具推荐:Uptime Kuma监控
  • 【Python 3.12.1 颠覆性升级:GIL 解锁与性能飞跃,开启多线程新时代】
  • C++ 将jpg图片变成16位565bmp图片
  • 直播预告|TinyEngine低代码引擎v2.2版本特性介绍
  • LabVIEW基于IMAQ实现直线边缘检测
  • µC/OS-III-事件标志
  • 探索 C 语言:编程世界的基石
  • 在kali linux中kafka的配置和使用
  • mysql深度分页优化方案
  • Redis 同步机制详解
  • 写Oracle表耗时25分钟缩短到23秒——SeaTunnel性能优化
  • 发布策略:蓝绿部署、金丝雀发布(灰度发布)、AB测试、滚动发布、红黑部署的概念与区别
  • CPaintDC的简单介绍
  • 大语言模型学习--本地部署DeepSeek
  • 利用机器学习进行信用风险评估
  • C语言总结目录
  • htp免费域名注册网站/百度推广助手手机版
  • 分享类网站源码/网站怎么快速收录
  • 中建国际建设有限公司官网/上海seo有哪些公司
  • 做网站好找工作吗/广州seo诊断
  • 如何帮人做网站赚钱吗/软文广告平台
  • 学生网站建设的总结与评价/app推广策略