概述

分享一个工作中的小技巧,当你监控发现磁盘IO很高的时候,想知道是哪个进程导致的该怎么办?

目前常用的IO观察工具用和,具体功能上说当然是更胜一筹,在IO统计上时间点上更具体精细。但二者都是在全局上看到IO,宏观上的数据对于判断IO到哪个文件上毫无帮助,这个时候的作用就显现出来了。

使用分析

1、启动和关闭

为什么需要先停掉功能?因为具体IO数据要通过输出,如果存在,则会往产生大量IO,干扰正常结果。

#/etc/init.d/rsyslog stop
#echo 1 > /proc/sys/vm/block_dump

dmesg时间_dmesg_dmesg-T

2、查看前十个IO占比高的进程

dmesg | awk ‘/(READ|WRITE|)/ {[$1]++} END {for (x in ) print [x],x}’ |sort -nr |awk ‘{print $2 ” ” $1}’ | head -n 10

dmesg时间_dmesg_dmesg-T

下图的dmesg结果可以看到IO基本是的3212进程

dmesg时间_dmesg_dmesg-T

通过dmesg信息可以看到IO正在写那些文件,有进程号,inode号,文件名和磁盘设备名;但每个文件写了多少呢,仅仅通过 inode就看不出来了,还需要分析WRITE block,后面的数字并不是真正的块号,而是内核IO层获取的扇区号,除以8即为块号,然后根据工具的和选项,就可以获取该文件系统块属于哪个具体文件。

3、关掉和启动

echo 0 > /proc/sys/vm/

/etc/init.d/ start

dmesg-T_dmesg时间_dmesg

基本原理:

的原理其实很简单,内核在IO层根据标志在IO提交给磁盘的关口卡主过关的每一个BIO,将它们的数据打出来:

void submit_bio(int rw, struct bio *bio)
{
 int count = bio_sectors(bio);
 
 bio->bi_rw |= rw;
 
/*
* If it's a regular read/write or a barrier with data attached,
* go through the normal accounting stuff before submission.
*/
 if (bio_has_data(bio) && !(rw & REQ_DISCARD)) {
 if (rw & WRITE) {
 count_vm_events(PGPGOUT, count);
 } else {
 task_io_account_read(bio->bi_size);
 count_vm_events(PGPGIN, count);
 }
 
 if (unlikely(block_dump)) {
 char b[BDEVNAME_SIZE];
 printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)n",
 current->comm, task_pid_nr(current),
 (rw & WRITE) ? "WRITE" : "READ",
 (unsigned long long)bio->bi_sector,
 bdevname(bio->bi_bdev, b),
 count);
 }
 }
 
 generic_make_request(bio);
}

具体WRITE block块号和文件系统块号之间的对应关系在函数中决定

bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);

inode的实现是通过搞定的,这次把关口架在inode脏数据写回的路上,把每个过关的inode信息打出来:

void __mark_inode_dirty(struct inode *inode, int flags)
{ 
if (unlikely(block_dump))
block_dump___mark_inode_dirty(inode);
}
static noinline void block_dump___mark_inode_dirty(struct inode *inode)
{
if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) {
struct dentry *dentry;
const char *name = "?";
 
dentry = d_find_alias(inode);
if (dentry) {
spin_lock(&dentry->d_lock);
name = (const char *) dentry->d_name.name;
}
printk(KERN_DEBUG
"%s(%d): dirtied inode %lu (%s) on %sn",
current->comm, task_pid_nr(current), inode->i_ino,
name, inode->i_sb->s_id);
if (dentry) {
spin_unlock(&dentry->d_lock);
dput(dentry);
}
}

dmesg-T_dmesg时间_dmesg

Linux 内核里 参数主要用来把 block 读写(WRITE/READ)状况 dump 到日志里,可以通过 dmesg 命令来查看,不过我还是习惯拿来抓一些IO比较高的进程。

———END———
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,永久会员只需109元,全站资源免费下载 点击查看详情
站 长 微 信: nanadh666

声明:1、本内容转载于网络,版权归原作者所有!2、本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。3、本内容若侵犯到你的版权利益,请联系我们,会尽快给予删除处理!