1. 程式人生 > >Linux性能優化實戰:如何利用系統緩存優化程序的運行效率?(17)

Linux性能優化實戰:如何利用系統緩存優化程序的運行效率?(17)

\n lar xtend 硬盤 ted tro hits 基於 roc

一、緩存命中率

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)