性能分析(7)- 未利用系統緩存致使 I/O 緩慢案例

性能分析小案例系列,能夠經過下面連接查看哦html

https://www.cnblogs.com/poloyy/category/1814570.htmllinux

 

前提

前面有學到 Buffer 和 Cache 的概念:https://www.cnblogs.com/poloyy/p/13503848.htmlgit

咱們來簡單複習下github

 

Buffer 和 Cache 的設計目的

爲了提高系統的 I/O 性能,它們利用內存,充當起慢速磁盤和快速 CPU 之間的橋樑,能夠加速 I/O 的訪問速度golang

 

Buffer 和 Cache

  • BUffer:對磁盤的讀寫數據緩存
  • Cache:對文件系統的讀寫數據緩存

 

讀寫角度

  • 的角度來講,不只能夠優化磁盤和文件的寫入,對應用程序也有好處,應用程序能夠在數據真正落盤前,就返回去作其餘工做
  • 的角度來講,不只能夠提升那些頻繁訪問數據的讀取速度,也能夠下降頻繁 I/O 對磁盤的壓力

 

引入主題

既然 Buffer 和 Cache 對系統性能有很大影響,那咱們在軟件開發的過程當中,能不能利用這 一點,來優化 I/O 性能,提高應用程序的運行效率呢? 答案天然是確定的docker

 

緩存命中率

靈魂拷問

咱們想利用緩存來提高程序的運行效率,應該怎麼評估這個效果呢?換句話說,有沒有哪一個指標能夠衡量緩存使用的好壞呢?ubuntu

 

靈魂回答

  • 緩存命中率
  • 指直接經過緩存獲取數據的請求次數,佔全部數據請求次數的百分比【使用緩存請求次數 / 總請求次數】
  • 命中率越高,表示使用緩存帶來的收益越高,應用程序的性能也就越好

 

緩存的重要性

  • 緩存是如今全部高併發系統必需的核心模塊
  • 主要做用:把常常訪問的數據(熱點數據),提早讀入到內存中,下次訪問時就能夠直接從內存讀取數據,而不須要通過硬盤,從而加快應用程序的響應速度

 

cachestat、cachetop

獨立的緩存模塊一般會提供查詢接口,方便咱們隨時查看緩存的命中狀況vim

不過 Linux 系統中並無直接提供這些接口,因此這裏要介紹一下,cachestat 和 cachetop ,它們正是查看系統緩存命中狀況的工具緩存

  • cachestat 提供了整個操做系統緩存的讀寫命中狀況
  • cachetop 提供了每一個進程的緩存命中狀況

 

Ubuntu 安裝工具

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
echo "deb https://repo.iovisor.org/apt/xenial xenial main" | sudo tee /etc/apt/sources.list.d/iovisor.list
sudo apt-get update
sudo apt-get install -y bcc-tools libbcc-examples linux-headers-$(uname -r)

 

配置環境變量

vim /etc/profile

# 在文件結尾處添加
export PATH=$PATH:/usr/share/bcc/tools

# 保存文件後
source /etc/profile

 

cachestat

# 它以 1 秒的時間間隔,輸出了 3 組緩存統計數據
cachestat 1 3

字段說明

 

cachetop

cachetop

  • 默認按照緩存的命中次數(HITS)排序,展現了每一個進程的緩存命中狀況
  • 具體到每個指標,這裏的 HITS、MISSES 和 DIRTIES ,跟 cachestat 裏的含義 同樣,分別表明間隔時間內的緩存命中次數、未命中次數以及新增到緩存中的髒頁數
  • READ_HIT:讀的緩存命中率
  • WRITE_HIT:寫的緩存命中率

 

查看文件的緩存大小

可使用 pcstat 這個工具,來查看文件在內存中的緩存大小以及緩存比例併發

 

安裝 pcstat

# 安裝 go
apt install golang-go

vim /etc/profile

# 在文件結尾處添加
export GOPATH=~/go
export PATH=~/go/bin:$PATH

# 保存文件後
source /etc/profile
 
go get golang.org/x/sys/unix
go get github.com/tobert/pcstat/pcstat

 

運行 pcstat

pcstat /bin/ls

Cached 就是 /bin/ls 在緩存中的大小,而 Percent 則是緩存的百分比,看到它們都是 0,這說明 /bin/ls 並不在緩存中

 

執行 ls 命令,再來查看

ls
pcstat /bin/ls

發現都在緩存中了

 

講案例前的準備

  • 系統:Ubuntu 18.04,固然一樣適用於其餘的 Linux 系 統。
  • 機器配置:2 CPU,2 GB 內存
  • 預先按照上面的步驟安裝 bcc 和 pcstat 軟件包,並把這些工具的安裝路徑添加到到 PATH 環境變量中
  • 預先安裝 Docker 軟件包: apt-get install docker.io 
  • 打開兩個終端同時連到 Linux 上

 

案例一:經過 dd 寫入讀取文件

注意:沒說第幾個終端都是默認第一個終端執行命令哦

 

 dd 命令生成一個臨時文件

# 生成一個 512MB 的臨時文件
dd if=/dev/sda1 of=file bs=1M count=512

# 清理緩存
echo 3 > /proc/sys/vm/drop_caches

 

運行 pcstat 查看 file 文件

pcstat file

確認剛剛生成的文件不在緩存中。若是一切正常, 會看到 Cached 和 Percent 都是 0

 

運行 cachetop 

# 每隔 1 秒刷新一次數據
cachetop 1

 

第二個終端運行 dd 命令

dd if=file of=/dev/null bs=1M

  • 從 dd 的結果能夠看出,這個文件的讀性能是 639 MB/s
  • 因爲在 dd 命令運行前咱們已經清理了緩存,因此 dd 命令讀取數據時,確定要經過文件系統從磁盤中讀取

 

查看 cachetop

能夠看到 dd 命令並非全部的讀都落到了磁盤上,讀請求的緩存命中率只有 50%

 

第二個終端再次運行 dd 命令

dd if=file of=/dev/null bs=1M

磁盤的讀性能蹭蹭蹭往上漲,去到了 1.6GB/s

 

再查看 cachetop

能夠發現,此次讀的緩存命中率是 100%

 

第二個終端運行 pcstat

pcstat  file

測試文件已經被所有緩存起來了,和剛剛 cachetop 觀察到緩存命中率 100% 是一致的

 

總結

這兩次結果說明,系統緩存對第二次 dd 操做有明顯的加速效果,能夠大大提升文件讀取的性能。

 

案例二

前提

  • 這裏運行了一個不可中斷狀態的進程
  • 功能:是每秒從磁盤分區 /dev/sda1 中讀取 32MB 的數據, 並打印出讀取數據花費的時間

 

查看應用日誌

從這裏能夠看到,每讀取 32 MB 的數據,就須要花 0.9 秒

 

靈魂拷問

這個時間合理嗎?這也太慢了吧,那這是否是沒用系統緩存致使的呢?

 

查看 cachetop

結果分析

讀的命中率雖然是 100%,命中次數是 1024,看起來所有的讀請求都通過了系統緩存

 

靈魂又拷問了

全都是緩存 I/O,讀取速度不該該這麼慢

 

深刻分析

  • 另外一個重要因素,每秒實際讀取的數據大小,HITS 表明緩存的命中次數,那麼每次命中能讀取多少數據呢?天然是一頁
  • 內存以頁爲單位進行管理,而每一個頁的大小是 4KB
  • 因此,在 5 秒的時間間隔 裏,命中的緩存爲 1024*4K/1024 = 4MB,再除以 5 秒,能夠獲得每秒讀的緩存是 0.8MB,顯然跟案例應用的 32 MB/s 相差太多

 

結果猜測

這個案例估計沒有充分利用系統緩存,若是系統調用設置直接 I/O 的標誌,就能夠繞過系統緩存

 

經過 strace 觀察系統調用

strace -p $(pgrep app)

結果分析

  • 從 strace 的結果能夠看到,案例應用調用了 openat 來打開磁盤分區 /dev/sdb1,而且傳 入的參數爲 O_RDONLY|O_DIRECT(中間的豎線表示或)
  • O_RDONLY 表示以只讀方式打開
  • 而 O_DIRECT 則表示以直接讀取的方式打開,這會繞過系統的緩存
  • 驗證了這一點,就很容易理解爲何讀 32 MB 的數據就都要那麼久了
  • 直接從磁盤讀寫的速度,天然遠慢於對緩存的讀寫,這也是緩存存在的最大意義了

 

查看應用源碼

它果真用了直接 I/O

 

修改源代碼

刪除 O_DIRECT 選項,讓應用程序使用緩存 I/O ,而不是直接 I/O,就能夠加速磁盤讀取速度

 

驗證修復後的應用

查看新應用的日誌

結果分析

如今,每次只須要 0.03 秒,就能夠讀取 32MB 數據,明顯比以前的 0.9 秒快多了。因此,此次應該用了系統緩存

 

再次查看 cachetop

結果分析

  • 果真,讀的命中率仍是 100%,HITS (即命中數)卻變成了 40960
  • 一樣的方法計算一 下,換算成每秒字節數正好是 32 MB(即 40960*4k/5/1024=32M)

 

總結

  • 在進行 I/O 操做時,充分利用系統緩存能夠極大地提高性能。
  • 但在觀察緩存命中率時,還要注意結合應用程序實際的 I/O 大小,綜合分析緩存的使用狀況

 

擴展

爲何優化前,經過 cachetop 只能看到不多一部分數據的所有命中,而沒有觀察到大量數據的未命中狀況呢?

 

回答

是由於,cachetop 工具並不把直接 I/O 算進來

相關文章
相關標籤/搜索