Linux性能優化實戰學習筆記:第十七講

1、緩存命中率

一、引子

一、咱們想利用緩存來提高程序的運行效率,應該怎麼評估這個效果呢?python

用衡量緩存好壞的指標linux

二、有沒有哪一個指標能夠衡量緩存使用的好壞呢?git

緩存命中率github

三、什麼是緩存命中率?golang

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

二、查看系統命中狀況的工具

一、緩存在高併發系統的應用

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

這些獨立的緩存模塊一般會提供查詢接口,方便咱們隨時查看緩存的命中率率。不過Linux系統中並無直接提供這些接口,
因此我這裏介紹一下cachestat 和 cachetop它們正是查看系統緩存命中狀況的工具。緩存

二、查看系統命中狀況的工具

cachestat 提供了整個操做系統緩存的讀寫命中狀況。bash

cachetop 提供了每一個進程的緩存命中狀況。併發

這兩個工具都是 bcc 軟件包的一部分,它們基於 Linux 內核的 eBPF(extended Berkeley PacketFilters)機制,來跟蹤內核中管理的緩存,並輸出緩存的使...

三、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 ,分別表示讀和寫的緩存命中率

2、指定文件的緩存大小

除了緩存的命中率外,還有一個指標你可能也會很感興趣,那就是指定文件在內存中的緩存大小。你可使用 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 |
+---------+----------------+------------+-----------+---------+


知道了緩存相應的指標和查看系統緩存的方法後咱們就開始施展了

3、案例一

一、而後,使用 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 |
+-------+----------------+------------+-----------+---------+

4、案例二

一、第一個終端運行

# 每隔 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%

4、總結

Buffers 和 Cache 都是操做系統來管理的,應用程序並不能直接控制這些緩存的內容和生命週期。

因此,在應用程序開發中,通常要用專門的緩存組件,來進一步提高性能。

好比,程序內部可使用堆或者棧明確聲明內存空間,來存儲須要緩存的數據。

再或者,使用 Redis 這類外部緩存服務,優化數據的訪問效率。

相關文章
相關標籤/搜索