美文网首页
[045][译]cfq-iosched.txt

[045][译]cfq-iosched.txt

作者: 王小二的技术栈 | 来源:发表于2020-03-24 19:09 被阅读0次

    前言

    按照[043][译]blkio-controller.txt,我已经学会了如何通过cgroup v1来调整不同进程的IO权重,这个IO权重是在CFQ调度算法中实现的,在深入学习一下CFQ调度算法之前,我决定先看一下CFQ的说明书cfq-iosched.txt。翻译完这个文档之后,我感觉受益良多,比网上很多的资料讲的清楚多了。

    cfq-iosched.txt

    CFQ (Complete Fairness Queueing)完全公平排队
    ===============================
    CFQ调度器的主要目的是为所有请求I/O操作的进程,提供请求磁盘的I/O操作的公平分配。
    
    CFQ为请求I/O的进程维护每个进程队列操作(同步请求)。
    在异步请求的情况下,所有进程的请求都根据其进程的I/O优先级。
    
    CFQ调度器可调项
    ========================
    
    slice_idle
    ----------
    这指定CFQ在确定的CFQ队列上(对于顺序工作负载)的下一个请求应空闲多长时间
    以及在队列过期之前,服务树(对于随机工作负载),CFQ选择要从中分派的下一个队列。
    
    默认情况下,slice_idle是一个非零值。这意味着默认情况下我们在队列/服务树会空闲。
    这对于单轴SATA/SAS磁盘等高稳定性介质非常有用,我们可以减少总的寻道次数,并提高吞吐量。
    
    将slice_idle设置为0将删除队列/服务树上的所有空闲。在更快的存储上,例如硬件RAID配置中的
    多个SATA/SAS磁盘等设备,我们应该看到总体吞吐量的提高。不利的一面是,写操作提供的隔离也会降低,
    IO优先级的概念会变得更弱。
    
    因此,根据存储和工作负载的不同,将slice_idle设置为0可能会很有用。
    一般来说,我认为对于SATA/SAS磁盘和SATA/SAS磁盘的软件RAID,保持slice_idle开启应该很有用。
    对于任何配置单个LUN(基于主机的硬件RAID),设置slice_idle=0可能会得到更好吞吐量和可接受的延迟的结果。
    
    back_seek_max
    -------------
    这指定了以KB为单位,向后搜索的最大“距离”。
    这个距离是从当前头部位置到在距离方面向后的扇区。
    
    此参数允许调度器在后面方向中预测请求
    如果他们在这个范围内,就把他们当作“下一个”与当前头部位置的距离。
    
    back_seek_penalty
    -----------------
    此参数用于计算反向搜索的成本。如果请求的后向距离仅为“前”请求的1/back_seek_penalty,
    则认为两个请求的搜索成本相等。
    
    所以调度器不会偏向一个或另一个请求(否则调度器会偏向前请求)。
    back_seek_penalty的默认值是2.
    
    fifo_expire_async
    -----------------
    此参数用于设置异步请求的超时。
    默认值是248ms。
    
    fifo_expire_sync
    ----------------
    此参数用于设置同步请求的超时。默认值是124ms. 
    如果希望同步请求优于异步请求,则应当减少fifo_expire_sync这个值。
    
    group_idle
    -----------
    此参数强制在CFQ组级别而不是CFQ队列级别的空闲。这是在观察到高端存储由于顺序队列上的空闲而出现瓶颈并
    允许从单个队列进行调度后引入的。这个参数的思想是它可以在slice_idle=0和group_idle=8的情况下运行
    ,使空闲不会在组中的单个队列上发生,而是在组中整体发生,从而仍然保持IO控制器工作。
    
    在组中的单个队列上不空闲,同时从组中的多个队列分派请求,并在更高端的存储上实现更高的吞吐量。
    
    参数的默认值是8ms.
    
    low_latency
    -----------
    这个参数被用于开启/关闭CFQ调度器的low_latency模式,
    如果开启,CFQ将会尝试重新计算每个进程时间片,基于系统设置的low_latency。
    这有利于公平而不是吞吐量。关闭low latency (设置成0) 忽略目标延迟,
    将会允许系统中的每一个进程获得完整的时间片
    
    默认low latency模式是开启的.
    
    target_latency
    --------------
    这个参数用于计算每一个进程获得的时间片,在开启CFQ的latency模式。 
    它将确保同步的请求有一个估计的延迟。 但是顺序工作更加重要(例如顺序读),
    然后为了满足延迟限制,由于每个进程在交换cfq队列之前,发出I/O请求的时间减少,吞吐量可能会降低。
    
    虽然这可以通过禁用latency_mode来克服,但它可能会增加某些应用程序的读取延迟。
    此参数允许通过sysfs接口更改target_latency,该接口可以提供平衡的吞吐量和读取延迟。
    
    默认值target_latency是300ms.
    
    slice_async
    -----------
    此参数和slice_sync一样,但是只是用于异步队列
    默认值是40ms.
    
    slice_async_rq
    --------------
    这个参数用于限制异步请求分发到设备的请求队列,在队列中的时间片,允许分派的最大请求数也取决于io优先级。. 
    默认值是2.
    
    slice_sync
    ----------
    当某个队列被选择执行的时候, 这个队列IO请求,只在一个确定的时间片里去执行,在切换到另外一个队列之前。
    这个参数就是用于同步队列的时间片的计算
    
    时间片的计算用以下方程式-
    time_slice = slice_sync + (slice_sync/5 * (4 - prio)). 
    为了增加同步IO的时间片,增加slice_sync的值 默认值100ms.
    
    quantum
    -------
    这个参数指定了被转发到设备队列的数量. 
    在一个队列的时间片中,如果转发给设备队列的数量超过了这个数,另一个请求将不会出现.
    这个参数用户同步请求
    
    如果存储有多个磁盘,此设置可以限制请求的并行处理。因此,增加该值可以提高性能,
    尽管这可能会导致一些I/O的延迟由于请求的数量增加而增加
    
    
    CFQ Group scheduling
    ====================
    CFQ支持blkio cgroup,在每个blkio cgroup目录中有"blkio."前缀的文件。
    它是基于权重基础,有四个旋钮对于配置-权重[_设备]和叶权重[_设备]。
    内部cgroup节点(带有子节点的节点)也可以在其中包含任务,
    前两个配置cgroup作为一个整体在其父级有权享有的比例,
    后两个配置cgroup中的其直接子任务相比所占的比例。
    
    另一种思考方法是假设每个内部节点一个隐式的叶子节点,它承载所有的任务,其权重为
    叶权重[设备]配置。假设一个blkio层次结构由根、A、B、AA和AB五个cgroups组成
    下面表示每个名称的权重。
    
            weight leaf_weight
     root :  125    125
     A    :  500    750
     B    :  250    500
     AA   :  500    500
     AB   : 1000    500
    
     根从来没有一个父母使其重量是毫无意义的。向后兼容性,权重始终与叶权重保持同步。
     B、AA、AB没有子代,因此它的任务没有子代与竞争。他们总是能得到cgroup在父级100%。
     仅考虑影响的权重,层次结构如下所示。
    
               root
           /    |   \
          A     B    leaf
         500   250   125
       /  |  \
      AA  AB  leaf
     500 1000 750
    
     如果所有的cgroup都有活动的IOs并且彼此竞争,那么磁盘时间将按如下方式分配:
     分布在根下。此级别的总有效重量为
     A:500 + B:250 + C:125 = 875.
    
     root-leaf :   125 /  875      =~ 14%
     A         :   500 /  875      =~ 57%
     B(-leaf)  :   250 /  875      =~ 28%
    
     A有孩子,并进一步将其57%分配给孩子隐式叶节点。
     此级别的总有效重量为
     AA:500 + AB:1000 + A-leaf:750 = 2250.
    
     A-leaf    : ( 750 / 2250) * A =~ 19%
     AA(-leaf) : ( 500 / 2250) * A =~ 12%
     AB(-leaf) : (1000 / 2250) * A =~ 25%
    
     组调度的CFQ-IOPS模式
     ===================================
     基本的CFQ设计是提供基于优先级的时间片。更高优先级进程的时间片越大,优先级越低进程的时间篇越短。
     如果存储速度快并且支持NCQ和最好在一次请求队列中,转发来自多个cfq队列的多个请求。
     在这种情况下,不可能精确测量被单个队列消耗时间。
    
     不过,可以测量从单个队列发出的请求数,同时允许从多个cfq队列发出,
     这就有效地提高了IOPS(IO operations per second)的公平性。
    
     如果设置slice_idle=0,并且存储支持NCQ,CFQ会在内部切换到IOPS模式,并根据分派的请求数提供公平性。
     注意,此模式切换仅对组调度有效。对于非cgroup用户,不应更改任何内容。
    
     CFQ-IO调度器空闲理论
     ===============================
     在队列中空闲主要是为了等待下一个请求的到来在同一队列上,在请求完成后之后。
     在此过程中,CFQ不会从其他cfq队列中分派请求,即使在处于挂起状态的请求在其他cfq队列。
    
     空转的基本原理是它可以减少旋转介质上的寻道次数。例如,如果一个进程正在执行相关的顺序读取
     (下一次读取仅在前一次读取完成后才开始),那么不从其他队列发送请求应该会有所帮助,
     因为我们没有移动磁盘头,而是继续从一个队列发送顺序IO。
    
     CFQ有以下服务树,并且在这些树上放置各种队列。
          sync-idle sync-noidle async
    
     所有执行同步顺序IO的cfq队列都将会到sync-idle树。
     在这棵树上,我们分别在每个队列上空闲。
    
     所有同步非顺序队列都在sync-noidle树上。还有任何未标记REQ_IDLE的同步写入请求在此进行服务树。
     在此树上,我们不在单个队列上空闲,而是在空闲在整个队列组或树上。所以如果有4个排队等候分派的IO,
     只有在最后一个队列分派最后一个IO后,我们才会空闲。
    
     所有异步写会到async服务树,不会有空闲在异步的队列
    
     CFQ对ssd进行了一些优化,如果它检测到一个支持更高队列深度的非旋转媒体(一次运行多个请求),
     那么它就减少了单个队列的空闲,所有队列都移动到同步noidle树,只剩下树空闲。
     此树空闲为异步树上的缓冲写队列提供隔离。
    
    常见问题解答
     ===
     Q1. 为什么要在所有未标记REQ_IDLE的队列上空闲(树空闲)。
     A1. 我们只对未标记REQ_IDLE的队列执行树空闲(sync-noidle树上的所有队列)。
         这有助于为所有同步空闲队列提供隔离。否则,在存在许多顺序读的情况下,其他异步的IO可能无法获得公平的磁盘份额。
         
         举个例子,假如有10个顺序读正在处理IO,每拿到了100ms。如果一个非REQ_IDLE请求来了,他将会在1秒以后野蛮的
         调度。如果在非REQ_IDLE请求完成之后,我们不空闲,几毫秒后另外一个非REQ_IDLE请求来了,他将在再次在1秒之后
         被调度。重复的,注意一个工作负载如何丢失其磁盘共享并遭受损失,由于多个顺序读。
    
         fsync可以生成依赖的IO,其中一堆数据是在fsync的上下文中写入的,然后再写入一些日志数据。
         日志数据只有在fsync完成其IO(至少对于ext4来说是这样)之后才会出现。
         现在如果有人决定不空闲的fsync线程由于没有!REQ_IDLE,则下次日志写入将不会被安排为另一秒。
         如果一个进程执行的fsync很小,那么在有多个顺序读的情况下,这个进程将受到严重影响。
    
         因此在所有非REQ_IDLE的线程上执行树空闲,提供了与多个顺序读的隔离,同时我们不在单个线程上空闲。
    
     Q1. 何时指定REQ_IDLE
     A2. 我认为,当一个人正在进行同步写操作,并且希望很快从同一个上下文发送更多的写操作时,
         应该能够在写操作时指定REQ_IDLE,这可能在大多数情况下都能很好地工作。
    

    相关文章

      网友评论

          本文标题:[045][译]cfq-iosched.txt

          本文链接:https://www.haomeiwen.com/subject/atqoyhtx.html