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

Linux系统的数据写入机制--延迟写入

我们都知道,在Linux关机的之前都会要运行一个命令那就是sync,这个命令是同步的意思,那为什么要运行这个?而且之前的数据改变我们已经看见了,为什么还要运行这个命令?要回答这个问题就要说一下Linux在这方面的执行机制。


首先我们要从buffer和cache说起,如下图:

wKioL1gIZ4iBDSgWAABT_uvGPtY101.jpg-wh_50

buffer和cache都可以翻译成缓存,但是到底有什么区别呢?


cache:

目的是为了数据重复使用在一定程度上解决读的效率,这里就是用来存放经常用到的数据,而不用每次都去磁盘上面读取,如果本次操作用到的数据没有,则会到磁盘上去寻找。这样就可以在一定程度上协议快速和慢速设备(比如:CPU和硬盘),另外cache也有换进换出机制,就是把原来经常用到,现在不常用的清除掉,这样就可以有空间放最近访问的数据了,以达到下次访问就直接从cache中读取。


buffer:

为了提高写如磁盘时的效率,其实也是为了协调快慢设备,避免造成把数据都提交到写入磁盘队列造成拥堵,因为内核把数据提交到写入队列不可能不管,它必须要等到有返回值才行。所以buffer的作用是先把数据写入(Linux中的write()函数)到buffer中,然后后台再去根据其他机制,把buffer中的数据提交到队列,最终完整同步到磁盘的过程。


我们知道用户发起的程序都会运行在内存中的用户空间内,这时候数据是放在内存中的,如果我们此时需要保存数据,这时候系统其实是先调用一个write()函数,然后再调用sync()或者fsync()函数(对于任何程序来说只要想把数据写入磁盘其过程都一样,有些也有例外)。


用户空间:常规进程所在区域,用户发起的,此区域的代码不能直接访问硬件

内核空间:操作系统所在区域,能访问硬件


当调用了write()函数时,该函数一旦返回正常值,我们可能就认为数据已经写入到了磁盘,但实际上,操作系统在实现磁盘文件的IO时,为了保证IO的效率,会在内存中使用一段专门的地址空间,该空间叫做内核空间,而内核空间之内又会有一段是用作IO的数据缓冲区(这个缓冲区就是buffer),write()函数的作用就是把数据写入到内核空间的IO缓冲区中。


wKioL1eCYaiDhKUNAABora4npp4231.jpg


内核空间的IO缓冲区也有一定大小,当该缓冲区没有写满时或者没有到一个同步周期时,会持续的把write()函数传递的数据写入到该缓冲区中,而当该缓冲区写满或者到了一个同步周期,则会把该缓冲区的内容提交到输出队列,当需要数据到达队列队首的时候,开始执行真正的磁盘IO操作,把数据写入磁盘(这里虽然用了写入磁盘,但是真正的动作不是移动而是复制,复制完成之后,内核空间的IO缓冲区才会释放该数据占用的空间)。这种方式叫做延迟写入

所以这就会出现一个问题,当调用了write()函数后并不等于数据真的保存到了磁盘,但是这里又会有一个错觉,就是你再次请求该文件的时候,可以显示你最后一次更新的内容,其实这个内容并不是从磁盘上读取过来的,而是从用户空间的缓冲区读取的。接着刚才提到的问题,如果数据在内核空间的IO缓冲区内,而此时操作系统出现故障、断电等异常情况就会造成数据丢失。

为了解决数据丢失问题,Unix系统提供了sync、fsync和fdatasync三个函数。

函数功能
sync函数返回0表示成功,该函数负责把所有内核空间中IO缓冲区内修改过的内容推送到输入队列,然后就返回,它并不等待所有磁盘IO操作完成。所以即使调用了sync函数,也不等于成功保存到磁盘了。
fsync函数返回0表示成功,与sync不同,它只会对指定文件描述符的单一文件生效,强制与该文件相连的所有修改过的数据传送到磁盘上,并且等待磁盘IO完毕,然后返回。当该函数返回0时,才真正表示成功保存到磁盘。数据库会在调用了write()之后调用fsync()。
fdatasync
它与fsync类似,它只影响文件数据部分,不涉及数据属性,比如inode信息。所以相对于fsync它需要较少的写磁盘操作。

看了上面的内容你就应该明白为什么关机前要运行一下sync命令了。






      本文转自linuxjavachen  51CTO博客,原文链接:http://blog.51cto.com/littledevil/1863881,如需转载请自行联系原作者





相关文章:

  • 它改变了整个扫地机器人行业,如今被全面收购
  • Day16 Django
  • Paros proxy:网页程序漏洞评估代理
  • HTML 5 Web 存储-sessionStorage和localStorage
  • 使用Prometheus监控Cloudflare的全球网络
  • 歌词显示控件的实现下——自定义View
  • [内核驱动] miniFilter 内核层与应用程序通信
  • 关于form表单input text 未绑定回车事件跳转问题
  • Android照片墙完整版,完美结合 内存方案 LruCache 和 硬盘方案 DiskLruCache
  • CentOS 7下搭建LAMP并把MySQL单独分离
  • Elasticsearch集群如何扩容机器?
  • React组件间通讯
  • 部分域名返回servfailed(案例)
  • CCNP精粹系列之二十三--BGP单自治系统通信,推荐
  • Ext-js 分页实现 (后台用Spring MVC)
  • Docker: 容器互访的三种方式
  • ES6 学习笔记(一)let,const和解构赋值
  • FastReport在线报表设计器工作原理
  • fetch 从初识到应用
  • go append函数以及写入
  • idea + plantuml 画流程图
  • laravel5.5 视图共享数据
  • nodejs实现webservice问题总结
  • Python爬虫--- 1.3 BS4库的解析器
  • Shell编程
  • spring security oauth2 password授权模式
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • SSH 免密登录
  • vue的全局变量和全局拦截请求器
  • vue脚手架vue-cli
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 为什么要用IPython/Jupyter?
  • 中文输入法与React文本输入框的问题与解决方案
  • 自定义函数
  • postgresql行列转换函数
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #pragma data_seg 共享数据区(转)
  • $$$$GB2312-80区位编码表$$$$
  • (¥1011)-(一千零一拾一元整)输出
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (笔试题)分解质因式
  • (附源码)ssm高校运动会管理系统 毕业设计 020419
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (十三)Maven插件解析运行机制
  • (五)MySQL的备份及恢复
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (转载)OpenStack Hacker养成指南