cgroup还有其他一些限制特性,如io,pid,hugetlb等,这些用处不多,参见Cgroupv1。下面介绍下与系统性能相关的io和hugepage,cgroup的io介绍参考Cgroup - Linux的IO资源隔离

linux IO

linux io涉及到对文件(磁盘设备)的读写性能,对io的优化主要分为

  • 磁盘相关参数调优
  • 文件系统参数调优,一般为io调度器选择和调度器参数调优
  • 文件系统挂载(mount)参数调优

使用如下命令查看当前系统支持的调度器

# dmesg | grep -i scheduler
[ 1.343756] io scheduler noop registered
[ 1.343759] io scheduler deadline registered (default)
[ 1.343784] io scheduler cfq registered
[ 1.343787] io scheduler mq-deadline registered
[ 1.343789] io scheduler kyber registered

使用如下命令查看当前磁盘支持的调度器,方括号表示当前生效的调度器

#  cat /sys/block/sda/queue/scheduler
noop [deadline] cfq

调度器的参数位于/sys/block/sda/queue/iosched/

Noop:该算法实现了最简单的FIFO队列,所有I/O请求大致按照先来后到的顺序进行操作,特别适用于固态硬盘

  • 在IO调度器下方有更加智能的IO调度设备。如果您的Block Device Drivers是Raid,或者SAN,NAS等存储设备,这些设备会更好地组织IO请求,不用IO调度器去做额外的调度工作;
  • 上层应用程序比IO调度器更懂底层设备。或者说上层应用程序到达IO调度器的IO请求已经是它经过精心优化的,那么IO调度器就不需要画蛇添足,只需要按序执行上层传达下来的IO请求即可。
  • 对于一些非旋转磁头氏的存储设备,使用Noop的效果更好。因为对于旋转磁头式的磁盘来说,IO调度器的请求重组要花费一定的CPU时间,但是对于SSD磁盘来说,这些重组IO请求的CPU时间可以节省下来,因为SSD提供了更智能的请求调度算法,不需要内核去画蛇添足。这篇文章提及了SSD中使用Noop效果会更好。

CFQ:给所有进程分配等同的块设备使用的时间片,进程在时间片内,可以将产生的IO请求提交给块设备进行处理,时间片结束,进程的请求将排进它自己的队列,等待下次调度的时候进行处理,适用于通用服务器。

Deadline:保证每个IO请求在一定的时间内一定要被服务到,以此来避免某个请求饥饿,deadline在大多数多线程应用场景和数据库应用场景下表现的性能要优于cfq

可以通过直接修改/sys/block/sda/queue/scheduler文件来临时修改调度器类型,永久修改可以参考如下命令

grubby --grub --update-kernel=ALL --args="elevator=deadline"

deadline使用了3个队列,”standerd queue“中按照block号排序,”read FIFO”和“write FIFO“则按照request请求的顺序添加,read FIFO的超时时间为500ms,write FIFO的超时时间为5s。系统会按照顺序处理standerd queue中的请求,当read FIFO或write FIFO超时后会切换到对应的FIFO处理request。这种处理方式用于防止”request starvation“,即系统可能会在某个block上处理多个request,而导致其他block上的request超时。更多详情参见Kernel Korner - I/O Schedulers,需要注意的是Anticipatory I/O Scheduler已经被废弃。

在遇到系统读写过慢时,可以采用如下步骤进行定位。(注:该系统的模拟故障由dd if=/dev/zero of=loadfile bs=1M count=5000触发):

  • 首先使用top命令查看当前io等待情况,如下可以看到当前io等待时间为84.7
Tasks:   total,    running,   sleeping,    stopped,    zombie
%Cpu(s): 0.7 us, 14.6 sy, 0.0 ni, 0.0 id, 84.7 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : total, free, used, buff/cache
KiB Swap: total, free, used. avail Mem
  • 使用iostat查看具体磁盘使用情况(当前系统只有一块磁盘),主要关注以下几个值

util:采集周期内用于IO操作的时间比率,该值过高直接说明IO占比过高,下面util已经升到了97.19%,IO已经很高了

await:平均每次IO请求等待时间(包括等待时间和处理时间,毫秒为单位),该值过高说明IO队列可能比较长,IO队列长度可以参考avgqu-sz(平均等待处理的IO请求队列长度)

svctm:平均每次IO请求的处理时间(毫秒为单位),正常情况下该值与await相差不大,差距越大,越说明IO过高。

IO有读写之分,如下例中明显写操作IO影响了性能,且设备为磁盘sda(iostat -x -k -d 1 2

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda 0.00 0.00 1.04 227.08 4.17 108850.00 954.34 124.40 1056.26 87.00 1060.71 4.26 97.19
    • 使用iotop -P查看当前IO占用率最高的进程,可以看到是一个PID为15162的进程,其IO达到了80.05%
Total DISK READ :       0.00 B/s | Total DISK WRITE :     403.22 M/s
Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 411.90 M/s
PID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
be/ root 0.00 B/s 403.22 M/s 0.00 % 80.05 % dd if=/dev/zero...
...

使用lsof查看该进程打开的文件,可以看到/home/loadfile的大小达到了4564156416

# lsof -p
lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /run/user/1000/gvfs
Output information may be incomplete.
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dd root cwd DIR , /home
dd root rtd DIR , /
dd root txt REG , /usr/bin/dd
dd root mem REG , /usr/lib/locale/locale-archive
dd root mem REG , /usr/lib64/libc-2.17.so
dd root mem REG , /usr/lib64/ld-2.17.so
dd root 0r CHR , 0t0 /dev/zero
dd root 1w REG , 4564156416 /home/loadfile
dd root 2u CHR , 0t0 /dev/pts/

确定/home/loadfile文件的挂载路径,为根路径

# df /home/
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/centos-root % /

查看根路径挂载的磁盘(本例中为一块磁盘,可以忽略该步骤),为发生IO性能问题的磁盘sda,到此基本可以确认是因为进程15162引发了IO问题。注:可以使用如“time dd if=/dev/zero bs=1M count=2048 of=direct_2G”命令测试磁盘性能

# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda : 20G disk
├─sda1 : 1G part /boot
└─sda2 : 19G part
├─centos-root : 17G lvm /
└─centos-swap : 2G lvm [SWAP]

linux 大页

Linux采用了通用的分页模型,用以减少进程使用的页表以及增加对内存的索引。在Linux-2.6.10版本中, Linux采用了三级分页模型. 而从2.6.11开始普遍采用了四级分页模型,32位系统中取消了PUD和PMD,为二级分页模型。注:每个进程都有其自身的页面目录PGD

    1. 页全局目录(Page Global Directory)
    2. 页上级目录(Page Upper Directory)
    3. 页中间目录(Page Middle Directory)
    4. 页表(Page Table)

下面是一个线性地址包含的各字段以及各字段的用途

注:CR3中含有页目录表物理内存基地址,因此该寄存器也被称为页目录基地址寄存器PDBR(Page-Directory Base address Register),用于定位进程PGD

对于32位系统来说,如果采用4K的分页大小,每个PGD含1024个目录,每个目录含1024个PT,每个PT可寻址4K物理内存,总计4G。从上述可以看出,当进程需要访问实际物理内存时需要经过多级页才行,为了增加地址访问效率,linux使用了一种页缓存,TLB(translation lookaside buffer)。当需要访问物理地址时会首先从TLB中寻找,若找到则称为TLB hit,否则称为TLB miss。

这篇文章描述了使用系统默认4k分页下出现的性能问题,总结下来就是:64位系统下,一个进程访问的内存空间变大时,其PGD里面的页表项也会变大,如一个进程访问一个12G内存时,其页表需要24M,当300个进程同时需要访问这12G内存时,总的页表达到了7200MB,这么大的页表不仅占用大量内存空间,页增加了地址访问的负担(TLB miss也会大大增加)。解决办法是使用大页内存,通过增加单个分页大小,进而减少总体需要的分页的数目(同时也提升了TLB hit的几率)

可以看出,大页内存一般用于64位系统或32位系统启用了PAE(内存地址扩展)的情况。页表的使用情况可以参见/proc/meminfo中的PageTables字段

下面描述来自这里

典型地,内存管理器在 x86 系统上处理的内存页为 4 KB。实际的页大小是与体系结构相关的。对大部分用途来说,内存管理器以这样大小的页来管理内存是最有效的。不过,有一些应用程序要使用特别多的内存。大型数据库就是其中一个常见的例子。由于每个页都要由每个进程映射,必须创建页表条目来将虚拟地址映射到物理地址。如果您的一个进程要使用 4KB 的页来映射 1 GB 内存,这将用到 262,144 个页表条目来保持对那些页的追踪。如果每个页表条目消耗 8 个字节,那些每映射 1 GB 内存需要 2 MB 的开销。这本身就已经是非常可观的开销了,不过,如果有多个进程共享那些内存时,问题会变得更严重。在这种情况下,每个映射到同一块 1 GB 内存的进程将为页表条目付出自己 2 MB 的代价。如果有足够多的进程,内存在开销上的浪费可能会超过应用程序请求使用的内存数量。

解决这一问题的一个方法是使用更大的页。大部分新的处理器都支持至少一个小的和一个大的内存页大小。在 x86 上,大内存页的大小是 4 MB,或者,在物理地址扩展(PAE)打开的系统上是 2 MB。假定在前面的中使用页大小为 4 MB 的大内存页,同样 1 GB 内存只用 256 个页表条目就可以映射,而不需要 262,144 个。这样开销从 2 MB 变为 2,048 个字节。

大内存页的使用还可以通过减少 变换索引缓冲(translation lookaside buffer, TLB)的失败次数来提高性能。TLB 是一种页表的高速缓存,让那些在表中列出的页可以更快地进行虚拟地址到物理地址的转换。大内存页可以用更少的实际页来提供更多的内存,相当于较小的页大小,使用的大内存页越多,就有越多的内存可以通过 TLB 引用。

TIPS:

  • 衡量IO资源的时候,一般使用两个单位,一个是数据读写的带宽,另一个是数据读写的IOPS。带宽就是以时间为单位的读写数据量,比如,100Mbyte/s。而IOPS是以时间为单位的读写次数。
  • docker对io的的设置参数为--blkio-weight和--blkio-weight-device,一个是针对所有设备的,另一个是针对特定设备的,设置的都是相对比例,设置范围为0-1000
  • IO调度算法主要用于在机械硬盘场景下减少磁头寻址造成的性能浪费,磁头寻址时间一般以毫秒为单位。3~15ms

参考:

https://blog.csdn.net/gzh0222/article/details/8666657

https://www.ibm.com/developerworks/cn/linux/l-lo-io-scheduler-optimize-performance/index.html

https://zorro.gitbooks.io/poor-zorro-s-linux-book/content/linuxde-io-diao-du.html

http://bencane.com/2012/08/06/troubleshooting-high-io-wait-in-linux/

https://www.ibm.com/developerworks/cn/linux/l-memmod/index.html

https://www.ibm.com/developerworks/cn/linux/l-cn-hugetlb/

https://github.com/gatieme/LDD-LinuxDeviceDrivers/blob/master/study/kernel/02-memory/02-pagetable/01-develop/README.md

cgroup其他部分 IO + hugepage的更多相关文章

  1. Linux资源管理-IO优先级

    前一篇博客介绍了利用 cgroup 来控制进程的 CPU和内存使用情况, 这次补上使用 cgroup 来控制进程的IO优先级的方法. 前提条件 如果想控制进程的IO优先级, 需要内核的支持, 内核编译 ...

  2. Linux的IO调度

    Linux的IO调度 IO调度发生在Linux内核的IO调度层.这个层次是针对Linux的整体IO层次体系来说的.从read()或者write()系统调用的角度来说,Linux整体IO体系可以分为七层 ...

  3. 如何提高Linux下块设备IO的整体性能?

    编辑手记:本文主要讲解Linux IO调度层的三种模式:cfp.deadline和noop,并给出各自的优化和适用场景建议. 作者简介: 邹立巍 Linux系统技术专家.目前在腾讯SNG社交网络运营部 ...

  4. Linux内核配置选项

    http://blog.csdn.net/wdsfup/article/details/52302142 http://www.manew.com/blog-166674-12962.html Gen ...

  5. 乐视云计算基于OpenStack的IaaS实践

    本文作者岳龙广,现在就职于乐视云计算有限公司,负责IaaS部门的工作. 从开始工作就混在开源世界里,在虚拟化方面做过CloudStack/Ovirt开发,现在是做以OpenStack为基础的乐视云平台 ...

  6. 进程的proc文件系统信息

    一.实验代码 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include &l ...

  7. 架构师养成记--21.netty编码解码

    背景 作为网络传输框架,免不了哟啊传输对象,对象在传输之前就要序列化,这个序列化的过程就是编码过程.接收到编码后的数据就需要解码,还原传输的数据. 代码 工厂类 import io.netty.han ...

  8. 架构师养成记--20.netty的tcp拆包粘包问题

    问题描述 比如要发ABC DEFG HIJK 这一串数据,其中ABC是一个包,DEFG是一个包,HIJK是一个包.由于TCP是基于流发送的,所以有可能出现ABCD EFGH 这种情况,那么ABC和D就 ...

  9. Linux systemd资源控制初探

    Linux systemd资源控制初探 本文记录一次cgroup子目录丢失问题,并简单探索了Linux systemd的资源控制机制. 问题现象 我们希望通过systemd拉起服务并通过cgroup限 ...

随机推荐

  1. sendBroadcast无法接收消息可能原因

    Beginning with Android 8.0 (API level 26), the system imposes additional restrictions on manifest-de ...

  2. Linux移植之tag参数列表解析过程分析

    在Linux移植之内核启动过程start_kernel函数简析中已经指出了start_kernel函数的调用层次,这篇主要是对具体的tag参数列表进行解析. 1.内存参数ATAG_MEM参数解析 2. ...

  3. spring mvc mybatis shiro构建cms系统ios android

    开发语言: java.ios.android 部署平台: linux.window jdk版本:JDK1.7以上版本 开发工具: eclipse.idea等 服务器中间件:Tomcat 6.7.Jbo ...

  4. IOS内存管理详解

    一.    基本原理 1.        什么是内存管理 移动设备的内存极其有限,每个app所能占用的内存是有限制的 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空 ...

  5. MySQL八、备份和还原

                MySQL 八.数据库备份和还原       1.二进制日志相关配置     1)查看使用中的二进制日志文件列表,及大小   SHOW {BINARY | MASTER} LO ...

  6. HTML之<meta>使用和说明

    关于<meta>,我们都不陌生,随意打开一个网页查看源代码就可以看到<head>里出现它的身影. 简单来说,<meta>是描述 HTML 文档的元数据.例如网页描述 ...

  7. ubuntu16.04安装最新版docker、docker-compose、docker-machine

    安装前说明: 本文将介绍在ubuntu16.04系统下安装和升级docker.docker-compose.docker-machine. docker:有两个版本:docker-ce(社区版)和do ...

  8. 调用redis的时候二维码不断刷新的排查

    一.背景和现象. 项目是PHP开发的,点击登录的时候就根据随机数生成了二维码,缓存在了redis.用户用微信扫描了二维码分析出需要请求的链接,然后微信浏览器就请求了服务器,服务器通过了随机数认证.正当 ...

  9. 2018CCPC-女生专场

    (咕咕咕,咕了快一年的bu题.. A.CCPC直播 传送:http://acm.hdu.edu.cn/showproblem.php?pid=6297 题意:rt. 分析:模拟. #include&l ...

  10. 解决C#调用执行js报检索 COM 类工厂中 CLSID 为 {0E59F1D5-1FBE-11D0-8FF2-00A0D10038BC} 组件失败

    最近做了一个模拟请求的网站简化原网站的繁琐数据,提出有用的数据简单展示并完成post.由于原网站数据有js加密,所以我抓出原网站的js解密方法,由C#调用js得到解密后的数据. 整个抓包的框架是用的苏 ...