概述
分享一个工作中的小技巧,当你监控发现磁盘IO很高的时候,想知道是哪个进程导致的该怎么办?
目前常用的IO观察工具用和,具体功能上说当然是更胜一筹,在IO统计上时间点上更具体精细。但二者都是在全局上看到IO,宏观上的数据对于判断IO到哪个文件上毫无帮助,这个时候的作用就显现出来了。
使用分析
1、启动和关闭
为什么需要先停掉功能?因为具体IO数据要通过输出,如果存在,则会往产生大量IO,干扰正常结果。
#/etc/init.d/rsyslog stop #echo 1 > /proc/sys/vm/block_dump
2、查看前十个IO占比高的进程
dmesg | awk ‘/(READ|WRITE|)/ {[$1]++} END {for (x in ) print [x],x}’ |sort -nr |awk ‘{print $2 ” ” $1}’ | head -n 10
下图的dmesg结果可以看到IO基本是的3212进程
通过dmesg信息可以看到IO正在写那些文件,有进程号,inode号,文件名和磁盘设备名;但每个文件写了多少呢,仅仅通过 inode就看不出来了,还需要分析WRITE block,后面的数字并不是真正的块号,而是内核IO层获取的扇区号,除以8即为块号,然后根据工具的和选项,就可以获取该文件系统块属于哪个具体文件。
3、关掉和启动
echo 0 > /proc/sys/vm/
/etc/init.d/ start
基本原理:
的原理其实很简单,内核在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); } }
Linux 内核里 参数主要用来把 block 读写(WRITE/READ)状况 dump 到日志里,可以通过 dmesg 命令来查看,不过我还是习惯拿来抓一些IO比较高的进程。
———END———
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,永久会员只需109元,全站资源免费下载 点击查看详情
站 长 微 信: nanadh666