Buffered I/O

那么大家肯定好奇, 如何查看系统的 page cache 中都缓存了哪些文件, 以及各个文件缓存了多少个 page 页, 那些 page 页被缓存 ?

page cache
/proc/{pid}/maps/proc/{pid}/fd/*
pgcacher
pgcacher

分析文件在 page cache 缓存占用信息的实现原理

如何分析文件在 page cache 缓存使用情况

查看分析某个文件在 page cache 缓存中的统计原理是这样的.

syscall.Mincorepage

那么文件的 page cache 内存使用情况,只需要使用被缓存的 page 的数量乘以系统的 page size 即可, page size 默认为 4KB.

# getconf PAGESIZE
4096
pgcacherGetFileMincore
import (
    "fmt"
    "os"
    "unsafe"

    "golang.org/x/sys/unix"
)

type Mincore struct {
    Cached int64
    Miss   int64
}

func GetFileMincore(f *os.File, size int64) (*Mincore, error) {
    if int(size) == 0 {
        return nil, nil
    }

    mmap, err := unix.Mmap(int(f.Fd()), 0, int(size), unix.PROT_NONE, unix.MAP_SHARED)
    if err != nil {
        return nil, fmt.Errorf("could not mmap: %v", err)
    }

    vecsz := (size + int64(os.Getpagesize()) - 1) / int64(os.Getpagesize())
    vec := make([]byte, vecsz)

    mmap_ptr := uintptr(unsafe.Pointer(&mmap[0]))
    size_ptr := uintptr(size)
    vec_ptr := uintptr(unsafe.Pointer(&vec[0]))

    ret, _, err := unix.Syscall(unix.SYS_MINCORE, mmap_ptr, size_ptr, vec_ptr)
    if ret != 0 {
        return nil, fmt.Errorf("syscall SYS_MINCORE failed: %v", err)
    }
    defer unix.Munmap(mmap)

    value := new(Mincore)
    for _, b := range vec {
        if b%2 == 1 {
            value.Cached++
        } else {
            value.Miss++
        }
    }

    return value, nil
}

如何计算进程打开文件的 page cache 占用情况 ?

pcstat/proc/{pid}/maps/proc/{pid}/fd/*pgcacherlsof -p pidmmap + mincore
/proc/{pid}/fd/*

当然倒是有个笨方法, 直接遍历 rocksDB 数据目录的所有文件, 求出该进程的 page cache 使用情况.

如何计算当前系统里哪些文件空间占用最多 ?

拿到当前系统的所有进程列表, 然后遍历轮询拿到各个进程的已打开文件列表, 接着使用 mmap + mincore 求出文件在 page cache 的缓存信息. 再拿到所有进程所有文件的 page cache 缓存信息后, 做个排序输出即可.

pgcacher 使用文档

安装

source code compilation

git clone https://github.com/rfyiamcool/pgcacher.git
cd pgcacher
make build
sudo cp pgcacher /usr/local/bin/
pgcacher -h

github releases

pgcacher/usr/local/bin

use binary directly

test pass on ubuntu, centos 7.x and centos 8.x.

wget xiaorui-cc.oss-cn-hangzhou.aliyuncs.com/files/pgcacher
chmod 777 pgcacher
\cp pgcacher /usr/local/bin

使用过程

pgcacher 命令帮助文档.

pgcacher <-json <-pps>|-terse|-default> <-nohdr> <-bname> file file file
    -limit limit the number of files displayed, default: 500
    -depth set the depth of dirs to scan, default: 0
    -worker concurrency workers, default: 2
    -pid show all open maps for the given pid
    -top scan the open files of all processes, show the top few files that occupy the most memory space in the page cache, default: false
    -lease-size ignore files smaller than the lastSize, such as '10MB' and '15GB'
    -exclude-files exclude the specified files by wildcard, such as 'a*c?d' and '*xiaorui*,rfyiamcool'
    -include-files only include the specified files by wildcard, such as 'a*c?d' and '*xiaorui?cc,rfyiamcool'
    -json output will be JSON
    -pps include the per-page information in the output (can be huge!)
    -terse print terse machine-parseable output
    -histo print a histogram using unicode block characters
    -nohdr don't print the column header in terse or default format
    -bname use basename(file) in the output (use for long paths)
    -plain return data with no box characters
    -unicode return data with unicode box characters

pgcacher 各种场景的使用过程.

查询该进程的 page cahce 使用占比, 附加了一个并发参数, 开启 5 个线程并发扫描.

# sudo pgcacher -pid=29260 -worker=5
+-------------------+----------------+-------------+----------------+-------------+---------+
| Name              | Size           │ Pages       │ Cached Size    │ Cached Pages│ Percent │
|-------------------+----------------+-------------+----------------+-------------+---------|
| /root/rui/file4g  | 3.906G         | 1024000     | 3.906G         | 1024000     | 100.000 |
| /root/rui/file3g  | 2.930G         | 768000      | 2.930G         | 768000      | 100.000 |
| /root/rui/file2g  | 1.953G         | 512000      | 1.953G         | 512000      | 100.000 |
| /root/rui/file1g  | 1000.000M      | 256000      | 1000.000M      | 256000      | 100.000 |
| /root/rui/open_re | 1.791M         | 459         | 1.791M         | 459         | 100.000 |
|-------------------+----------------+-------------+----------------+-------------+---------|
│ Sum               │ 9.767G         │ 2560459     │ 9.767G         │ 2560459     │ 100.000 │
+-------------------+----------------+-------------+----------------+-------------+---------+

查询多个文件在 page cache 的使用情况.

# dd if=/dev/urandom of=file1g bs=1M count=1000
# dd if=/dev/urandom of=file2g bs=1M count=2000
# dd if=/dev/urandom of=file3g bs=1M count=3000
# dd if=/dev/urandom of=file4g bs=1M count=4000
# cat file1g file2g file3g file4g > /dev/null

# sudo pgcacher file1g file2g file3g file4g
+--------+----------------+-------------+----------------+-------------+---------+
| Name   | Size           │ Pages       │ Cached Size    │ Cached Pages│ Percent │
|--------+----------------+-------------+----------------+-------------+---------|
| file4g | 3.906G         | 1024000     | 3.906G         | 1024000     | 100.000 |
| file3g | 2.930G         | 768000      | 2.930G         | 768000      | 100.000 |
| file2g | 1.953G         | 512000      | 1.953G         | 512000      | 100.000 |
| file1g | 1000.000M      | 256000      | 1000.000M      | 256000      | 100.000 |
|--------+----------------+-------------+----------------+-------------+---------|
│ Sum    │ 9.766G         │ 2560000     │ 9.766G         │ 2560000     │ 100.000 │
+--------+----------------+-------------+----------------+-------------+---------+

查看该目录下的所有文件在 page cache 缓存里的使用情况.

# sudo pgcacher /root/xiaorui.cc/*

+------------+----------------+-------------+----------------+-------------+---------+
| Name       | Size           │ Pages       │ Cached Size    │ Cached Pages│ Percent │
|------------+----------------+-------------+----------------+-------------+---------|
| file4g     | 3.906G         | 1024000     | 3.906G         | 1024000     | 100.000 |
| file3g     | 2.930G         | 768000      | 2.930G         | 768000      | 100.000 |
| file2g     | 1.953G         | 512000      | 1.953G         | 512000      | 100.000 |
| testfile   | 1000.000M      | 256000      | 1000.000M      | 256000      | 100.000 |
| file1g     | 1000.000M      | 256000      | 1000.000M      | 256000      | 100.000 |
| pgcacher   | 2.440M         | 625         | 2.440M         | 625         | 100.000 |
| open_re    | 1.791M         | 459         | 1.791M         | 459         | 100.000 |
| cache.go   | 19.576K        | 5           | 19.576K        | 5           | 100.000 |
| open_re.go | 644B           | 1           | 644B           | 1           | 100.000 |
| nohup.out  | 957B           | 1           | 957B           | 1           | 100.000 |
|------------+----------------+-------------+----------------+-------------+---------|
│ Sum        │ 10.746G        │ 2817091     │ 10.746G        │ 2817091     │ 100.000 │
+------------+----------------+-------------+----------------+-------------+---------+

查看当前系统下所有进程的已打开文件在 page cache 缓存里的使用情况.

# sudo pgcacher -top -limit 3

+------------------+----------------+-------------+----------------+-------------+---------+
| Name             | Size           │ Pages       │ Cached Size    │ Cached Pages│ Percent │
|------------------+----------------+-------------+----------------+-------------+---------|
| /root/rui/file4g | 3.906G         | 1024000     | 3.906G         | 1024000     | 100.000 |
| /root/rui/file3g | 2.930G         | 768000      | 2.930G         | 768000      | 100.000 |
| /root/rui/file2g | 1.953G         | 512000      | 1.953G         | 512000      | 100.000 |
|------------------+----------------+-------------+----------------+-------------+---------|
│ Sum              │ 8.789G         │ 2304000     │ 8.789G         │ 2304000     │ 100.000 │
+------------------+----------------+-------------+----------------+-------------+---------+

递归遍历 4 层查看 aaa 目录所有子文件在 page cache 缓存里的使用情况.

# sudo pgcacher -depth=4 aaa/

+---------------------+----------------+-------------+----------------+-------------+---------+
| Name                | Size           │ Pages       │ Cached Size    │ Cached Pages│ Percent │
|---------------------+----------------+-------------+----------------+-------------+---------|
| aaa/a2g             | 1.953G         | 512000      | 1.953G         | 512000      | 100.000 |
| aaa/bbb/ccc/ddd/d2g | 1.953G         | 512000      | 1.940G         | 508531      | 99.322  |
| aaa/bbb/ccc/c1g     | 1000.000M      | 256000      | 1000.000M      | 256000      | 100.000 |
| aaa/bbb/ccc/c2g     | 1.953G         | 512000      | 1000.000M      | 256000      | 50.000  |
| aaa/bbb/ccc/ddd/d1g | 1000.000M      | 256000      | 1000.000M      | 256000      | 100.000 |
| aaa/a1g             | 1000.000M      | 256000      | 1000.000M      | 256000      | 100.000 |
| aaa/bbb/bbb1g       | 1000.000M      | 256000      | 1000.000M      | 256000      | 100.000 |
| aaa/bbb/bbb2g       | 1.953G         | 512000      | 1000.000M      | 256000      | 50.000  |
|---------------------+----------------+-------------+----------------+-------------+---------|
│ Sum                 │ 11.719G        │ 3072000     │ 9.752G         │ 2556531     │ 83.220  │
+---------------------+----------------+-------------+----------------+-------------+---------+

总结

如何分析文件在 page cache 缓存中的使用情况
pgcacher