Linux性能優化實戰:如何利用系統緩存優化程序的運行效率?(17)
一、緩存命中率
1、引子
1、我們想利用緩存來提升程序的運行效率,應該怎麽評估這個效果呢?
用衡量緩存好壞的指標
2、有沒有哪個指標可以衡量緩存使用的好壞呢?
緩存命中率
3、什麽是緩存命中率?
所謂緩存命中率,是指直接通過緩存獲取數據的請求次數,占所有數據請求次數的百分比。命中率越高,表示使用緩存帶來的收益越高,應用程序的性能也就越好
2、查看系統命中情況的工具
1、緩存在高並發系統的應用
實際上、緩存是現在所有高並發系統必須的核心模塊,主要作用就是把經常訪問的數據(也就是熱點數據),提取讀入到內存中,這樣下次訪問時就可以直接從內存讀取數據,而不需要過硬盤,從而加快應用程序的響應速度
這些獨立的緩存模塊通常會提供查詢接口,方便我們隨時查看緩存的命中率率。不過Linux系統中並沒有直接提供這些接口,
所以我這裏介紹一下cachestat 和 cachetop它們正是查看系統緩存命中情況的工具。
2、查看系統命中情況的工具
cachestat 提供了整個操作系統緩存的讀寫命中情況。
cachetop 提供了每個進程的緩存命中情況。
這兩個工具都是 bcc 軟件包的一部分,它們基於 Linux 內核的 eBPF(extended Berkeley PacketFilters)機制,來跟蹤內核中管理的緩存,並輸出緩存的使...
3、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)
操作完這些步驟,bcc 提供的所有工具就都安裝到 /usr/share/bcc/tools 這個目錄中了。不過這裏提醒你,bcc 軟件包默認不會把這些工具配置到系統的的 PATH 路徑中,所以你得自己手動配置:
export PATH=$PATH:/usr/share/bcc/tools
cachestat 的運行界面,它以 1 秒的時間間隔,輸出了 3 組緩存統計數據:
cachestat 1 3 TOTAL MISSES HITS DIRTIES BUFFERS_MB CACHED_MB 2 0 2 1 17 279 2 0 2 1 17 279 2 0 2 1 17 279
cachetop
cachetop 11:58:50 Buffers MB: 258 / Cached MB: 347 / Sort: HITS / Order: ascending PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT% 13029 root python 1 0 0 100.0% 0.0%
它的輸出跟 top 類似,默認按照緩存的命中次數(HITS)排序,展示了每個進程的緩存命中情況。具體到每一個指標,
這裏的 HITS、MISSES 和 DIRTIES ,跟cachestat 裏的含義一樣,分別代表間隔時間內的緩存命中次數、未命中次數以及新增到緩存中的臟頁數。
而 READ_HIT 和 WRITE_HIT ,分別表示讀和寫的緩存命中率
二、指定文件的緩存大小
除了緩存的命中率外,還有一個指標你可能也會很感興趣,那就是指定文件在內存中的緩存大小。你可以使用 pcstat這個工具,來查看文件在內存中的緩存大小以及緩存比例。
pcstat 是一個基於 Go 語言開發的工具,所以安裝它之前,你首先應該安裝 Go 語言,你可以點擊這裏下載安裝。
安裝完 Go 語言,再運行下面的命令安裝 pcstat:
export GOPATH=~/go $ export PATH=~/go/bin:$PATH $ go get golang.org/x/sys/unix $ go get github.com/tobert/pcstat/pcstat
/bin/ls 這個文件的緩存情況:
pcstat /bin/ls +---------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |---------+----------------+------------+-----------+---------| | /bin/ls | 133792 | 33 | 0 | 000.000 | +---------+----------------+------------+-----------+---------+
如果你執行一下 ls 命令,再運行相同的命令來查看的話,就會發現 /bin/ls 都在緩存中了:
ls $ pcstat /bin/ls +---------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |---------+----------------+------------+-----------+---------| | /bin/ls | 133792 | 33 | 33 | 100.000 | +---------+----------------+------------+-----------+---------+
知道了緩存相應的指標和查看系統緩存的方法後我們就開始施展了
三、案例一
1、然後,使用 dd 命令生成一個臨時文件,用於後面的文件讀取測試:
# 生成一個 512MB 的臨時文件 $ dd if=/dev/sda1 of=file bs=1M count=512 # 清理緩存 $ echo 3 > /proc/sys/vm/drop_caches
2、確認剛剛生成的文件不在緩存中(終端一)
pcstat file +-------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |-------+----------------+------------+-----------+---------| | file | 536870912 | 131072 | 0 | 000.000 | +-------+----------------+------------+-----------+---------+
3、運行 cachetop 命令
# 每隔 5 秒刷新一次數據 $ cachetop 5
4、查看cachetop界面的緩存命中情況(終端一)
PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT% \.\.\. 3264 root dd 37077 37330 0 49.8% 50.2%
實驗二
5、運行dd命令測試文件的讀取速度(終端二)
dd if=file of=/dev/null bs=1M 512+0 records in 512+0 records out 536870912 bytes (537 MB, 512 MiB) copied, 16.0509 s, 33.4 MB/s
6、終端一 查看cachetop界面的緩存命中情況(終端一)
10:45:22 Buffers MB: 4 / Cached MB: 719 / Sort: HITS / Order: ascending PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT% \.\.\. 32642 root dd 131637 0 0 100.0% 0.0%
7、運行dd命令測試文件的讀取速度(終端二)
dd if=file of=/dev/null bs=1M 512+0 records in 512+0 records out 536870912 bytes (537 MB, 512 MiB) copied, 0.118415 s, 4.5 GB/s
8、再回到第一個終端查看cachetop 的情況
10:45:22 Buffers MB: 4 / Cached MB: 719 / Sort: HITS / Order: ascending PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT% \.\.\. 32642 root dd 131637 0 0 100.0% 0.0%
9、回到第二個終端,再次執行 pcstat 查看文件file 的緩存情況:
pcstat file +-------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |-------+----------------+------------+-----------+---------| | file | 536870912 | 131072 | 131072 | 100.000 | +-------+----------------+------------+-----------+---------+
四、案例二
1、第一個終端運行
# 每隔 5 秒刷新一次數據 $ cachetop 5
2、第二個終端運行案例
docker run --privileged --name=app -itd feisky/app:io-direct
3、確認案例已經正常啟動終端二
docker logs app Reading data from disk /dev/sdb1 with buffer size 33554432 Time used: 0.929935 s to read 33554432 bytes Time used: 0.949625 s to read 33554432 bytes
4、回到第一個終端,先看看 cachetop 的輸出
16:39:18 Buffers MB: 73 / Cached MB: 281 / Sort: HITS / Order: ascending PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT% 21881 root app 1024 0 0 100.0% 0.0%
5、繼續在第二個終端
# strace -p $(pgrep app) strace: Process 4988 attached restart_syscall(<\.\.\. resuming interrupted nanosleep \.\.\.>) = 0 openat(AT_FDCWD, "/dev/sdb1", O_RDONLY|O_DIRECT) = 4 mmap(NULL, 33558528, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f448d240000 read(4, "8vq\213\314\264u\373\4\336K\224\[email protected]\371\1\252\2\262\252q\221\n0\30\225bD\252\[email protected]"\.\.\., 33554432) = 33554432 write(1, "Time used: 0.948897 s to read 33"\.\.\., 45) = 45 close(4) = 0
6、案例應用源代碼
int flags = O_RDONLY | O_LARGEFILE | O_DIRECT; int fd = open(disk, flags, 0755);
7、運行修復後應用
# 刪除上述案例應用 $ docker rm -f app # 運行修復後的應用 $ docker run --privileged --name=app -itd feisky/app:io-cached
8、在第二個終端查看應用程序
docker logs app Reading data from disk /dev/sdb1 with buffer size 33554432 Time used: 0.037342 s s to read 33554432 bytes Time used: 0.029676 s to read 33554432 bytes
9、在回到第一個終端 cachetop
16:40:08 Buffers MB: 73 / Cached MB: 281 / Sort: HITS / Order: ascending PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT% 22106 root app 40960 0 0 100.0% 0.0%
四、總結
Buffers 和 Cache 都是操作系統來管理的,應用程序並不能直接控制這些緩存的內容和生命周期。
所以,在應用程序開發中,一般要用專門的緩存組件,來進一步提升性能。
比如,程序內部可以使用堆或者棧明確聲明內存空間,來存儲需要緩存的數據。
再或者,使用 Redis 這類外部緩存服務,優化數據的訪問效率。
Linux性能優化實戰:如何利用系統緩存優化程序的運行效率?(17)