打通IO栈:一次编译服务器性能优化实战( 三 )


ext4挂载参数: dataext4有3种日志模式 , 分别是ordered , writeback , journal 。 他们的差别网上有很多资料 , 我简单介绍下:

  1. jorunal:把元数据与数据一并写入到日志块 。 性能差不多折半 , 因为数据写了两次 , 但最安全
  2. writeback: 把元数据写入日志块 , 数据不写入日志块 , 但不保证数据先落盘 。 性能最高 , 但由于不保证元数据与数据的顺序 , 也是掉电最不安全的
  3. ordered:与writeback相似 , 但会保证数据先落盘 , 再是元数据 。 这种性能以保证足够的安全 , 这是大多数PC上推荐的默认的模式
在不需要担心掉电的服务器环境 , 我们完全可以使用writeback的日志模式 , 以获取最高的性能 。
# mount -o remount,rw,data=http://kandian.youth.cn/index/writeback /homemount: /home not mounted or bad option# dmesg[235737.532630] EXT4-fs (vda1): Cannot change data mode on remount沮丧 , 又是不能动态改 , 干脆写入到/etc/config , 只能寄希望于下次重启了 。
# cat /etc/fstabUUID=.../homeext4defaults,rw,data=http://kandian.youth.cn/index/writeback...ext4挂载参数:noatimeLinux上对每个文件都记录了3个时间戳
时间戳全称含义atimeaccess time访问时间 , 就是最近一次读的时间mtimedata modified time数据修改时间 , 就是内容最后一次改动时间ctimestatus change time文件状态(元数据)的改变时间 , 比如权限 , 所有者等
我们编译执行的Make可以根据修改时间来判断是否要重新编译 , 而atime记录的访问时间其实在很多场景下都是多余的 。 所以 , noatime应运而生 。 不记录atime可以大量减少读造成的元数据写入量 , 而元数据的写入往往产生大量的随机IO 。
# mount -o ...noatime... /homeext4挂载参数:nobarrier这主要是决定在日志代码中是否使用写屏障(write barrier) , 对日志提交进行正确的磁盘排序 , 使易失性磁盘写缓存可以安全使用 , 但会带来一些性能损失 。 从功能来看 , 跟writeback和ordered日志模式非常相似 。 没研究过这方面的源码 , 说不定就是一回事 。 不管怎么样 , 禁用写屏障毫无疑问能提高写性能 。
# mount -o ...nobarrier... /homeext4挂载参数:delallocdelalloc是 delayed allocation 的缩写 , 如果使能 , 则ext4会延缓申请数据块直至超时 。 为什么要延缓申请呢?在inode中采用多级索引的方式记录了文件数据所在的数据块编号 , 如果出现大文件 , 则会采用 extent 区段的形式 , 分配一片连续的块 , inode中只需要记录开始块号与长度即可 , 不需要索引记录所有的块 。 这除了减轻inode的压力之外 , 连续的块可以把随机写改为顺序写 , 加快写性能 。 连续的块也符合 局部性原理 , 在预读时可以加大命中概率 , 进而加快读性能 。
# mount -o ...delalloc... /homeext4挂载参数:inode_readahead_blksext4从inode表中预读的indoe block最大数量 。 访问文件必须经过inode获取文件信息、数据块地址 。 如果需要访问的inode都在内存中命中 , 就不需要从磁盘中读取 , 毫无疑问能提高读性能 。 其默认值是32 , 表示最大预读 32 × block_size 即 64K 的inode数据 , 在内存充足的情况下 , 我们毫无疑问可以进一步扩大 , 让其预读更多 。
# mount -o ...inode_readahead_blks=4096... /homeext4挂载参数:journal_async_commitcommit块可以不等待descriptor块 , 直接往磁盘写 。 这会加快日志的速度 。
# mount -o ...journal_async_commit... /homeext4挂载参数:commitext4一次缓存多少秒的数据 。 默认值是5 , 表示如果此时掉电 , 你最多丢失5s的数据量 。 设置更大的数据 , 就可以缓存更多的数据 , 相对的掉电也有可能丢失更多的数据 。 在此服务器不怕掉电的情况 , 把数值加大可以提高性能 。
# mount -o ...commit=1000... /homeext4挂载参数汇总最终在不能umount情况下 , 我执行的调整挂载参数的命令为:
mount -o remount,rw,noatime,nobarrier,delalloc,inode_readahead_blks=4096,journal_async_commit,commit=1800/home此外 , 在/etc/fstab中也对应修改过来 , 避免重启后优化丢失
# cat /etc/fstabUUID=.../homeext4defaults,rw,noatime,nobarrier,delalloc,inode_readahead_blks=4096,journal_async_commit,commit=1800,data=http://kandian.youth.cn/index/writeback 0 0...页缓存页缓存在FS与通用块层之间 , 其实也可以归到通用块层中 。 为了提高IO性能 , 减少真实的从磁盘读写的次数 , Linux内核设计了一层内存缓存 , 把磁盘数据缓存到内存中 。 由于内存以4K大小的 页 为单位管理 , 磁盘数据也以页为单位缓存 , 因此也称为页缓存 。 在每个缓存页中 , 都包含了部分磁盘信息的副本 。