性能瓶頸--DISK(I/O)

說到磁盤,這是數(shù)據(jù)持久化保存的一種保存媒介,也是計(jì)算機(jī)必不可少的一種硬件設(shè)備严蓖,而想要用到磁盤就必須提到文件系統(tǒng)。

文件系統(tǒng)

文件系統(tǒng)是構(gòu)建在磁盤上的氧急,用來管理文件的颗胡。為了方便管理,Linux為每個(gè)文件都分配了兩個(gè)數(shù)據(jù)結(jié)構(gòu)吩坝,索引節(jié)點(diǎn)(index node)和目錄項(xiàng)(directory entry)他們主要用來記錄文件的元信息和目錄結(jié)構(gòu)毒姨。

  • 索引節(jié)點(diǎn):又稱為inode。用來記錄文件的元數(shù)據(jù)钉寝,他和文件內(nèi)容一樣是會被持久化存儲的弧呐。(存儲到磁盤)
  • 目錄項(xiàng):又稱為dentry闸迷。用來記錄文件的名字、索引節(jié)點(diǎn)指針以及與其他目錄項(xiàng)的關(guān)聯(lián)關(guān)系俘枫,目錄項(xiàng)是由內(nèi)核維護(hù)的一種內(nèi)存數(shù)據(jù)結(jié)構(gòu)腥沽。(內(nèi)存緩存)


    文件系統(tǒng).png

每塊磁盤在使用前都需要格式化,而格式化后就會被分成三個(gè)存儲區(qū)鸠蚪,超級塊今阳,索引節(jié)點(diǎn)和數(shù)據(jù)塊區(qū)。

  • 超級塊:存儲整個(gè)文件系統(tǒng)的狀態(tài)
  • 索引節(jié)點(diǎn)區(qū):用來存儲索引節(jié)點(diǎn)
  • 數(shù)據(jù)塊區(qū):存儲數(shù)據(jù)茅信。

VFS

Linux在用戶進(jìn)程空間與文件系統(tǒng)中間由引入了一個(gè)抽象層盾舌。也就是虛擬文件系統(tǒng)VFS。VFS定義了一組所有文件系統(tǒng)都支持的數(shù)據(jù)結(jié)構(gòu)的標(biāo)準(zhǔn)接口汹押。這樣用戶進(jìn)程空間和內(nèi)核只需要和VFS交互矿筝,而不需要關(guān)系各種文件系統(tǒng)底層的實(shí)現(xiàn)關(guān)系了。
如下圖:


文件系統(tǒng).png

值得注意的是棚贾,文件系統(tǒng)不僅僅有基于磁盤的文件系統(tǒng)窖维,還有基于內(nèi)存的虛擬文件系統(tǒng),如/proc文件系統(tǒng)妙痹,再比如/sys 文件系統(tǒng)铸史。/sys 主要向用戶空間導(dǎo)出層次化的內(nèi)核對象。
在Linux中怯伊,磁盤是作為一個(gè)塊設(shè)備來管理的琳轿,并且支持隨機(jī)讀寫,每塊設(shè)備會被賦予兩個(gè)設(shè)備號耿芹,分別是主設(shè)備號和次設(shè)備號崭篡。主設(shè)備號用在驅(qū)動程序中,用來區(qū)分設(shè)備吧秕,而次設(shè)備號用來給多個(gè)同類設(shè)備編號琉闪。

通用塊層

Linux通過一個(gè)通用塊層來管理各種不同的設(shè)備。它會將文件系統(tǒng)和應(yīng)用程序發(fā)來的I/O請求排隊(duì)砸彬,并通過重新排序颠毙、請求合并等方式來提高磁盤的讀寫效率。
對于I/O請求排序的過程砂碉,也就是I/O調(diào)度算法蛀蜜,通常Linux支持4種調(diào)度算法,分別是NONE增蹭,NOOP滴某,CFQ以及DeadLine。
這里不做詳細(xì)的介紹。只是簡單提一下壮池。

  • NONE 不做任何I/O調(diào)度偏瓤,通常在虛擬機(jī)中杀怠,此時(shí)的磁盤I/O交給宿主機(jī)負(fù)責(zé)椰憋。
  • NOOP 先入先出隊(duì)列,只做一些簡單的請求合并赔退。
  • CFQ 完全公平調(diào)度器橙依。為每一個(gè)進(jìn)程都維護(hù)一個(gè)I/O調(diào)度隊(duì)列。并按事件片來均勻分布每一個(gè)進(jìn)程的I/O請求硕旗。(最適合運(yùn)行大量進(jìn)程的系統(tǒng))
  • DeadLine 分別為讀窗骑、寫請求創(chuàng)建了不同的I/O隊(duì)列。多用在I/O壓力比較重的場景漆枚,如日志歸集创译,數(shù)據(jù)庫服務(wù)器。

Linux的I/O

Linux的I/O棧就是由 文件系統(tǒng)墙基,通用塊和設(shè)備層組成了软族。
小結(jié)一下。

  • 文件系統(tǒng)層:包括虛擬文件系統(tǒng)和其他各種文件系統(tǒng)的實(shí)現(xiàn)残制。它為上層的應(yīng)用程序提供標(biāo)準(zhǔn)的訪問接口立砸。對下層通過通用塊層來存儲和管理磁盤數(shù)據(jù)。
  • 通用塊層: 管理塊設(shè)備I/O隊(duì)列和I/O調(diào)度器初茶。會對文件系統(tǒng)傳過來的I/O 請求進(jìn)行排隊(duì)颗祝,再重新組合排序,發(fā)給下一層的設(shè)備層恼布。
  • 設(shè)備層:負(fù)責(zé)最終的物理設(shè)備的I/O操作螺戳。

磁盤的性能指標(biāo)

最常見的指標(biāo)有五種。分別是使用率折汞,飽和度倔幼,IOPS,吞吐量以及響應(yīng)時(shí)間字支。

  • 使用率:是指磁盤處理I/O的時(shí)間百分比凤藏。一般超過80%就意味著磁盤性能瓶頸了。
  • 飽和度:是指磁盤處理I/O的繁忙程度堕伪。當(dāng)飽和度為100%時(shí)揖庄,磁盤無法再接受新的I/O請求。
  • IOPS :每秒的I/O請求數(shù)欠雌。
  • 吞吐量:每秒的I/O請求大小蹄梢。
  • 響應(yīng)時(shí)間:是指I/O請求從發(fā)出到收到響應(yīng)的間隔時(shí)間。

例如在數(shù)據(jù)庫,大量小文件等這種隨機(jī)讀寫比較多的場景禁炒,IOPS可以更好反映出系統(tǒng)的整體性能而咆。而多媒體等順序讀寫較多的場景中,吞吐量才是重點(diǎn)幕袱。

磁盤I/O狀態(tài)查看工具

iostat

[root@vm1 ~] # iostat -d -x 1
Linux 3.10.0-957.el7.x86_64 (vm.oom-killer.org)     2019年04月07日     _x86_64_    (2 CPU)

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.00     0.01    0.16    0.16     6.50     2.47    56.73     0.00    6.26   11.91    0.53   2.75   0.09
dm-0              0.00     0.00    0.13    0.17     5.29     2.39    51.92     0.00    6.50   14.24    0.55   2.91   0.09
dm-1              0.00     0.00    0.00    0.00     0.09     0.00    54.67     0.00    0.62    0.62    0.00   0.52   0.00

指標(biāo)的含義:

  • r/s:每秒的讀請求暴备。
  • w/s:每秒的寫請求。
  • rkB/s:每秒從磁盤讀取的數(shù)據(jù)量们豌。單位KB涯捻。
  • wkB/s:每秒往磁盤寫入的數(shù)據(jù)量。單位KB望迎。
  • rrqm?s:每秒合并的讀請求數(shù)障癌。
  • wrqm/s:每秒合并的寫請求書。
  • r_await:讀請求處理完成等待時(shí)間辩尊。
  • w_await:寫請求處理完成等待時(shí)間涛浙。
  • avgqu-sz:平均請求隊(duì)列長度。
  • rareq-sz:平均讀請求大小摄欲。
  • wareq-sz:平均寫請求大小轿亮。
  • svctm:處理I/O請求所需的平均時(shí)間。
  • %util:磁盤處理I/O的時(shí)間百分比蒿涎。
    上述指標(biāo)中:
    1 . %util 是磁盤I/O的使用率哀托。
    2 . r/s + w/s 是IOPS
    3 . rkB/s + wkB/s 是吞吐量
    4 . r_await + w_await 是響應(yīng)時(shí)間

實(shí)際案例

-定位MySQL的慢查詢原因
這里的模擬場景是mysql查詢慢。相關(guān)的例子在 geektime 中有劳秋。
初始化完數(shù)據(jù)庫后仓手,并插入了10000條數(shù)據(jù)。在mysql中如何定位一個(gè)慢查詢玻淑。
1.pidstat -d 1 來確認(rèn)哪個(gè)進(jìn)程在大量的磁盤操作

$ pidstat -d 1
平均時(shí)間:   UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s  Command
平均時(shí)間:     0      6821      1.00      1.00      0.00  rsyslogd
平均時(shí)間:     0     15143   1930.17      0.00      0.00  bash
平均時(shí)間:     0     16438      0.00      2.00      0.00  dockerd
平均時(shí)間:   999     16782 216598.50      0.00      0.00  mysqld
平均時(shí)間:     0     17100      2.00      1.00      0.00  python
平均時(shí)間:     0     17525   1922.19      0.00      0.00  curl

這里可以看到是mysqld 進(jìn)程一直在讀磁盤請求嗽冒。
追蹤mysql可以看到讀的文件都為/var/lib/mysql/test/products.MYD 。這是MYD文件补履,是MyISAM引擎來儲存表數(shù)據(jù)的文件添坊,而文件名就是數(shù)據(jù)表的名字,文件是數(shù)據(jù)庫的名字箫锤。(這里需要強(qiáng)調(diào)以下贬蛙,當(dāng)使用strace的時(shí)候,對應(yīng)用程序的消耗很大谚攒,所以強(qiáng)烈推薦perf trace)

$ perf trace -p 16782
766.518 ( 0.038 ms): mysqld/17277 read(fd: 40</var/lib/mysql/test/products.MYD>, buf: 0x7f2180300ab0, count: 131072) = 131072
   766.574 ( 0.012 ms): mysqld/17277 read(fd: 40</var/lib/mysql/test/products.MYD>, buf: 0x7f2184033178, count: 24576) = 24576
   766.591 ( 0.037 ms): mysqld/17277 read(fd: 40</var/lib/mysql/test/products.MYD>, buf: 0x7f2180300ab0, count: 131072) = 131072
   766.645 ( 0.013 ms): mysqld/17277 read(fd: 40</var/lib/mysql/test/products.MYD>, buf: 0x7f21840338f4, count: 20480) = 20480
   766.664 ( 0.037 ms): mysqld/17277 read(fd: 40</var/lib/mysql/test/products.MYD>, buf: 0x7f2180300ab0, count: 131072) = 131072
   766.719 ( 0.012 ms): mysqld/17277 read(fd: 40</var/lib/mysql/test/products.MYD>, buf: 0x7f2184033070, count: 24576) = 24576

看下mysql中正在執(zhí)行的命令阳准。

mysql> show full processlist;
+-----+------+-----------------+------+---------+------+--------------+-----------------------------------------------------+
| Id  | User | Host            | db   | Command | Time | State        | Info                                                |
+-----+------+-----------------+------+---------+------+--------------+-----------------------------------------------------+
| 766 | root | localhost       | NULL | Query   |    0 | init         | show full processlist                               |
| 792 | root | 127.0.0.1:43134 | test | Query   |    0 | Sending data | select * from products where productName='geektime' |
+-----+------+-----------------+------+---------+------+--------------+-----------------------------------------------------+

這是一個(gè)十分簡單的查詢語句,慢查詢的問題應(yīng)該是沒有利用好索引導(dǎo)致的馏臭。

mysql> explain select * from products where productName='geektime';
+----+-------------+----------+------+---------------+------+---------+------+-------+-------------+
| id | select_type | table    | type | possible_keys | key  | key_len | ref  | rows  | Extra       |
+----+-------------+----------+------+---------------+------+---------+------+-------+-------------+
|  1 | SIMPLE      | products | ALL  | NULL          | NULL | NULL    | NULL | 10000 | Using where |
+----+-------------+----------+------+---------------+------+---------+------+-------+-------------+
1 row in set (0.01 sec)

可以看到野蝇,這里的select_type 是簡單類型的不包括子查詢和UNION,type是全表查詢,而不是索引查詢(index)绕沈。possible_keys 可能選用的索引也是空锐想,key 確切使用的索引更是空了。
那就手動創(chuàng)建索引吧乍狐。

mysql> create index products_index on products (productName(64));
Query OK, 10000 rows affected (2.99 sec)
Records: 10000  Duplicates: 0  Warnings: 0

之后再觀察下查詢的速度赠摇,能快幾個(gè)量級。從400ms縮短到4ms

Got data: () in 0.42174482345581055 sec 
Got data: () in 0.03160667419433594 sec 
Got data: () in 0.0020470619201660156 sec 
Got data: () in 0.004390239715576172 sec 

除了緩存外澜躺,需要知道MyISAM的引擎蝉稳,是使用操作系統(tǒng)緩存的,所以 buffer/cache 也是十分重要的掘鄙。

  • redis 的響應(yīng)慢
    redis 響應(yīng)慢的案例同樣來自geektime。首先搭建好環(huán)境嗡髓,發(fā)起curl操作操漠,然后發(fā)現(xiàn)響應(yīng)比較慢。查看io發(fā)現(xiàn)有大量的讀操作饿这。
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.00     0.00    0.00 1592.00     0.00  4032.00     5.07     0.22    0.14    0.00    0.14   0.14  22.00
dm-0              0.00     0.00    0.00 1592.00     0.00  4032.00     5.07     0.22    0.14    0.00    0.14   0.14  22.00
dm-1              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00

通過perf trace發(fā)現(xiàn)浊伙。這里有很多的epoll_pwait read write fdatasync 的系統(tǒng)調(diào)用,上面觀察到的寫磁盤就是write或者fdatasync導(dǎo)致的了长捧。

  3406.417 ( 0.055 ms): redis-server/21462 write(fd: 8<socket:[97825]>, buf: 0x7f146a5d8fd4, count: 10           ) = 10
  3406.504 ( 0.200 ms): redis-server/21462 epoll_pwait(epfd: 5<anon_inode:[eventpoll]>, events: 0x7f146a5ab000, maxevents: 10128, timeout: 12, sigsetsize: 8) = 1
  3406.733 ( 0.011 ms): redis-server/21462 read(fd: 8<socket:[97825]>, buf: 0x7f146a5de9c5, count: 16384         ) = 67
  3406.771 ( 0.006 ms): redis-server/21462 read(fd: 3<pipe:[95583]>, buf: 0x7ffeb6f4ce97, count: 1               ) = -1 EAGAIN Resource temporarily unavailable
  3406.783 ( 0.027 ms): redis-server/21462 write(fd: 7</data/appendonly.aof>, buf: 0x7f146a498463, count: 67     ) = 67
  3406.818 ( 0.446 ms): redis-server/21462 fdatasync(fd: 7</data/appendonly.aof>            

觀察得知 寫的文件為 /data/appendonly.aof ,相應(yīng)的系統(tǒng)調(diào)用包括 write 和 fdatasync嚣鄙。
這里就要引出redis持久化配置中的 appendonly和appendfsync選項(xiàng)了

$ docker exec -it redis redis-cli config get 'append*'
1) "appendfsync"
2) "always"
3) "appendonly"
4) "yes"

redis 提供了兩種數(shù)據(jù)持久化的方法,快照和追加文件串结。

  • 快照方式:會按照指定的時(shí)間間隔哑子,生成數(shù)據(jù)的快照,并且保存到磁盤文件中肌割,為避免阻塞主進(jìn)程卧蜓,redis會fork出一個(gè)子進(jìn)程,來負(fù)責(zé)快照的保存把敞。
    優(yōu)點(diǎn):性能好
    缺點(diǎn):數(shù)據(jù)量大的話弥奸,fork子進(jìn)程需要比較大的內(nèi)存,保存數(shù)據(jù)也很耗時(shí)奋早。
  • 追加文件:在文件末尾追加記錄的方式盛霎,對redis寫入數(shù)據(jù),依次進(jìn)行持久化耽装。 但追加至磁盤中愤炸,具體方法有三種,1.always:每個(gè)操作都調(diào)用一次 fsync 剂邮。2.everysec:每秒鐘調(diào)用一次fsync摇幻。3.no:交給操作系統(tǒng)來處理。
    好了。現(xiàn)在就知道為什么有I/O的這么大量的寫請求了绰姻。
$ perf trace -e fdatasync -p 21462 --tool_stats -T
         ? (     ?   ): redis-server/21462  ... [continued]: fdatasync()) = 0
10202644.113 ( 0.455 ms): redis-server/21462 fdatasync(fd: 17</data/appendonly.aof>                                ) = 0
10202646.585 ( 0.448 ms): redis-server/21462 fdatasync(fd: 17</data/appendonly.aof>                                ) = 0
10202647.667 ( 0.535 ms): redis-server/21462 fdatasync(fd: 17</data/appendonly.aof>                                ) = 0
10202649.237 ( 0.425 ms): redis-server/21462 fdatasync(fd: 17</data/appendonly.aof>                                ) = 0
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末枉侧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子狂芋,更是在濱河造成了極大的恐慌榨馁,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帜矾,死亡現(xiàn)場離奇詭異翼虫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)屡萤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門珍剑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人死陆,你說我怎么就攤上這事招拙。” “怎么了措译?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵别凤,是天一觀的道長。 經(jīng)常有香客問我领虹,道長规哪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任塌衰,我火速辦了婚禮诉稍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猾蒂。我一直安慰自己均唉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布肚菠。 她就那樣靜靜地躺著舔箭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚊逢。 梳的紋絲不亂的頭發(fā)上层扶,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機(jī)與錄音烙荷,去河邊找鬼镜会。 笑死,一個(gè)胖子當(dāng)著我的面吹牛终抽,可吹牛的內(nèi)容都是我干的戳表。 我是一名探鬼主播桶至,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼匾旭!你這毒婦竟也來了镣屹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤价涝,失蹤者是張志新(化名)和其女友劉穎女蜈,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體色瘩,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伪窖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了居兆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片覆山。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖史辙,靈堂內(nèi)的尸體忽然破棺而出汹买,到底是詐尸還是另有隱情,我是刑警寧澤聊倔,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站生巡,受9級特大地震影響耙蔑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜孤荣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一甸陌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盐股,春花似錦钱豁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至幌蚊,卻和暖如春谤碳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背溢豆。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工蜒简, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人漩仙。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓搓茬,卻偏偏與公主長得像犹赖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子卷仑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當(dāng)在唯一索引所對應(yīng)的列上鍵入重復(fù)值時(shí)峻村,會觸發(fā)此異常。 O...
    我想起個(gè)好名字閱讀 5,320評論 0 9
  • 操作系統(tǒng)概論 操作系統(tǒng)的概念 操作系統(tǒng)是指控制和管理計(jì)算機(jī)的軟硬件資源系枪,并合理的組織調(diào)度計(jì)算機(jī)的工作和資源的分配雀哨,...
    野狗子嗷嗷嗷閱讀 11,931評論 3 34
  • 硬盤物理結(jié)構(gòu) 硬盤內(nèi)部主要部件為磁盤盤片、傳動手臂私爷、讀寫磁頭和主軸馬達(dá)雾棺。實(shí)際數(shù)據(jù)都是寫在盤片上,讀寫主要是通過傳動...
    灘主閱讀 3,680評論 0 5
  • 轉(zhuǎn) # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 9,729評論 0 44
  • feisky云計(jì)算衬浑、虛擬化與Linux技術(shù)筆記posts - 1014, comments - 298, trac...
    不排版閱讀 3,855評論 0 5