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

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

1752
上篇《Linux 内存 PageCache 和数据库共享内存分析(中)》总结了PG的共享内存特点,本篇我们看看ORACLE共享内存的表现特点并回答最初的疑惑。
在此之前我们先回顾一下进程虚拟内存特点。借网上图。
计算机CPU运行在保护模式,每个进程都有独立的虚拟内存空间(VMA),虚拟内存空间有内核空间和用户空间。所有进程的内核空间大部分内容相同,用户空间里有栈、内存、堆、内存映射区域。用户进程的虚拟内存页面在被访问的时候会跟物理内存页面建立映射关系,每笔记录对应内存页,大小4KiB。进程的虚拟内存地址是连续的,但是对应的物理页面一般是离散的。当物理内存很大或者进程很多的时候,所有进程的内存页映射表空间会比较大。为了降低页表消耗,Linux使用多级页表映射和提供大页技术。
多级页表映射技术不是本文重点就略过了。主要说说大页技术

大页和透明大页

Linux 提供页表大小为2MB1GB两种大小的大页,可以大大减少页表占用的内存,以及提高页地址转换缓存(TLB)的命中率。Linux大页的大小和使用情况可以查看/proc/meminfo 。默认情况是没有启用的。
启用大页需要设置内核参数里的vm.nr_hugepages ,指定大页页数。这个乘以2M 得到的是大页内存大小。
设置大页后使用命令sysctl -p 生效。从无到有,或者调大大页是立即生效的,但是调小大页或者取消大页好像需要重启服务器。
此外,使用大页还需要应用支持(应用要修改代码),ORACLEPG都支持大页。Linux 后来支持一种透明大页(THP),它可以自动创建、管理和使用传统大页,好处是降低使用门槛,坏处是并不适合数据库。透明大页像是动态分配和管理大页,而传统大页是预分配和管理。

关闭透明大页

有关透明大页的用法不是本文重点,这里需要做的是关闭透明大页。
  1. 1.      检查操作系统Transparent HugePages是否关闭。
    root@rac1[/root]#cat sys/kernel/mm/transparent_hugepage/defrag
    always madvise [never]
    如果不是选中 never表示是或者可能会开启。
    1. 2.      备份启动文件。
      # cp boot/grub2/grub.cfg boot/grub2/grub.cfg.bak
      # cp etc/default/grub etc/default/grub.bak
      1. 3.      编辑启动文件,禁用透明大页。
        vi etc/default/grub
        GRUB_CMDLINE_LINUX="crashkernel=128M rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet transparent_hugepage=never"
        4.     重启主机。
        如果上面方法失败,则用下面方法,在主机启动的时候关闭透明大页。
        1. 1.      添加启动项。
          # vi + etc/rc.d/rc.local
          # Disable Transparent HugePages
          if test -f sys/kernel/mm/transparent_hugepage/enabled; then
          echo never > sys/kernel/mm/transparent_hugepage/enabled
          fi
          if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
          echo never > /sys/kernel/mm/transparent_hugepage/defrag
          fi
          chmod +x /etc/rc.d/rc.local
          重启后重新检测是否使用了透明大页。
          在本篇的ORACLE共享内存测试中,都关闭了透明大页。

          ORACLE共享内存

          上篇文章介绍了PG的共享内存特点,这篇介绍ORACLE的共享内存。

          不使用大页和AMM

          首先不启用大页看看。除了不用大页外,还调整几个ORACLE参数。
          参数文件如下:
          关键几个参数是:
          • filesystemio_options= 'setall',启用 Direct I/O和异步I/O。
          • memory_max_target=0 和 memory_target=0,关闭AMM特性。
          • sga_target 设置为 150GB。

          ORACLE 启动后查看free -h 的结果。
          可以看出ORACLE SGA对应的共享内存不算在free命令的used字段,而是在shared 和cache字段里。
          再看atop命令。SGA内存看起来在cache字段、shmem和shrss字段。
          从这两个输出看,ORACLE SGA共享内存这个特点跟PG使用 SYSTEM V创建SHARED BUFFER共享内存时特点是一样的。
          再用ipcs -m 命令确认一下。
          ORACLE创建了多个共享内存,其中最大的是 shmid=15的内存,大小是161598144512 Byte,约等于150.5GB。应该就是SGA。
          再查看进程的maps或者用pmap命令看。
          这个大小跟SGA大小差不多。
          ORACLE 19c在Linux上默认安装应该是延续早期版本的,使用SYSTEM V创建共享内存。所以ORACLE安装前需要配置内核参数shmem等。ORACLE 11g以后推出AMM特性,这个会变化。

          不使用大页和使用AMM

          调整ORACLE参数,设置memory_target和memory_max_target为200GB,但是 sga_target 还是150GB 。
          启动ORACLE实例后,首先看free 命令。
          可以看出 shared字段和cach字段都有121G。推测这是动态SGA的大小。
          再查看atop命令,cache、shmem字段都是121G,shrss只有3M。
          可见SGA对应共享内存没有计算在shrss中。
          这个跟PG的mmap方式实现的共享内存特点类似。我们再看更多线索确认。
          继续查看 ipcs 命令,发现只有一笔记录。并不能确认这个是SGA。
          查看ORACLE pmon进程的maps文件。
          发现进程有很多内存映射记录,每个都有对应的文件。
            1ec0000000-1ec0006000 rw-s 00000000 00:04 36/SYSV377fd2b0 (deleted)


            maps文件里还有一笔deleted记录,根据前面对比名称格式知应该不是SGA。从 smaps里看大小也能知道。我们先看 /dev/shm/下那个文件映射信息。
            这些文件映射的内存大小不一定一样,最大是 524288 KB 即512MB。
            查看实际文件大小也是如此。
            上篇里提到 /dev/shm 是文件系统tmpfs,这是Linux自动创建的文件系统,大小默认为内存的一半。
            根据PG共享内存的特点可以推测ORACLE AMM特性启用时,共享内存使用的是 POSIX 方案。原因估计是tmpfs可以快速动态调整大小。AMM将SGA分割为很多小文件(最大512MB)来实现动态调整SGA和PGA的大小。
            所以SGA共享内存是算在shmem字段中,但不在shrss中。
            接下来看启用大页后会怎样。

            使用大页和不使用AMM

            启用大页方法,修改内核参数
              vim + /etc/sysctl.conf
              vm.nr_hugepages=102400
              sysctl -p
              这里直接简单设置大200GB。然后查看 meminfo文件 看到大页设置生效了。
              大页设置后查看 free 命令(已关闭其他所有ORACLE和PG实例)。
              此时发现 free命令的used字段变为214GB,其中就包含有200GB的大页预留内存,而shared和cache 没有大的变化(毕竟还没有程序创建共享内存)。所以说Linux大页是预分配的,然后支持大页的程序(如ORACLE、PG),只要它申请的内存小于这里200GB,就可以在预留的大页内存里分配。这200G 也不在 available字段里,说明不可回收。
              调整ORACLE实例启动参数,sga设置为150G,关闭AMM特性。
              启动ORACLE实例后,再查看free 命令。
              可见 ORACLE 启动后(创建了共享内存),但这个不会在free命令的shared和cache字段体现。说明free 命令是在used 里统计了这部分内存。
              我们再看 atop 命令的输出。
              同样的,cache 和shmem 里没有包含共享内存,但是shrss里包含了。
              此外,atop增加显示了两个跟大页有关的字段。hptot:total hugepage,hpuse:used hugepage,很好理解。通过atop命令一眼可以看出当前系统启用了多大的大页,以及使用了多少大页。
              再看看ipcs 命令。
              初看跟前面一样,有一笔 sga 共享内存对应的记录,大小能对上。细看,不一样的地方是当使用了大页,shmid 会从更大的值递增,而不是沿着之前的5678递增等。估计内核是有区别对待大页。
              查看pmon进程的maps文件,根据shmid 也是能看出SGA对应的那笔映射记录。
              查看pmon的smaps记录里看到这笔记录的Rss和Pss为0。
              查看所有的dbw进程发现都是这样。
                ps -ef|grep dbw |grep -v grep | awk -F' ' '{print $2}' |sed 's#.*#/proc/&/smaps#' |xargs grep /SYSV00000000 -A3
                最后我们再来看最后一种情形。

                同时使用大页和AMM

                AMM的目标是动态调整SGAPGA的大小,所以才去将tmpfs上文件映射虚拟内存中作为SGA。大页的目标是提前预留一部分2MB页大小的内存,这个不能动态的调整大小。透明大页看起来是动态调整,但ORACLEPG数据库都声明不要用透明大页,有严重性能问题。所以看起来AMM和大页的目标就有点冲突,估计两个特性不能同时用。
                实际测试也证实了这点,当开启大页和AMM时,ORACLE启动报错了,说AMM不支持大页。
                ORACLE 大页测试完了,我们再回到PG看看开启大页时候会怎么样。

                PG 共享内存2

                测试PG的时候将大页从200G调整到66G 左右。由于大页调小后,free 里的used 并不变化,可知内核不会主动释放之前大页预留的内存。此时直接重启服务器。
                确认大页设置生效了。
                used 81G里肯定包含了大页预留内存,sharedcache是初始化状态。
                再看atop结果,跟ORACLE 开启大页前一样,就不再重复解释了。
                根据PG共享内存原理又分 mmapSYSTEM V

                MMAP

                修改PG启动参数shared_memory_type huge_pages启动PG实例。
                查看 free -h 命令输出。
                在读写测试期间,used字段始终未变,shared也不变,不包含sgacache在增长,但基本可以推论出是文件cache的增加。
                atop命令输出大页内存的统计在专门字段hptothpuse里,不在 shmemshrss
                这点跟ORACLE大页表现还不完全一样。推测原因在映射方式上。
                PG进程的pmap输出。
                有一笔大小跟shared_buffers能对得上的映射记录,状态是deleted,名称是 anon_hugepage ,这是 mmap的匿名映射。

                SYSTEM V

                调整shared_memory_type sysv 时,pg启动直接报错了。
                看起来这种方式不支持大页。
                有关大页和数据库的特点就探索到这里。

                总结

                这三篇主要目的是总结ORACLE和PG在不同方案实现共享内存时在 free和atop命令以及进程内存映射文件中里观察到的特征,从而反过来用这两个命令加上加上查看进程内存映射文件方法去分析未知数据库的内存原理和运维特性。
                测试到目前,有下面几个结论。
                • free 命令的cache字段的主要包含文件的缓存和共享内存。如果有共享内存,则在shared字段里也包含了,但不会在available字段里(共享内存不可回收)。但是,如果启用了大页并且共享内存用上了大页,则共享内存这部分内存就不在sharedcache字段里,而会在used字段里。
                • atop命令的cache字段跟free命令的cache一致,shmem字段对应共享内存大小是包含映射到tmpfs那部分内存,shrss就只包含进程中的虚拟内存对应的物理内存。当PGshared_memory_type=sysv时,cacheshmemshrss字段都包含shared_buffer对应的共享内存;但是当shared_memory_type=mmap时,只有cacheshmem字段包含shared_buffer对应的共享内存,shrss不包含。原因是共享内存是将tmpfs上文件映射到进程虚拟内存中。ORACLE使用AMM特性时表现也一样。
                • ORACLE SGA对应共享内存实现默认方案也是system v,所以共享内存在freeatop上体现跟PG是一致的,sharedcache字段都包含,used不包含。但是,如果使用了大页,则转移到free命令的used字段体现。同时,使用大页后,atopcacheshmem字段也不包含共享内存,而shrss字段则包含了这部分大小。
                • 同样是使用大页技术,PGORACLE表现也不一样。ORACLE共享内存会体现在atop命令的shrss字段,而PG的则不会体现在shmemshrss上。不过,只要使用了大页技术,atop命令的hptothpuse字段就会有所体现。透明大页在RedHat 7 以后会默认开启,数据库主机上建议关闭。
                • 文件Cachemmaps文件映射的内存在物理内存不足的时候会被换出,换出之前内存会同步到文件(msync)。
                • 借助于  linux-fincore命令可以用shell脚本找出内存占用最大的进程打开的文件在 PageCache 里缓存情况。进程关闭文件后该文件的缓存还会在。使用命令 linux-fadvise 可以将文件纳入或者踢出 PageCache。

                其他阅读
                Linux 内存 PageCache 和数据库共享内存分析(上)
                Linux 内存 PageCache 和数据库共享内存分析(中)

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

                评论