一、咱們想利用緩存來提高程序的運行效率,應該怎麼評估這個效果呢?python
用衡量緩存好壞的指標linux
二、有沒有哪一個指標能夠衡量緩存使用的好壞呢?git
緩存命中率github
三、什麼是緩存命中率?golang
所謂緩存命中率,是指直接經過緩存獲取數據的請求次數,佔全部數據請求次數的百分比。命中率越高,表示使用緩存帶來的收益越高,應用程序的性能也就越好docker
實際上、緩存是如今全部高併發系統必須的核心模塊,主要做用就是把常常訪問的數據(也就是熱點數據),提取讀入到內存中,這樣下次訪問時就能夠直接從內存讀取數據,而不須要過硬盤,從而加快應用程序的響應速度ubuntu
這些獨立的緩存模塊一般會提供查詢接口,方便咱們隨時查看緩存的命中率率。不過Linux系統中並無直接提供這些接口,
因此我這裏介紹一下cachestat 和 cachetop它們正是查看系統緩存命中狀況的工具。緩存
cachestat 提供了整個操做系統緩存的讀寫命中狀況。bash
cachetop 提供了每一個進程的緩存命中狀況。併發
這兩個工具都是 bcc 軟件包的一部分,它們基於 Linux 內核的 eBPF(extended Berkeley PacketFilters)機制,來跟蹤內核中管理的緩存,並輸出緩存的使...
在 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 | +---------+----------------+------------+-----------+---------+
知道了緩存相應的指標和查看系統緩存的方法後咱們就開始施展了
一、而後,使用 dd 命令生成一個臨時文件,用於後面的文件讀取測試:
# 生成一個 512MB 的臨時文件 $ dd if=/dev/sda1 of=file bs=1M count=512 # 清理緩存 $ echo 3 > /proc/sys/vm/drop_caches
二、確認剛剛生成的文件不在緩存中(終端一)
pcstat file +-------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |-------+----------------+------------+-----------+---------| | file | 536870912 | 131072 | 0 | 000.000 | +-------+----------------+------------+-----------+---------+
三、運行 cachetop 命令
# 每隔 5 秒刷新一次數據 $ cachetop 5
四、查看cachetop界面的緩存命中狀況(終端一)
PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT% \.\.\. 3264 root dd 37077 37330 0 49.8% 50.2%
五、運行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
六、終端一 查看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%
七、運行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
八、再回到第一個終端查看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%
九、回到第二個終端,再次執行 pcstat 查看文件file 的緩存狀況:
pcstat file +-------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |-------+----------------+------------+-----------+---------| | file | 536870912 | 131072 | 131072 | 100.000 | +-------+----------------+------------+-----------+---------+
一、第一個終端運行
# 每隔 5 秒刷新一次數據 $ cachetop 5
二、第二個終端運行案例
docker run --privileged --name=app -itd feisky/app:io-direct
三、確認案例已經正常啓動終端二
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
四、回到第一個終端,先看看 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%
五、繼續在第二個終端
# 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\25@\371\1\252\2\262\252q\221\n0\30\225bD\252\266@J"\.\.\., 33554432) = 33554432 write(1, "Time used: 0.948897 s to read 33"\.\.\., 45) = 45 close(4) = 0
六、案例應用源代碼
int flags = O_RDONLY | O_LARGEFILE | O_DIRECT; int fd = open(disk, flags, 0755);
七、運行修復後應用
# 刪除上述案例應用 $ docker rm -f app # 運行修復後的應用 $ docker run --privileged --name=app -itd feisky/app:io-cached
八、在第二個終端查看應用程序
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
九、在回到第一個終端 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 這類外部緩存服務,優化數據的訪問效率。