![确定负责高 I/O 的特定文件](https://linux22.com/image/49398/%E7%A1%AE%E5%AE%9A%E8%B4%9F%E8%B4%A3%E9%AB%98%20I%2FO%20%E7%9A%84%E7%89%B9%E5%AE%9A%E6%96%87%E4%BB%B6.png)
这是一个简单的问题,但我第一次真正解决它:查找哪些特定文件/索引节点是最多 I/O 的目标。我希望能够获得一般系统概述,但如果我必须提供 PID 或 TID,我也可以接受。
我想不必strace
对弹出的程序进行操作iotop
。最好使用iotop
与按文件逐项列出的工具相同的工具。我可以用它lsof
来查看 mailman 打开了哪些文件,但它并不表明哪个文件正在接收 I/O 或有多少。
我在其他地方看到建议使用它,auditd
但我不想这样做,因为它会将信息放入我们的审计文件中,我们将其用于其他目的,这似乎是我应该能够研究的问题这样。
我现在遇到的具体问题是 LVM 快照填充得太快。我已经解决了这个问题,但希望能够以这种方式修复它,而不是仅仅ls
对所有打开的文件描述符进行操作/proc/<pid>/fd
以查看哪个文件增长最快。
答案1
这个问题的几个方面已通过其他工具部分解决,但似乎没有一个工具可以提供您正在寻找的所有功能。
奥托普
该工具显示哪些进程消耗的 I/O 最多。但它缺少显示特定文件名的选项。
$ sudo iotop
Total DISK READ: 0.00 B/s | Total DISK WRITE: 0.00 B/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % init
2 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kthreadd]
3 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [ksoftirqd/0]
5 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kworker/u:0]
6 rt/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [migration/0]
7 rt/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [watchdog/0]
默认情况下,它执行常规top
进程对争夺 CPU 时间的操作(磁盘 I/O 除外)。您可以使用开关引导它为您提供 30,000 英尺的视图,-a
以便它显示随时间推移的过程累积情况。
$ sudo iotop -a
Total DISK READ: 0.00 B/s | Total DISK WRITE: 0.00 B/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
258 be/3 root 0.00 B 896.00 K 0.00 % 0.46 % [jbd2/dm-0-8]
22698 be/4 emma 0.00 B 72.00 K 0.00 % 0.00 % chrome
22712 be/4 emma 0.00 B 172.00 K 0.00 % 0.00 % chrome
1177 be/4 root 0.00 B 36.00 K 0.00 % 0.00 % cupsd -F
22711 be/4 emma 0.00 B 120.00 K 0.00 % 0.00 % chrome
22703 be/4 emma 0.00 B 32.00 K 0.00 % 0.00 % chrome
22722 be/4 emma 0.00 B 12.00 K 0.00 % 0.00 % chrome
i* 工具(inotify、iwatch 等)
这些工具提供对文件访问事件的访问,但是它们需要专门针对特定目录或文件。因此,在调试性能问题时尝试追踪未知进程的恶意文件访问时,它们并没有多大帮助。
此外,该inotify
框架不提供有关正在访问的文件的任何详细信息。使用这些工具仅提供访问类型,因此无法获得有关来回移动的数据量的信息。
iostat
显示基于对给定设备(硬盘驱动器)或分区的访问的整体性能(读取和写入)。但没有提供任何有关哪些文件正在生成这些访问的信息。
$ iostat -htx 1 1
Linux 3.5.0-19-generic (manny) 08/18/2013 _x86_64_ (3 CPU)
08/18/2013 10:15:38 PM
avg-cpu: %user %nice %system %iowait %steal %idle
18.41 0.00 1.98 0.11 0.00 79.49
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.01 0.67 0.09 0.87 1.45 16.27 37.06 0.01 10.92 11.86 10.82 5.02 0.48
dm-0
0.00 0.00 0.09 1.42 1.42 16.21 23.41 0.01 9.95 12.22 9.81 3.19 0.48
dm-1
0.00 0.00 0.00 0.02 0.01 0.06 8.00 0.00 175.77 24.68 204.11 1.43 0.00
块跟踪
这个选项级别太低了。它缺乏关于正在访问哪些文件和/或索引节点的可见性,仅了解原始块号。
$ sudo blktrace -d /dev/sda -o - | blkparse -i -
8,5 0 1 0.000000000 258 A WBS 0 + 0 <- (252,0) 0
8,0 0 2 0.000001644 258 Q WBS [(null)]
8,0 0 3 0.000007636 258 G WBS [(null)]
8,0 0 4 0.000011344 258 I WBS [(null)]
8,5 2 1 1266874889.709032673 258 A WS 852117920 + 8 <- (252,0) 852115872
8,0 2 2 1266874889.709033751 258 A WS 852619680 + 8 <- (8,5) 852117920
8,0 2 3 1266874889.709034966 258 Q WS 852619680 + 8 [jbd2/dm-0-8]
8,0 2 4 1266874889.709043188 258 G WS 852619680 + 8 [jbd2/dm-0-8]
8,0 2 5 1266874889.709045444 258 P N [jbd2/dm-0-8]
8,0 2 6 1266874889.709051409 258 I WS 852619680 + 8 [jbd2/dm-0-8]
8,0 2 7 1266874889.709053080 258 U N [jbd2/dm-0-8] 1
8,0 2 8 1266874889.709056385 258 D WS 852619680 + 8 [jbd2/dm-0-8]
8,5 2 9 1266874889.709111456 258 A WS 482763752 + 8 <- (252,0) 482761704
...
^C
...
Total (8,0):
Reads Queued: 0, 0KiB Writes Queued: 7, 24KiB
Read Dispatches: 0, 0KiB Write Dispatches: 3, 24KiB
Reads Requeued: 0 Writes Requeued: 0
Reads Completed: 0, 0KiB Writes Completed: 5, 24KiB
Read Merges: 0, 0KiB Write Merges: 3, 12KiB
IO unplugs: 2 Timer unplugs: 0
Throughput (R/W): 0KiB/s / 510KiB/s
Events (8,0): 43 entries
Skips: 0 forward (0 - 0.0%)
法特拉斯
这是 Linux 内核的一项新增功能,并且很受欢迎,因此它仅出现在较新的发行版中,例如 Ubuntu 12.10。我的 Fedora 14 系统缺少它 8-)。
inotify
它提供了与您无需针对特定目录和/或文件即可获得的相同访问权限。
$ sudo fatrace
pickup(4910): O /var/spool/postfix/maildrop
pickup(4910): C /var/spool/postfix/maildrop
sshd(4927): CO /etc/group
sshd(4927): CO /etc/passwd
sshd(4927): RCO /var/log/lastlog
sshd(4927): CWO /var/log/wtmp
sshd(4927): CWO /var/log/lastlog
sshd(6808): RO /bin/dash
sshd(6808): RO /lib/x86_64-linux-gnu/ld-2.15.so
sh(6808): R /lib/x86_64-linux-gnu/ld-2.15.so
sh(6808): O /etc/ld.so.cache
sh(6808): O /lib/x86_64-linux-gnu/libc-2.15.so
上面显示了正在进行文件访问的进程 ID 以及它正在访问哪个文件,但它没有提供任何总体带宽使用情况,因此每次访问与任何其他访问都无法区分。
那么该怎么办?
该fatrace
选项显示了最有希望的最后提供一个工具,可以根据正在访问的文件(而不是执行访问的进程)显示磁盘 I/O 的聚合使用情况。
参考
答案2
我还没有得到答案,但我确实写了这个脚本(最后),它似乎做了我想要的。我还没有在其他系统上测试过它,它是特定于 Linux 的。
基本上它只循环strace
30 秒,过滤与文件相关的系统调用,并努力删除文件名。它计算该文件在 中出现的次数,strace
并向用户提供分页摘要。它并不完美,但对特定文件的系统调用次数可能与其执行的 I/O 量有一些弱相关性。
我还没有完全测试过它,但如果它不能立即使用,它应该能为人们提供一个起点。如果它进一步充实,建议将其重写为更高级的语言像蟒蛇。
如果我在一周内没有得到一个不太自制的方法的答案(即使它是另一个只计算特定进程的 I/O 的工具),我会接受这个作为我对后代的答案。
脚本:
#!/bin/bash
####
# Creates files underneath /tmp
# Requires commands: timeout strace stty
####
#
# All commands are GNU unless otherwise stated
#
##########################################################
####
## Initialization
####
outputFile=/tmp/out.$RANDOM.$$
uniqueLinesFile=/tmp/unique.$RANDOM.$$
finalResults=/tmp/finalOutput.txt.$$
if [ $# -ne 1 ]; then
echo "USAGE: traceIO [PID]" >&2
exit 2
fi
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
echo "USAGE: traceIO [PID]" >&2
echo -e "\nGiven Process ID is not a number." >&2
exit 2
fi
if [ ! -e /proc/$1 ]; then
echo "USAGE: traceIO [PID]" >&2
echo -e "\nThere is no process with $1 as the PID." >&2
exit 2
fi
if [[ "x$PAGER" == "x" ]]; then
for currentNeedle in less more cat; do
which $currentNeedle >/dev/null 2>&1
if [ $? -eq 0 ]; then
PAGER=$currentNeedle
break;
fi
done
if [[ "x$PAGER" == "x" ]]; then
echo "Please set \$PAGER appropriately and re-run" >&2
exit 1
fi
fi
####
## Tracing
####
echo "Tracing command for 30 seconds..."
timeout 30 strace -e trace=file -fvv -p $1 2>&1 | egrep -v -e "detached$" -e "interrupt to quit$" | cut -f2 -d \" > $outputFile
if [ $? -ne 0 ]; then
echo -e "\nError performing Trace. Exiting"
rm -f $outputFile 2>/dev/null
exit 1
fi
echo "Trace complete. Preparing Results..."
####
## Processing
####
sort $outputFile | uniq > $uniqueLinesFile
echo -e "\n-------- RESULTS --------\n\n #\t Path " > $finalResults
echo -e " ---\t-------" >> $finalResults
while IFS= read -r currentLine; do
echo -n $(grep -c "$currentLine" "$outputFile")
echo -e "\t$currentLine"
done < "$uniqueLinesFile" | sort -rn >> $finalResults
####
## Presentation
####
resultSize=$(wc -l $finalResults | awk '{print $1}')
currentWindowSize=$(stty size | awk '{print $1}')
# We put five literal lines in the file so if we don't have more than that, there were no results
if [ $resultSize -eq 5 ]; then
echo -e "\n\n No Results found!"
elif [ $resultSize -ge $currentWindowSize ] ; then
$PAGER $finalResults
else
cat $finalResults
fi
# Cleanup
rm -f $uniqueLinesFile $outputFile $finalResults
答案3
您可以使用sysdig
它有一个名为的凿子topfiles_bytes
,正是这样做的。
例子:
sysdig -c topfiles_bytes
sysdig -c topfiles_time
列出所有可用的凿子:
sysdig -cl
答案4
使用 奥托普获取使 io 负载最多的进程的 pid。下次使用拉索夫获取 pid 打开的文件列表。