Linux下的IO監控與分析
近期要在公司內部做個Linux IO方面的培訓, 整理下手頭的資料給大家分享下
各種IO監視工具在Linux IO 體系結構中的位置
源自 Linux Performance and Tuning Guidelines.pdf
1 系統級IO監控
iostat
iostat -xdm 1 # 個人習慣
%util 代表磁碟繁忙程度。100% 表示磁碟繁忙, 0%表示磁碟空閒。但是注意,磁碟繁忙不代表磁碟(頻寬)利用率高
argrq-sz 提交給驅動層的IO請求大小,一般不小於4K,不大於max(readahead_kb, max_sectors_kb)
可用於判斷當前的IO模式,一般情況下,尤其是磁碟繁忙時, 越大代表順序,越小代表隨機
svctm 一次IO請求的服務時間,對於單塊盤,完全隨機讀時,基本在7ms左右,既尋道+旋轉延遲時間
注: 各統計量之間關係
=======================================
%util = ( r/s + w/s) * svctm / 1000 # 佇列長度 = 到達率 * 平均服務時間
avgrq-sz = ( rMB/s + wMB/s) * 2048 / (r/s + w/s) # 2048 為 1M / 512
=======================================
總結:
iostat 統計的是通用塊層經過合併(rrqm/s, wrqm/s)後,直接向裝置提交的IO資料,可以反映系統整體的IO狀況,但是有以下2個缺點:
1 距離業務層比較遙遠,跟程式碼中的write,read不對應(由於系統預讀 + pagecache + IO排程演算法等因素, 也很難對應)
2 是系統級,沒辦法精確到程序,比如只能告訴你現在磁碟很忙,但是沒辦法告訴你是誰在忙,在忙什麼?
2 程序級IO監控
iotop 和 pidstat (僅rhel6u系列)
iotop 顧名思義, io版的top
pidstat 顧名思義, 統計程序(pid)的stat,程序的stat自然包括程序的IO狀況
這兩個命令,都可以按程序統計IO狀況,因此可以回答你以下二個問題
-
- 當前系統哪些程序在佔用IO,百分比是多少?
- 佔用IO的程序是在讀?還是在寫?讀寫量是多少?
pidstat 引數很多,僅給出幾個個人習慣
pidstat -d 1 #只顯示IO
pidstat -u -r -d -t 1 # -d IO 資訊,
# -r 缺頁及記憶體資訊
# -u CPU使用率
# -t 以執行緒為統計單位
# 1 1秒統計一次
iotop, 很簡單,直接敲命令
block_dump, iodump
iotop 和 pidstat 用著很爽,但兩者都依賴於/proc/pid/io檔案匯出的統計資訊, 這個對於老一些的核心是沒有的,比如rhel5u2
因此只好用以上2個窮人版命令來替代:
echo 1 > /proc/sys/vm/block_dump # 開啟block_dump,此時會把io資訊輸入到dmesg中
# 原始碼: [email protected]_rw_blk.c:3213
watch -n 1 "dmesg -c | grep -oP \"\w+\(\d+\): (WRITE|READ)\" | sort | uniq -c"
# 不停的dmesg -c
echo 0 > /proc/sys/vm/block_dump # 不用時關閉
也可以使用現成的指令碼 iodump, 具體參見 http://code.google.com/p/maatkit/source/browse/trunk/util/iodump?r=5389
iotop.stp
systemtap指令碼,一看就知道是iotop命令的窮人複製版,需要安裝Systemtap, 預設每隔5秒輸出一次資訊
stap iotop.stp # examples/io/iotop.stp
總結
程序級IO監控 ,
- 可以回答系統級IO監控不能回答的2個問題
- 距離業務層相對較近(例如,可以統計程序的讀寫量)
但是也沒有辦法跟業務層的read,write聯絡在一起,同時顆粒度較粗,沒有辦法告訴你,當前程序讀寫了哪些檔案? 耗時? 大小 ?
3 業務級IO監控
ioprofile
ioprofile 命令本質上是 lsof + strace, 具體下載可見 http://code.google.com/p/maatkit/
ioprofile 可以回答你以下三個問題:
1 當前程序某時間內,在業務層面讀寫了哪些檔案(read, write)?
2 讀寫次數是多少?(read, write的呼叫次數)
3 讀寫資料量多少?(read, write的byte數)
假設某個行為會觸發程式一次IO動作,例如: "一個頁面點選,導致後臺讀取A,B,C檔案"
============================================
./io_event # 假設模擬一次IO行為,讀取A檔案一次, B檔案500次, C檔案500次
ioprofile -p `pidof io_event` -c count # 讀寫次數
ioprofile -p `pidof io_event` -c times # 讀寫耗時
ioprofile -p `pidof io_event` -c sizes # 讀寫大小
注: ioprofile 僅支援多執行緒程式,對單執行緒程式不支援. 對於單執行緒程式的IO業務級分析,strace足以。
總結:
ioprofile本質上是strace,因此可以看到read,write的呼叫軌跡,可以做業務層的io分析(mmap方式無能為力)
4 檔案級IO監控
檔案級IO監控可以配合/補充"業務級和程序級"IO分析
檔案級IO分析,主要針對單個檔案, 回答當前哪些程序正在對某個檔案進行讀寫操作.
1 lsof 或者 ls /proc/pid/fd
2 inodewatch.stp
lsof 告訴你 當前檔案由哪些程序開啟
lsof ../io # io目錄 當前由 bash 和 lsof 兩個程序開啟
lsof 命令 只能回答靜態的資訊, 並且"開啟" 並不一定"讀取", 對於 cat ,echo這樣的命令, 開啟和讀取都是瞬間的,lsof很難捕捉
可以用 inodewatch.stp 來彌補
stap inodewatch.stp major minor inode # 主裝置號, 輔裝置號, 檔案inode節點號
stap inodewatch.stp 0xfd 0x00 523170 # 主裝置號, 輔裝置號, inode號,可以通過 stat 命令獲得
5 IO模擬器
iotest.py # 見附錄
開發人員可以 利用 ioprofile (或者 strace) 做詳細分析系統的IO路徑,然後在程式層面做相應的優化。
但是一般情況下調整程式,代價比較大,尤其是當不確定修改方案到底能不能有效時,最好有某種模擬途徑以快速驗證。
以為我們的業務為例,發現某次查詢時,系統的IO訪問模式如下:
訪問了A檔案一次
訪問了B檔案500次, 每次16位元組, 平均間隔 502K
訪問了C檔案500次, 每次200位元組, 平均間隔 4M
這裡 B,C檔案是交錯訪問的, 既
1 先訪問B,讀16位元組,
2 再訪問C,讀200位元組,
3 回到B,跳502K後再讀16位元組,
4 回到C,跳4M後,再讀200位元組
5 重複500次
strace 檔案如下:
一個簡單樸素的想法, 將B,C交錯讀,改成先批量讀B , 再批量讀C,因此調整strace 檔案如下:
將調整後的strace檔案, 作為輸入交給 iotest.py, iotest.py 按照 strace 檔案中的訪問模式, 模擬相應的IO
iotest.py -s io.strace -f fmap
fmap 為對映檔案,將strace中的222,333等fd,對映到實際的檔案中
===========================
111 = /opt/work/io/A.data
222 = /opt/work/io/B.data
333 = /opt/work/io/C.data
===========================
6 磁碟碎片整理
一句話: 只要磁碟容量不常年保持80%以上,基本上不用擔心碎片問題。
如果實在擔心,可以用 defrag 指令碼
7 其他IO相關命令
blockdev 系列
=======================================
blockdev --getbsz /dev/sdc1 # 檢視sdc1盤的塊大小
block blockdev --getra /dev/sdc1 # 檢視sdc1盤的預讀(readahead_kb)大小
blockdev --setra 256 /dev/sdc1 # 設定sdc1盤的預讀(readahead_kb)大小,低版的核心通過/sys設定,有時會失敗,不如blockdev靠譜
=======================================
附錄 iotest.py
#! /usr/bin/env python # -*- coding: gbk -*- import os import re import timeit from ctypes import CDLL, create_string_buffer, c_ulong, c_longlong from optparse import OptionParser usage = '''%prog -s strace.log -f fileno.map ''' _glibc = None _glibc_pread = None _c_char_buf = None _open_file = [] def getlines(filename): _lines = [] with open(filename,'r') as _f: for line in _f: if line.strip() != "": _lines.append(line.strip()) return _lines def parsecmdline(): parser = OptionParser(usage) parser.add_option("-s", "--strace", dest="strace_filename", help="strace file", metavar="FILE") parser.add_option("-f", "--fileno", dest="fileno_filename", help="fileno file", metavar="FILE") (options, args) = parser.parse_args() if options.strace_filename is None: parser.error("strace is not specified.") if not os.path.exists(options.strace_filename): parser.error("strace file does not exist.") if options.fileno_filename is None: parser.error("fileno is not specified.") if not os.path.exists(options.strace_filename): parser.error("fileno file does not exist.") return options.strace_filename, options.fileno_filename # [type, ...] # [pread, fno, count, offset] # pread(15, "", 4348, 140156928) def parse_strace(filename): lines = getlines(filename) action = [] _regex_str = r'(pread|pread64)[^\d]*(\d+),\s*[^,]*,\s*([\dkKmM*+\-. ]*),\s*([\dkKmM*+\-. ]*)' for i in lines: _match = re.match(_regex_str, i) if _match is None: continue # 跳過無效行 _type, _fn, _count, _off = _match.group(1), _match.group(2), _match.group(3), _match.group(4) _off = _off.replace('k', " * 1024 ").replace('K', " * 1024 ").replace('m', " * 1048576 ").replace('M', " * 1048576 ") _count = _count.replace('k', " * 1024 ").replace('K', " * 1024 ").replace('m', " * 1048576 ").replace('M', " * 1048576 ") #print _off action.append([_type, _fn, str(int(eval(_count))), str(int(eval(_off))) ]) return action def parse_fileno(filename): lines = getlines(filename) fmap = {} for i in lines: if i.strip().startswith("#"): continue # 註釋行 _split = [j.strip() for j in i.split("=")] if len(_split) != 2: continue # 無效行 fno, fname = _split[0], _split[1] fmap[fno] = fname return fmap def simulate_before(strace, fmap): global _open_file, _c_char_buf rfmap = {} for i in fmap.values(): _f = open(i, "r+b") #print "open {0}:{1}".format(_f.fileno(), i) _open_file.append(_f) rfmap[i] = str(_f.fileno()) # 反向對映 to_read = 4 * 1024 # 預設4K buf for i in strace: i[1] = rfmap[fmap[i[1]]] # fid -> fname -> fid 對映轉換 to_read = max(to_read, int(i[2])) #print "read buffer len: %d Byte" % to_read _c_char_buf = create_string_buffer(to_read) def simulate_after(): global _open_file for _f in _open_file: _f.close() def simulate(actions): #timeit.time.sleep(10) # 休息2秒鐘, 以便IO間隔 start = timeit.time.time() for act in actions: __simulate__(act) finish = timeit.time.time() return finish - start def __simulate__(act): global _glibc, _glibc_pread, _c_char_buf if "pread" in act[0]: _fno = int(act[1]) _buf = _c_char_buf _count = c_ulong(int(act[2])) _off = c_longlong(int(act[3])) _glibc_pread(_fno, _buf, _count, _off) #print _glibc.time(None) else: pass pass def loadlibc(): global _glibc, _glibc_pread _glibc = CDLL("libc.so.6") _glibc_pread = _glibc.pread64 if __name__ == "__main__": _strace, _fileno = parsecmdline() # 解析命令列引數 loadlibc() # 載入動態庫 _action = parse_strace(_strace) # 解析 action 檔案 _fmap = parse_fileno(_fileno) # 解析 檔名對映 檔案 simulate_before(_action, _fmap) # 預處理 #print "total io operate: %d" % (len(_action)) #for act in _action: print " ".join(act) print "%f" % simulate(_action)
相關推薦
Linux下的IO監控與分析
近期要在公司內部做個Linux IO方面的培訓, 整理下手頭的資料給大家分享下 各種IO監視工具在Linux IO 體系結構中的位置
Linux IO 監控與深入分析
4.6 .cn 計時 說明 扇區 版本 play linux patch https://jaminzhang.github.io/os/Linux-IO-Monitoring-and-Deep-Analysis/ Linux IO 監控與深入分析 引言 接昨天電話面試
(轉)Linux下通過rsync與inotify(異步文件系統事件監控機制)實現文件實時同步
-a 推送 root started init.d log tool mysql同步 .tar.gz Linux下通過rsync與inotify(異步文件系統事件監控機制)實現文件實時同步原文:http://www.summerspacestation.com/linux%
Linux監控與分析工具nmon
一、概述 nmon是一種在AIX與各種Linux作業系統上廣泛使用的監控與分析工具,相對於其它一些系統資源監控工具來說,nmon所記錄的資訊是比較全面的,它能在系統執行過程中實時地捕捉系統資源的使用情況,並且能輸出結果到檔案中,然後通過nmon_analyzer工具產生資料檔案與圖形化結
Linux下程式設計------檔案與IO(三) 檔案共享和fcntl函式
檔案共享 一個程序打開了兩個檔案 檔案表條目(file-table-entry): 1.檔案狀態標誌(file-status-flags): 讀/寫/追加/同步/
Linux 下MySQL 安裝與卸載
word stat client int etc dpkg init net 是否 參考博客:http://www.cnblogs.com/steven_oyj/archive/2010/05/24/1742808.html http://www.linuxidc.com/
linux下LAMP安裝與配置
函數 rri osi ase live ins php expose share 安裝 一. Apache 安裝 yum install -y httpd啟動 /etc/init.d/httpd start備註:Apache啟動之後會提示錯誤: 正在啟動http
Linux下的打包與壓縮和tar命令!
tar.gz 安裝 gin font log 針對 更新 mil emp 本文介紹了linux下的打包壓縮程序tar、gzip、gunzip、bzip2、bunzip2、 compress、uncompress、zip、unzip、rar、unrar程序,以及如何使用它們對
Linux下安裝Nginx與配置
目錄 openssl oct pan yum安裝 usr 負載均衡 官方 err 一,安裝GCC yum安裝gcc-c ++ -y 二,安裝nginx的所需要的依賴庫 yum -y安裝zlib-devel openssl-devel pcre-devel
2017-2018-1 20179202《Linux內核原理與分析》第八周作業
預測 rar 合並 數據 代碼分析 一個 設置 堆棧 linu 一 、可執行程序的裝載 1. 預處理、編譯、鏈接 gcc –e –o hello.cpp hello.c //預處理 gcc -x cpp-output -S -o hello.s hello.cpp //
20179223《Linux內核原理與分析》第九周學習筆記
3.18 用戶 通過 linux內核 良好的 數據 context from inux 視頻學習 進程調度與進程調度的時機分析 不同類型的進程有不同的調度需求 第一種分類: ——I/O-bound:1.頻繁的進行I/O;2.通常會花費很多時間等待I/O操作的完成 ——CPU
2017-2018-1 20179202《Linux內核原理與分析》第九周作業
發生 png inpu 方法 地址轉換 blog pic int 內核棧 進程的切換和系統的一般執行過程 1.知識總結 (1)進程調度的時機: 中斷處理過程直接調用schedule(),或者返回用戶態時根據need_resched標記調用schedule()。 內核線程是
20179203 《Linux內核原理與分析》第十周作業
計時 使用 數據 一個個 類型 原則 聲明 標識 變量 第17章 設備與模塊 一、設備類型 1. Linux及Unix系統: 塊設備 字符設備 網絡設備 2.塊設備: 通常縮寫為blkdev,它是可尋址的,尋址以塊為單位,塊大小隨設備不同而不同;塊設備通常支持重定位操作,也
2017-2018-1 20179215《Linux內核原理與分析》第十周作業
自動填充 可移植性 智能 x86 調試 推薦 狀態 討論 ani 第17章 設備與模塊 一、設備類型 ?除了以上3種典型的設備之外,其實Linux中還有一些其他的設備類型,其中見的較多的應該算是"偽設備"。所謂"偽設備",其實就是一些虛擬的設備,僅提供訪問內核功能而已,沒
Linux下tomcat6.0與jdk安裝
可執行 tomcat6 環境變量 /var/ serve 兩個 所在 開機自啟動 完成後 Linux下tomcat6.0與jdk安裝 步驟如下: 1、 上傳apache-tomcat-6.0.37.tar.gz和jdk-6u13-linux-i586.bin至/usr/lo
Redis在Linux下的安裝與配置
conf eas etc 下載 127.0.0.1 基於內存 最新 ansi lin Redis是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日誌型、Key-Value數據庫,並提供多種語言的API。 Redis是 NoSQL技術陣營中的一員。 說到
2017-2018-1 20179215《Linux內核原理與分析》第十二周作業
繼續 解壓 判斷語句 cti 數據信息 接下來 分組 後臺數據庫 就是 Sql註入基礎原理介紹 分組:和20179205王雅哲共同完成實驗 一、實驗說明 1.1 sql註入 ?SQL註入攻擊通過構建特殊的輸入作為參數傳入Web應用程序,而這些輸入大都是SQL語法裏的一些組合
20179203 《Linux內核原理與分析》第十二周作業
系統管理 ash 數據讀取 用戶控制 tar 初始設置 可執行 uid time Return-to-libc 攻擊實驗 一、實驗描述 緩沖區溢出的常用攻擊方法是用 shellcode 的地址來覆蓋漏洞程序的返回地址,使得漏洞程序去執行存放在棧中 shellcode。為了
linux下FTP安裝與配置
linux ftp pure-ftpdcd /usr/local/src/wget http://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.42.tar.bz2 (下載pureftp源碼包)tar jxvf pure-f
linux下rsync安裝與配置
linux rsync rsync (同步數據,支持增量備份)使用方法:rsync -av 192.168.31.182:/tmp/1.txt /tmp/ (將服務器192.168.31.182中tmp文件夾下的1.txt文件拷貝到本機的tmp目錄下)rsync -av /tmp/1.tx