First get this script and name it: iodump
#!/usr/bin/env perl
=pod
=head1 NAME
iodump - Compute per-PID I/O stats for Linux when iotop/pidstat/iopp are not available.
=head1 SYNOPSIS
Prepare the system:
dmesg -c
/etc/init.d/klogd stop
echo 1 > /proc/sys/vm/block_dump
Start the reporting:
while true; do sleep 1; dmesg -c; done | perl iodump
CTRL-C
Stop the system from dumping these messages:
echo 0 > /proc/sys/vm/block_dump
/etc/init.d/klogd start
=head1 LICENSE
This software is released to the public domain, with no guarantees whatsoever.
=cut
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use sigtrap qw(handler finish untrapped normal-signals);
my %tasks;
my $oktorun = 1;
my $line;
while ( $oktorun && (defined ($line = <>)) ) {
my ( $task, $pid, $activity, $where, $device );
( $task, $pid, $activity, $where, $device )
= $line =~ m/(\S+)\((\d+)\): (READ|WRITE) block (\d+) on (\S+)/;
if ( !$task ) {
( $task, $pid, $activity, $where, $device )
= $line =~ m/(\S+)\((\d+)\): (dirtied) inode \(.*?\) (\d+) on (\S+)/;
}
if ( $task ) {
my $s = $tasks{$pid} ||= { pid => $pid, task => $task };
++$s->{lc $activity};
++$s->{activity};
++$s->{devices}->{$device};
}
}
printf("%-15s %10s %10s %10s %10s %10s %s\n",
qw(TASK PID TOTAL READ WRITE DIRTY DEVICES));
foreach my $task (
reverse sort { $a->{activity} <=> $b->{activity} } values %tasks
) {
printf("%-15s %10d %10d %10d %10d %10d %s\n",
$task->{task}, $task->{pid},
($task->{'activity'} || 0),
($task->{'read'} || 0),
($task->{'write'} || 0),
($task->{'dirty'} || 0),
join(', ', keys %{$task->{devices}}));
}
sub finish {
my ( $signal ) = @_;
if ( $oktorun ) {
print STDERR "# Caught SIG$signal.\n";
$oktorun = 0;
}
else {
print STDERR "# Exiting on SIG$signal.\n";
exit(1);
}
}
Then turn on kernel messages about I/O:
echo 1 > /proc/sys/vm/block_dump
This makes the kernel start writing messages about every I/O operation that takes place. Now all you have to do is get those messages and feed them into the iodump script:
while true; do sleep 1; dmesg -c; done | perl iodump
Wait a little while, then cancel the script. The results should look something like the following:
# while true; do sleep 1; dmesg -c; done | perl iodump
^C# Caught SIGINT.
TASK PID TOTAL READ WRITE DIRTY DEVICES
firefox 4450 4538 251 4287 0 sda4, sda3
kjournald 2100 551 0 551 0 sda4
firefox 28452 185 185 0 0 sda4
kjournald 782 59 0 59 0 sda3
pdflush 31 30 0 30 0 sda4, sda3
syslogd 2485 2 0 2 0 sda3
firefox 28414 2 2 0 0 sda4, sda3
firefox 28413 1 1 0 0 sda4
firefox 28410 1 1 0 0 sda4
firefox 28307 1 1 0 0 sda4
firefox 28451 1 1 0 0 sda4
When finished, turn off kernel messages about I/O:
echo 0 > /proc/sys/vm/block_dump
主要是因为有太多系统日志记录,而系统日志记录会引发kjournald内核文件系统日志记录程序大量频繁读写。
[root@no02 ~]# while true; do sleep 1; dmesg -c; done | perl iodump
# Caught SIGINT.
TASK PID TOTAL READ WRITE DIRTY DEVICES
kjournald 1873 2082 0 2082 0 dm-0
kjournald 520 258 0 258 0 sda1
pdflush 18732 78 0 78 0 sda1
bash 15430 18 18 0 0 sda1
named 13285 11 11 0 0 dm-0
mysqld 6910 6 6 0 0 dm-0
syslogd 27718 3 0 3 0 sda1
sendmail 373 2 0 2 0 sda1
sendmail 466 2 0 2 0 sda1
procmail 670 1 0 1 0 sda1
sendmail 605 1 0 1 0 sda1
关闭syslog相关日志:
cat /etc/syslog.conf
# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.* /dev/console
# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none;named.none /var/log/messages
# The authpriv file has restricted access.
authpriv.* /var/log/secure
# Log all the mail messages in one place.
mail.* -/var/log/maillog
# Log cron stuff
cron.* /var/log/cron
# Everybody gets emergency messages
*.emerg *
# Save news errors of level crit and higher in a special file.
uucp,news.crit /var/log/spooler
# Save boot messages also to boot.log
local7.* /var/log/boot.log
重启syslog日志,发现io写频繁降下来。
service syslog restart