事情是这样的,一个用户测试UAT库,从库无故的频繁的报错
而内存本身是OK的。但为什么是这样的 MYSQL 的版本是官版的8.011
首先我这边在拿到这个问题,想通过PERCONA 的工具集中的pt-pmp 来进行分析,但是在启动pt-pmp 后发现无法运行,直接报 virtual memory exhausted
但问题是内存没有用完,我们也有SWAP呀, 到底就怎么就无法分片内存了。这里突然想起之前看到过的一篇文章,是不是因为 overcommit_memory的配置有问题,导致这个明明有内存,但就是无法分配的问题。
首先我们再熟悉一下overcommit 的值为0 1 2
默认大部分系统选择为 0 , 官方文档的描述为适用于典型的系统,对严重超出预期的内存的分配会拒绝,并且会尽量少的使用SWAP 的内存空间
1 则是一个特别的列子,他并不关心系统的内存是否已经超分了,这样的配置仅仅适用于一些特别的应用程序。
2 则是和 1 的反例,他提供的内存分配仅仅会对整体的系统的50%进行分配, SWAP + 整体的内存的 50% 是他最多能分配的,当无法对应用程序分配内存,系统并不会OOM应用,但应用会接受到一个内存分配的错误。
下面我第一个反应是查询 /proc/sys/vm/overcommit_memory ,果然里面的状态是 2 .
马上修改参数 sudo vi /etc/sysctl.conf
然后在执行 sysctl -p
再次启动PT-PMP 命令
pt-pmp --binary mysqld --iterations 2 --interval 1 --save-samples mysql.txt
在修改后
在查看MYSQL 的错误日志,,从修改后,系统目前也就没有错误了. 后来其他的DBA 想起来当初是为了测试这个参数对数据库的影响,而调整了参数. 忘记改回来了.不过也好,通过这个事情也彻彻底底的弄清楚 overcommit 参数如果在默认情况下设置成 2 ,MYSQL 可能会发生的问题.
相关的代码
- int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
- {
- unsigned long free, allowed;
-
- vm_acct_memory(pages);
-
- /*
- * Sometimes we want to use more memory than we have
- */
- if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS) //overcommit_memory=1,直接返回成功,不做任何限制。
- return 0;
-
- if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) { //overcommit_memory=0,启发式方式,根据当前系统中空闲内存状况来决定是否可以分配内存。
- unsigned long n;
-
- free = global_page_state(NR_FILE_PAGES);
- free += nr_swap_pages;
-
- /*
- * Any slabs which are created with the
- * SLAB_RECLAIM_ACCOUNT flag claim to have contents
- * which are reclaimable, under pressure. The dentry
- * cache and most inode caches should fall into this
- */
- free += global_page_state(NR_SLAB_RECLAIMABLE);
-
- /*
- * Leave the last 3% for root
- */
- if (!cap_sys_admin)
- free -= free / 32; //root用户可以在free更少(3%)的时候,分配内存。
-
- if (free > pages) // pages为需要分配的内存大小,free为根据一定规则算出来的“空闲内存大小”,第一次free仅为NR_FILE_PAGES+NR_SLAB_RECLAIMABLE,由于直接或者系统中“实际空闲”内存代价比较大,所以进行分阶判断,提高效率。
- return 0;
-
- /*
- * nr_free_pages() is very expensive on large systems,
- * only call if we're about to fail.
- */
- n = nr_free_pages(); //当第一次判断不满足内存分配条件时,再进行“实际空闲”内存的获取操作。
-
- /*
- * Leave reserved pages. The pages are not for anonymous pages.
- */
- if (n <= totalreserve_pages)
- goto error;
- else
- n -= totalreserve_pages;
-
- /*
- * Leave the last 3% for root
- */
- if (!cap_sys_admin)
- n -= n / 32;
- free += n;
-
- if (free > pages)
- return 0;
-
- goto error;
- }
-
- allowed = (totalram_pages - hugetlb_total_pages()) //当overcommit_memory=2时,根据系统中虚拟地址空间的总量来进行限制。
- * sysctl_overcommit_ratio / 100;
- /*
- * Leave the last 3% for root
- */
- if (!cap_sys_admin)
- allowed -= allowed / 32;
- allowed += total_swap_pages;
-
- /* Don't let a single process grow too big:
- leave 3% of the size of this process for other processes */
- if (mm)
- allowed -= mm->total_vm / 32;
-
- if (percpu_counter_read_positive(&vm_committed_as) < allowed)
- return 0;
- error:
- vm_unacct_memory(pages);
-
- return -ENOMEM;
- }