暂无图片
暂无图片
暂无图片
暂无图片
1
暂无图片

Linux 内存 PageCache 和数据库共享内存分析(上)

2594
本文主要是总结Linux内存的PageCache 原理,并观察ORACLEMySQLPG数据库的内存使用特点。
文中Linux系统是CentOS 7.9,内核版本3.10.0-1160 。服务器内存大小512GB
有关Linux内存的源码解读和原理总结的书非常多且厚。这里只是就实际工作中的疑点尝试进行分析总结。所以不会那么系统和完备。
说内存之前其实先从磁盘说起。以前机械盘读取速度实在太慢,现在的SSD虽然快很多了,能到几十万的 IOPS,但是相比内存的读写速度那还是慢多了。部署在磁盘上的文件系统为提升自己的读写性能,降低磁盘I/O的慢速影响,文件系统对读写的页支持缓存。这个缓存是从内存里借来的,体现为Page Cache。(这里我不关注Page CacheBuffer Cache的历史)。而数据库部署在文件系统上的I/O有的会用文件系统这个缓存特性,有的又不用这个特性。加上成熟的数据库还会有自己的缓存,这使得内存成为影响数据库性能结果的重要因素之一(其他还有磁盘)。而我一直好奇的就是想知道Page Cache里具体缓存哪些内容。

Cache 大小查看

通常查看 PageCache的大小方法是 free 命令中的 Cache字段。
这个字段实际是Buffer cachePage cache的值统计在一起,这里有个历史原因。不过由于buffer cache大小一般很小(1G不到),所以这里不关心buffer cache的数据。
Free 命令的帮助文档对 Cache 的解释细节过于简单,说是从 proc/meminfo 取的。
这里我们换另外一个命令atop cache 字段查看Page Cache 大小。
atop 命令的帮助文档里对Cache的解释是包含resident shared memory 在内的用作文件系统缓存的内存。而 atop shmem 字段则显示了包括tmpfs在内的共享内存大小。
所以初步看来,Cache包含文件的缓存和共享内存。


查看文件缓存的工具

pcstat 命令

网上查看文件缓存的工具有pcstat。项目地址:https://github.com/tobert/pcstat 
比如说用 pcstat 可以查看常见的lib文件的缓存情况。Cached 字段表示缓存的页数量(页大小是4KB),Percent是每个文件内容在缓存中的比例。
这些Lib文件很多,但每个都不是很大,所以总的大小也不过几个GB,也不是我关注的重点。我们换个别的文件例子。
上篇文章《SSD扇区大小以及对ORACLE数据库影响总结》中我提到ORACLE 19c在文件系统上安装时默认是 Buffer I/O。我们也通过 pcstat 工具来观察一下ORACLE数据文件在Page Cache中缓存情况。
果然,数据文件和Redo日志文件都在Page Cache里缓存着。这个有点坑,不过不是本文重点。
上面是已知文件路径去查文件的缓存情况。我想直接查某个进程所有文件缓存情况,或者直接查看Page Cache里所有缓存。这时候又有一个命令hcache

hcache 命令

hcache 开源项目地址:https://github.com/silenceshell/hcache
下面查看ORACLE的读写用的进程,看看这些进程打开的文件的缓存情况。
这个工具想法是好的,但是经常报错(/proc/进程id/下文件读取报错)。最重要的是它找出来的文件都是一些 Lib 文件,看不到数据库文件。查看了源码发现,它是读取进程的虚拟内存中的映射文件,然后将文件传递给pcstat去显示。
有关进程虚拟内存和内存映射后面再介绍,显然这个命令还不是我想要的。
根据 pcstat的项目说明,它是参考项目linux-ftools写的。我们再看看这个工具。

linux-ftools 工具

linux-ftools 一共提供三个工具:
·linux-fincore : 用于查看文件的缓存情况,可以设置过滤条件。
·linux-fadvise :用于干预一个文件的缓存策略。这个跟系统调用 fadvise函数类似。有关干预策略后面再单独说。
·linux-fallocate:用于快速扩大文件的逻辑空间。这个方式产生的文件里面主要是空洞,压缩比非常高。这个以后单独写文章再介绍。
我们重点看 linux-fincore 命令。
实际使用后,感觉linux-fincore参数比较实用。
不过遗憾的是它不能直接查看Page Cache 里的缓存的内容,或者根据进程ID查看。
这两个需求里前面那个实现有点困难,但后面这个还是比较容易的。根据进程ID可以查看进程打开的文件列表,将列表传递给 linux-fincore就可以查看。
前面那个需求后来有网友写脚本变相实现了。查看所有进程,根据进程实际内存(RSS)大小排序,取前N个进程,查看其打开的文件缓存,基本上能确定Page Cache中占比比较大的文件信息了。脚本我做了小的修改(去重)。
    [root@sfx110008 ~]# cat ~/memory/list_pgf.sh
    #!/bin/bash
    #Author: Shanker
    #Time: 2016/06/08


    #set -e
    #set -u
    #you have to install linux-fincore
    if [ ! -f usr/local/bin/linux-fincore ]
    then
    echo "You haven't installed linux-fincore yet"
    exit
    fi


    #find the top 10 processs' cache file
    ps -e -o pid,rss|sort -nk2 -r|head -50 |awk '{print $1}'>/tmp/cache.pids
    #find all the processs' cache file
    #ps -e -o pid>/tmp/cache.pids


    if [ -f tmp/cache.files ]
    then
    echo "the cache.files is exist, removing now "
    rm -f tmp/cache.files
    fi


    while read line
    do
    lsof -p $line 2>/dev/null|awk '{print $9}' >>/tmp/cache.files
    done </tmp/cache.pids




    if [ -f tmp/cache.fincore ]
    then
    echo "the cache.fincore is exist, removing now"


    rm -f tmp/cache.fincore
    fi


    for i in `cat tmp/cache.files | sort |uniq `
    do


    if [ -f $i ]
    then
    echo $i >>/tmp/cache.fincore
    fi
    done


    linux-fincore --only-cached -C 1048576 -s `cat /tmp/cache.fincore`


    rm -f /tmp/cache.{pids,files,fincore}




    复制

    使用这个脚本我们再查看一次当前系统中文件缓存状况。
    这基本满足了我的查看需求。
    看上面汇总的Page Cache 大小是207,596,109,824(约194GB),即使我查看全部的进程汇总得到的值也差不多。跟free atop看到总的cache大小(347G)相差还是很大。
    大概相差了 150GB 左右。这个差异数据就是共享内存部分,正是freeshared字段,也是atopshmem字段。还是ORACLE SGA 内存大小。查看ORACLE的参数、共享内存段大小,数据吻合。
    然而,如果你看你的ORACLE环境,看到的现象可能跟我这里还有点区别。一方面当进程关闭了文件后,这个脚本就看不到这个文件的缓存情况,而文件还在Page Cache里缓存。另外一方面这还跟ORACLE的共享内存实现机制有关系,这个下篇文章再介绍。我们先继续就查看Page Cache中文件继续展开。
    ORACLE的表全部在表空间里,所以看到表空间的缓存情况就够了。当然实际上文件系统上的ORACLE都会改为Direct I/O,表空间的文件也就不会缓存了。但是PostgreSQL 数据库至今还不支持Direct I/O。加上PG里的表是单独的文件,并且大表还会按大小切割为很多小文件,文件的缓存状况对数据库的性能还会有影响。这个工具脚本作用就大了。

    PostgreSQL数据库表文件缓存状况

    对一个正在做读写测试的PostgreSQL实例使用上面脚本查看缓存的文件信息,内容非常多,取头部和尾部信息看看。
    头部:
    尾部:
    可以看到缓存的文件大头是表和WAL日志文件。
    不过这里不容易看出是什么表,只能看到数字。当然根据数字到PG元数据库里关联查询也能确定是哪个库哪个表。
    不过PG也提供了一个数据库扩展,可以查看一个表的缓存情况。看名字实现原理跟 linux-fincore类似。

    pgfincore 扩展

    pgfincore 开源项目地址: https://github.com/klando/pgfincore 
    编译安装后,在每个db上创建扩展。然后就可以查询了。
    pgfincore 扩展还提供了多个函数实现类似 linux_fadvise 功能,可以对一个表在Page Cache的缓存策略进行干预。
    这个可以用于数据库重启后的重要大表的快速预热,或者将某个大表从缓存中踢出。
    OS里用 linux_fincore命令可以核实一下这个结果。
    然后我们可以重新预热这个表。
    PG数据库主机的Cache大小也远远大于上面脚本统计的大小,其原因也类似,跟共享内存有关。这个放到下篇介绍。
    参考

    文章转载自数据库技术闲谈,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论

    手机用户0289
    暂无图片
    11月前
    评论
    暂无图片 0
    总内存128G,cache78G,shared499M,使用list_pgf.sh脚本直接结果内存为3G,不知是什么原因
    11月前
    暂无图片 点赞
    评论