我们都知道数据库是IO密集型应用。为了提高它们的性能,大量IO操作使用内存而不是文件(交换分区)是保证数据库稳定性和效率的基本原则。那么数据库是如何使用内存的,我们如何查看数据库的内存使用情况,如何通过设置数据库内存配置来提高其性能呢?本文以Mysql数据库(InnoDB引擎)为例,了解Linux数据库和内存相关的话题。读取内存数据非常快。为了提高性能,我们需要将所有的数据集尽可能的放在内存中,以保证高效。但是,Swap交换分区是一根救命稻草。mysql也要设置,防止出现紧急情况下内存不足,直接OOM杀死mysql服务的情况。同时,mysql交换分区的占用也是我们衡量一个数据是否健康的一种手段。如果一个数据库经常使用swap,就意味着我们需要人工干预来优化数据库。内存使用情况在Linux下,我们可以通过一些shell命令来了解MySQL的内存使用情况。先用ps命令查看mysqld进程的内存使用情况:ps-eosize,pid,user,command--sort-size|grepmysqld|awk'{hr=$1/1024;printf("%13.2fMB",hr)}{for(x=4;x<=NF;x++){printf("%s",$x)}print""}'|cut-d""-f2|cut-d"-"-f11990.88MB/usr/local/mariadb/bin/mysqld0.49MB/bin/sh/usr/local/mariadb/bin/mysqld_safetop命令也可以查看上面对应的结果用top也可以得到:top-b-o%MEM-n1-p$(pidofmysqld)|grepPID-APIDUSERPNIVIRTRESSHRS%CPU%MEMTIME+COMMAND2239mysql20021085363168367548S0.04.048:47.37mysqld其中VIRT(virtualmemoryusage)表示mysql使用的虚拟内存总量。它包括所有代码、数据和共享库以及最终将被换出的页面。RES(residentmemoryusage)常驻内存,包括当前进程使用的内存,不包括被替换的内存。SHR(sharedmemory)共享内存,进程使用的共享内存,也包括其他进程的共享内存。交换分区让我们检查一下mysqld是否正在使用交换分区。首先使用free-m查看swap分区是否被使用。free-mtotalusedfreesharedbuff/cacheavailableMem:782250911788325522290Swap:399923997以上结果说明系统使用了少量swap分区(2M),那么如何判断是否被MySQL使用呢?我们来验证一下:cat/proc/$(pidofgitlab)/status|grepSwapVmSwap:0kB可以看出mysqld没有使用交换区,说明我的mysqld运行效率很高。这里我们提供一个脚本来遍历每个进程,找出哪些进程使用了??交换分区:foriin$(ls-d/proc/[0-9]*)doout=$(grepSwap$i/status2>/dev/null)if["x$(echo$out|awk'{print$2}')"!="x0"]&&["x$(echo$out|awk'{print$2}')"!="x"]thenecho"$(ps-p$(echo$i|cut-d'/'-f3)|tail-n1|awk'{print$4'}):$(echo$out|awk'{print$2$3}')"fidone当然,exchange中的页面可能已经存在很久了,既然用过一次,后面就没有再用过。为了获得实时的swap分区状态,我们可以使用vmstat:vmstat110在这个服务器上,我们可以看到mysqld没有使用swap。如果系统内存足够了,但是mysqld还是占据了部分swap分区,这是怎么回事?如何检查?如果发生这种情况,可能的直接原因是swappiness和Numa。Swappinessswappiness参数控制内核将进程移出物理内存并移入交换磁盘分区的趋势。我们之前也说过,磁盘IO操作比RAM慢得多,所以如果进程过于频繁地从内存中换出,这会导致系统和应用程序响应时间变慢。高swappiness值意味着内核更有可能取消内存页面。相反,低交换性,内核将不太可能取消内存页面。swappiness值越高,替换的系统内存就越多。linux下系统(CentOS、RedHat、ubuntu)默认的swappiness值是60,如果内存小,这个值要适当调高。对于有足够内存的MySQL服务器,这个默认设置有点太高了,应该降低。一般来说,业界建议这个值可以设置为5.以下。设置swappiness的方法是使用sysctl命令直接更改内核参数。sysctl-wvn.swappinness=1NUMA设置的另一个方面是NUMA设置。对于具有多个NUMA核心的服务器,建议将NUMA模式设置为交错以平衡所有节点之间的内存分配。最新的MySQL8.0支持为InnoDB设置NUMA。可以通过启动配置:innodb_numa_interleave=1要检查是否有多个NUMA节点,可以使用numactl-H这是两个不同的输出:我们可以看到当有多个NUMA节点时(下图),默认情况下,内存会不会在所有节点之间平均分配。这会导致更多的内存位移。文件系统缓存默认情况下,Linux会使用文件系统来缓存所有的I/O操作(这也是不推荐使用MyISAM的原因之一,MyISAM存储引擎依赖于FS缓存,可能会导致数据丢失)。在MysqlInnoDB引擎中使用O_DIRECT作为innodb_flush_method,MySQL将绕过文件系统缓存,不会对数据文件(*.ibd)使用任何FSCacheMemory。当然,MySQL中使用的其他非数据文件还是会使用FSCache。我们来看个例子:dbsakefincorebinlog.000017binlog.000017:total_pages=120841cached=50556percent=41.84ls-lhbinlog.000017-rw-r-----1mysqlmysql473MSep1807:17binlog.000017free-mtotalusedfreesharedbufferscachedMem:5965460813561284352456-/+buffers/cache:17164249Swap:2045302015dbsakeuncachebinlog.000017Uncachedbinlog.000017#free-mtotalusedfreesharedbufferscachedMem:5965441315521284352259-/+buffers/cache:17184247Swap:2045302015开始检查文件系统缓存中存在多少二进制日志(使用dbsakefincore),我们可以看到473M中有42%使用RAM作为FScache.Ithenforceunusedthesepagesincache(usingfincoreuncache),andasaresult,wefreed+/-195MBofRAM.
