版权声明:本文由高剑林原创文章,转载请注明出处: 
文章原文链接:https://www.qcloud.com/community/article/106

来源:腾云阁 https://www.qcloud.com/community

对linux内核来说,读写要经过层层路径,才能真正读写硬盘。从io路径来说,io要经过page cache,io调度队列,dispatch队列,ncq队列和硬盘cache,才能真正到达硬盘。

Page cache:page cache是linux内核提供的缓存接口,page cache的名字就说明内核是通过page单元(通常4K大小)来管理cache。读操作首先在page cache查找,如果找到,就复制page cache的内容返回,找不到,才真正调用下层处理。写操作,buffer io 写到page cache就返回,真正的磁盘写,是由内核的pdflush内核线程负责

IO调度队列:

Linux内核提供了四种io调度算法,as,deadline,cfq,noop。每种调度算法都实现了一个调度队列,io首先在队列中排序(noop最简单,不排序),然后根据条件,决定是否到dispatch队列。从调度队列下发,涉及一个unplug的概念。也就是说,调度队列通常处于阻塞(plug)状态,当执行unplug操作时,io离开调度队列,开始下发。unplug是个循环动作,将调度队列的所有io都尝试下发,直到不能下发为止。
总结一下,执行unplug有下列条件:

  • 第一个io启动了三毫秒的定时器,定时器到了,会unplug,开始下发

  • io请求超过设定的限制(缺省是4),执行unplug,开始下发

  • Sync标志的io,立即unplug,开始下发。

  • Barrier标志的io,清空调度队列后,执行unplug,开始下发

  • 一个io执行完毕,也要unplug队列。

dispatch队列:dispatch队列对应用关系不大。但是内核层对日志文件系统的joural数据,提供了一种barrier io,这个主要在dispatch队列实现。

Ncq队列:
NCQ是sata硬盘自身的队列。(sas硬盘的队列叫TCQ)。NCQ队列是由操作系统创建的,但是加入到NCQ队列的io,是由硬盘来决定执行顺序。为了实现这个,NCQ队列创建在内核的DMA内存中,然后通知硬盘,至于硬盘选择那个io执行,是硬盘自身选择的结果。

硬盘cache:
硬盘cache是硬盘内部的cache。如果打开硬盘cache的话,写硬盘的io,首先是到硬盘cache,而非直接落到硬盘。

一. Pdflush的回写逻辑

Pdflush提供了四个参数来控制回写。在内核实现中,pdflush的回写策略控制还比较复杂。

但是简单一点说,内核缺省情况下,每5秒钟扫描脏页,如果脏页生存时间超过30秒(缺省数值),就刷脏页到磁盘。

详细的可参考本人写的《linux内核回写机制和调整》一文。

二. 数据下盘和一致性分析

从上文的分析,通常的io写,到page cache层就结束返回了,并没真正写到硬盘。这样机器掉电或者故障的时候,就有丢失数据的风险。为了尽快下io,系统又提供了一些措施解决这个问题。

O_SYNC:打开文件的时候,可以设置O_SYNC标志,在page cache的写完成后,如果文件有O_SYNC标志,立即开始将io下发,进入调度队列。随后将文件系统的meta data数据也下发,然后开始循环执行unplug操作,直到所有的写io完成。和回写机制比较,O_SYNC没有等脏页生存30秒,就尝试立即下发到硬盘。

O_SYNC本质就是io下发,然后执行unplug操作。O_SYNC的几个问题是:

  • 写page cache时候要把io拆成4k的单元。回写也是每次写4K的页面,如果是大io,就需要内核的调度层把4k的io重新再合并起来。这是冗余的过程

  • 每个io都要立即unplug,这样就不能实现io的排序和合并。O_SYNC的性能相当低。

  • 如果多个进程并发写,不能保证写操作的顺序。Ncq队列根据硬盘磁头的位置和磁盘旋转位置确定执行的顺序。一般是meta data数据一起写,这样存在不同步的风险。

  • 如果硬盘cache打开了,那么写只到硬盘cache就返回了。存在丢数据的风险。通常存储厂商都要求硬盘cache关闭。不过腾讯的服务器都是打开硬盘cache的。

O_DIRECT:打开文件的时候,可设置O_DIRECT标志。O_DIRECT不使用内核提供的page cache。这样读操作,就不会到page cache中检查是否有需要数据存在。而写操作,也不会将数据写入page cache,而是送入调度队列。

O_DIRECT执行写io的时候,会置WRITE_SYNC标志。这个标志在io进入调度队列后,会执行一次unplug操作。而不是像O_SYNC那样,循环执行unplug操作。

为了避免O_SYNC每个写io都要阻塞等待的问题,系统提供了fsync和fdatasync系统调用,可以让应用层自己控制同步的时机。

Fsync:fsync将文件范围内,所有的脏页面都下发到硬盘。然后也要将脏的元数据写到 硬盘。如果文件的inode本身有变化,同样需要写到硬盘。

Fdatasync:fdatasync和fsync的区别其实很轻微。比如ext2文件系统,如果文件的inode只有轻微的变化,fdatasync此时不更新inode。典型的轻微变化是文件atime的变化。而在ext3文件系统,fsync和fdatasync是完全一样的。不管是否轻微变化,都要回写inode。

Fsync和fdatasync都是对整个文件的操作,如果应用只想刷新文件的指定位置,这两个系统调用就失效了。所以新的内核还提供了sync_file_range来指定范围写。不过要注意,sync_file_range是不回写文件的meta data。必须应用层保证meta data没有更新。

三. Pdflush的回写逻辑

Pdflush提供了四个参数来控制回写。在内核实现中,pdflush的回写策略控制还比较复杂。

但是简单一点说,内核缺省情况下,每5秒钟扫描脏页,如果脏页生存时间超过30秒(缺省数值),就刷脏页到磁盘。

详细的可参考本人写的<<linux内核回写机制和调整》一文。

四. 内核的barrier io

从上文的分析看出,内核没有为用户态提供保证顺序的,确定写到硬盘的系统调用。但是对于内核文件系统来说,必须提供这样的接口。比如日志文件系统,必须要数据落到硬盘后,才能修改元数据的日志。否则,出错情况下就可能造成文件系统崩溃。为此,内核专门提供了一个barrier方式实现日志的准确写到硬盘。

文件系统的barrier io,意味着,这个barrier io之前的写io必须完成。同时,在barrier io完成之前(是真正写到硬盘,不是写到cache就返回),也不能有别的写io再执行。为此,上文分析的dispatch 队列完成了这个功能。

当写io从调度队列进入dispatch队列的时候,要检查是否是一个barrier io。如果是barrier io,dispatch首先在队列中插入一个SCSI命令SYNCHRONIZE_CACHE,这个命令指示硬盘cache刷所有的写io到硬盘。然后再下发barrier io,之后再插入一个SYNCHRONIZE_CACHE命令,指示硬盘将刚才的barrier io真正写到硬盘(还有一种方式,是通过命令携带FUA标志实现不经过cache直接下盘)。

五. 总结

对于单一的存储系统来说,数据一致性,性能和可靠性是几个矛盾的指标。标准的linux内核在这方面也有些左右为难。比如内核在io失败的情况下,一般会重试(内核设置了5次的重试)。这样重试时间可能超过1分钟,这对互联网系统的业务来说是不可承受的。如何找到合适点,平衡几个指标的关系,从操作系统最底层提升产品的可靠性和性能,是一项长期的任务。

数据一致性和io类型的更多相关文章

  1. 关于不同应用程序存储IO类型的描述

    介绍 存储系统作为数据的载体,为前端的服务器和应用程序提供读写服务.存储阵列某种意义上来说,是对应用服务器提供数据服务的后端“服务器”.应用服务器对存 储系统发送数据的“读”和“写”的请求.然而,不同 ...

  2. io类型

    非阻塞io from socket import * import time s=socket(AF_INET,SOCK_STREAM) s.bind(('127.0.0.1',8080)) s.li ...

  3. java中io类型及成熟io框架

    就io本身而言,概念上有5中模型:blocking I/O, nonblocking I/O, I/O multiplexing(select and poll), singal driven I/O ...

  4. [翻译]各个类型的IO - 阻塞, 非阻塞,多路复用和异步

    同事推荐,感觉写的不错就试着翻译了下. 原文链接: https://www.rubberducking.com/2018/05/the-various-kinds-of-io-blocking-non ...

  5. FPGA之IO信号类型深入理解

    在FPGA设计开发中,很多场合会遇到同一根信号既可以是输入信号,又可以是输出信号,即IO类型(Verilog定义成inout). 对于inout型的信号,我们既可以使用FPGA原语来实现,也可以使用V ...

  6. [连载]《C#通讯(串口和网络)框架的设计与实现》- 5.串口和网络统一IO设计

    目       录 第五章           串口和网络统一IO设计... 2 5.1           统一IO接口... 2 5.1.1    串口IO.. 4 5.1.2    网络IO.. ...

  7. 操作系统IO模型

    操作系统IO模型 声明:如下内容是根据APUE和mycat两本著作中关于I/O模式的一些内容加上自己的一些理解整理而成,仅供学习使用. 本节内容 UNIX下可用的五种I/O模型 三种I/O模型 Rea ...

  8. Scalaz(41)- Free :IO Monad-Free特定版本的FP语法

    我们不断地重申FP强调代码无副作用,这样才能实现编程纯代码.像通过键盘显示器进行交流.读写文件.数据库等这些IO操作都会产生副作用.那么我们是不是为了实现纯代码而放弃IO操作呢?没有IO的程序就是一段 ...

  9. 泛函编程(37)-泛函Stream IO:通用的IO处理过程-Free Process

    在上两篇讨论中我们介绍了IO Process:Process[I,O],它的工作原理.函数组合等.很容易想象,一个完整的IO程序是由 数据源+处理过程+数据终点: Source->Process ...

随机推荐

  1. 数据库 Oracle数据库性能优化

    --在Oacle数据库涉及到全表扫描的SQL查询(top,count)中, --现场用户删除表中大部分数据,只保留1W条数据,但是查询仍然很慢,检查磁盘IO,发现磁盘IO不是很高 --经过分析Oacl ...

  2. UML基本表示法

    1 物件 结构化物件 类 接口 协作 用例 组件 节点 行为物件 交互 状态机器 组物件 包 注解物件 注释 2 关系 依赖关系 协作 泛化 实现 3 UML图 结构化物件 类注释 对象表示法 接口表 ...

  3. TensorFlow基础笔记(11) conv2D函数

    #链接:http://www.jianshu.com/p/a70c1d931395 import tensorflow as tf import tensorflow.contrib.slim as ...

  4. [转载]如何解决failed to push some refs to git

    Administrator@PC-20150110FGWU /K/cocos2d/yc (master) $ git push -u origin master To git@github.com:y ...

  5. 【转】Microsoft .Net Remoting之Remoting事件处理全接触

    Remoting事件处理全接触 前言:在Remoting中处理事件其实并不复杂,但其中有些技巧需要你去挖掘出来.正是这些技巧,仿佛森严的壁垒,让许多人望而生畏,或者是不知所谓,最后放弃了事件在Remo ...

  6. WaitForSingleObject()

    参见:http://blog.csdn.net/xiaobai1593/article/details/6672193 1. 格式 DWORD WaitForSingleObject( HANDLE  ...

  7. apache -- 端口被占用

    需求不断变更,总会安装不同的软件,这些软件理想情况下会使用不同的端口,但还是有软件之间端口被占的情况. 最近在电脑上装了一个VMware虚拟机软件,结果导致开启本机的Apache服务无法启动,报 “T ...

  8. 【Java 线程的深入研究2】常用函数说明

    ①sleep(long millis): 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行) ②join():指等待t线程终止. 使用方式. join是Thread类的一个方法,启动线程后直接调用, ...

  9. MS17-010 EternalBlue SMB Remote Windows Kernel Pool Corruption 2017-05-18 16:45

    wget "https://raw.githubusercontent.com/rapid7/metasploit-framework/6d81ca42087efd6548bfcf92417 ...

  10. 利用PHPExcel导出Excel相关设置

    功能包括: 1.设置单元格格式,包括单元格边框.单元格高度.单元格宽度 2.合并指定的单元格 3.设置Excel数据源,并将数据源保护起来(这个是为了实现单元格下拉选项功能) 4.设置字体样式 pub ...