新聞中心
怎樣監(jiān)測(cè)Linux進(jìn)程的實(shí)時(shí)IO情況,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。
成都創(chuàng)新互聯(lián)長(zhǎng)期為上1000家客戶(hù)提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為望謨企業(yè)提供專(zhuān)業(yè)的網(wǎng)站建設(shè)、網(wǎng)站制作,望謨網(wǎng)站改版等技術(shù)服務(wù)。擁有十多年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。
Linux Kernel 2.6.20 以上的內(nèi)核支持進(jìn)程 IO 統(tǒng)計(jì),可以用類(lèi)似 iotop 這樣的工具來(lái)監(jiān)測(cè)每個(gè)進(jìn)程對(duì) IO 操作的情況,就像用 top 來(lái)實(shí)時(shí)查看進(jìn)程內(nèi)存、CPU 等占用情況那樣。但是對(duì)于 2.6.20 以下的 Linux 內(nèi)核版本就沒(méi)那么幸運(yùn)了。筆者寫(xiě)了一個(gè)簡(jiǎn)單的 Python 腳本用來(lái)在 linux kernel < 2.6.20 下打印進(jìn)程 IO 狀況。
Kernel < 2.6.20
這個(gè)腳本的想法很簡(jiǎn)單,把 dmesg 的結(jié)果重定向到一個(gè)文件后再解析出來(lái),每隔1秒鐘打印一次進(jìn)程 IO 讀寫(xiě)的統(tǒng)計(jì)信息,執(zhí)行這個(gè)腳本需要 root:
1. #!/usr/bin/python
2. # Monitoring per-process disk I/O activity
3. # written by http://www.vpsee.com
4.
5. import sys, os, time, signal, re
6.
7. class DiskIO:
8. def __init__(self, pname=None, pid=None, reads=0, writes=0):
9. self.pname = pname
10. self.pid = pid
11. self.reads = 0
12. self.writes = 0
13.
14. def main():
15. argc = len(sys.argv)
16. if argc != 1:
17. print "usage: ./iotop"
18. sys.exit(0)
19.
20. if os.getuid() != 0:
21. print "must be run as root"
22. sys.exit(0)
23.
24. signal.signal(signal.SIGINT, signal_handler)
25. os.system('echo 1 > /proc/sys/vm/block_dump')
26. print "TASK PID READ WRITE"
27. while True:
28. os.system('dmesg -c > /tmp/diskio.log')
29. l = []
30. f = open('/tmp/diskio.log', 'r')
31. line = f.readline()
32. while line:
33. m = re.match(\
34. '^(\S+)\((\d+)\): (READ|WRITE) block (\d+) on (\S+)', line)
35. if m != None:
36. if not l:
37. l.append(DiskIO(m.group(1), m.group(2)))
38. line = f.readline()
39. continue
40. found = False
41. for item in l:
42. if item.pid == m.group(2):
43. found = True
44. if m.group(3) == "READ":
45. item.reads = item.reads + 1
46. elif m.group(3) == "WRITE":
47. item.writes = item.writes + 1
48. if not found:
49. l.append(DiskIO(m.group(1), m.group(2)))
50. line = f.readline()
51. time.sleep(1)
52. for item in l:
53. print "%-10s %10s %10d %10d" % \
54. (item.pname, item.pid, item.reads, item.writes)
55.
56. def signal_handler(signal, frame):
57. os.system('echo 0 > /proc/sys/vm/block_dump')
58. sys.exit(0)
59.
60. if __name__=="__main__":
61. main()
62.
Kernel >= 2.6.20
如果想用 iotop 來(lái)實(shí)時(shí)查看進(jìn)程 IO 活動(dòng)狀況的話(huà),需要下載和升級(jí)新內(nèi)核(2.6.20 或以上版本)。編譯新內(nèi)核時(shí)需要打開(kāi) TASK_DELAY_ACCT 和 TASK_IO_ACCOUNTING 選項(xiàng)。解壓內(nèi)核后進(jìn)入配置界面:
# tar jxvf linux-2.6.30.5.tar.bz2
# mv linux-2.6.30.5 /usr/src/
# cd /usr/src/linux-2.6.30.5
# make menuconfig
選擇 Kernel hacking –> Collect scheduler debugging info 和 Collect scheduler statistics,保存內(nèi)核后編譯內(nèi)核:
# make; make modules; make modules_install; make install
修改 grub,確認(rèn)能正確啟動(dòng)新內(nèi)核:
# vi /boot/grub/menu.lst
出了新內(nèi)核外,iotop 還需要 Python 2.5 或以上才能運(yùn)行,所以如果當(dāng)前 Python 是 2.4 的話(huà)需要下載和安裝最新的 Python 包。這里使用源代碼編譯安裝:
# tar jxvf Python-2.6.2.tar.bz2
# cd Python-2.6.2
# ./configure
# make; make install
別忘了下載 setuptools:
# mv setuptools-0.6c9-py2.6.egg.sh setuptools-0.6c9-py2.6.egg
# sh setuptools-0.6c9-py2.6.egg
有網(wǎng)友對(duì)以上腳本提出問(wèn)題,問(wèn)到 WRITE 為什么會(huì)出現(xiàn)是 0 的情況,這是個(gè)好問(wèn)題,筆者在這里好好解釋一下。首先看看我們?cè)趺礃硬拍軐?shí)時(shí)監(jiān)測(cè)不同進(jìn)程的 IO 活動(dòng)狀況。
block_dump
Linux 內(nèi)核里提供了一個(gè) block_dump 參數(shù)用來(lái)把 block 讀寫(xiě)(WRITE/READ)狀況 dump 到日志里,這樣可以通過(guò) dmesg 命令來(lái)查看,具體操作步驟是:
# sysctl vm.block_dump=1
or
# echo 1 > /proc/sys/vm/block_dump
然后就可以通過(guò) dmesg 就可以觀察到各個(gè)進(jìn)程 IO 活動(dòng)的狀況了:
# dmesg -c
kjournald(542): WRITE block 222528 on dm-0
kjournald(542): WRITE block 222552 on dm-0
bash(18498): dirtied inode 5892488 (ld-linux-x86-64.so.2) on dm-0
bash(18498): dirtied inode 5892482 (ld-2.5.so) on dm-0
dmesg(18498): dirtied inode 11262038 (ld.so.cache) on dm-0
dmesg(18498): dirtied inode 5892496 (libc.so.6) on dm-0
dmesg(18498): dirtied inode 5892489 (libc-2.5.so) on dm-0
問(wèn)題
一位細(xì)心的網(wǎng)友提到這樣一個(gè)問(wèn)題:為什么會(huì)有 WRITE block 0 的情況出現(xiàn)呢?筆者跟蹤了一段時(shí)間,發(fā)現(xiàn)確實(shí)有 WRITE 0 的情況出現(xiàn),比如:
# dmesg -c
...
pdflush(23123): WRITE block 0 on sdb1
pdflush(23123): WRITE block 16 on sdb1
pdflush(23123): WRITE block 104 on sdb1
pdflush(23123): WRITE block 40884480 on sdb1
...
答案
原來(lái)我們把 WRITE block 0,WRITE block 16, WRITE block 104 這里面包含的數(shù)字理解錯(cuò)了,這些數(shù)字不是代表寫(xiě)了多少 blocks,是代表寫(xiě)到哪個(gè) block,為了尋找真相,筆者追到 Linux 2.6.18 內(nèi)核代碼里,在 ll_rw_blk.c 里找到了答案:
$ vi linux-2.6.18/block/ll_rw_blk.c
1. void submit_bio(int rw, struct bio *bio)
2. {
3. int count = bio_sectors(bio);
4.
5. BIO_BUG_ON(!bio->bi_size);
6. BIO_BUG_ON(!bio->bi_io_vec);
7. bio->bi_rw |= rw;
8. if (rw & WRITE)
9. count_vm_events(PGPGOUT, count);
10. else
11. count_vm_events(PGPGIN, count);
12.
13. if (unlikely(block_dump)) {
14. char b[BDEVNAME_SIZE];
15. printk(KERN_DEBUG "%s(%d): %s block %Lu on %s\n",
16. current->comm, current->pid,
17. (rw & WRITE) ? "WRITE" : "READ",
18. (unsigned long long)bio->bi_sector,
19. bdevname(bio->bi_bdev,b));
20. }
21.
22. generic_make_request(bio);
23. }
很明顯從上面代碼可以看出 WRITE block 0 on sdb1,這里的 0 是 bio->bi_sector,是寫(xiě)到哪個(gè) sector,不是 WRITE 了多少 blocks 的意思。還有,如果 block 設(shè)備被分成多個(gè)區(qū)的話(huà),這個(gè) bi_sector(sector number)是從這個(gè)分區(qū)開(kāi)始計(jì)數(shù),比如 block 0 on sdb1 就是 sdb1 分區(qū)上的第0個(gè) sector 開(kāi)始。
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)的支持。
本文題目:怎樣監(jiān)測(cè)Linux進(jìn)程的實(shí)時(shí)IO情況
鏈接URL:http://www.ef60e0e.cn/article/pgjoch.html