记录一次mysql5.7oomkill
集群节点环境
[root@master ~]# uname -a
Linux master 5.14.0-229.el9.x86_64
启动mysq:5.7镜像会出现oomkill,属于系统镜像问题,解决方法有两个,使用centos7(centos8未测试),或者修改镜像启动命令
修改镜像启动命令参考了链接:
https://learnku.com/articles/34598
大致内容如下
MySQL 源码分析
MySQL 源码中直接调用 getrlimit 的地方不多,排除了 ndb、innodb_memcached、libevent 之后,只有一处直接调用:
static uint set_max_open_files(uint max_file_limit)
{
struct rlimit rlimit;
uint old_cur;
DBUG_ENTER("set_max_open_files");
DBUG_PRINT("enter",("files: %u", max_file_limit));
if (!getrlimit(RLIMIT_NOFILE,&rlimit))
{
old_cur= (uint) rlimit.rlim_cur;
DBUG_PRINT("info", ("rlim_cur: %u rlim_max: %u",
(uint) rlimit.rlim_cur,
(uint) rlimit.rlim_max));
if (rlimit.rlim_cur == (rlim_t) RLIM_INFINITY)
rlimit.rlim_cur = max_file_limit;
if (rlimit.rlim_cur >= max_file_limit)
DBUG_RETURN(rlimit.rlim_cur); /* purecov: inspected */
rlimit.rlim_cur= rlimit.rlim_max= max_file_limit;
if (setrlimit(RLIMIT_NOFILE, &rlimit))
max_file_limit= old_cur; /* Use original value */
else
{
rlimit.rlim_cur= 0; /* Safety if next call fails */
(void) getrlimit(RLIMIT_NOFILE,&rlimit);
DBUG_PRINT("info", ("rlim_cur: %u", (uint) rlimit.rlim_cur));
if (rlimit.rlim_cur) /* If call didn't fail */
max_file_limit= (uint) rlimit.rlim_cur;
}
}
DBUG_PRINT("exit",("max_file_limit: %u", max_file_limit));
DBUG_RETURN(max_file_limit);
其中逻辑是:如果系统的文件打开限制是 RLIM_INFINITY 或者比要设置的 max_file_limit 大,都返回系统的限制。
这个函数也只被直接调用一次:
uint my_set_max_open_files(uint files)
{
struct st_my_file_info *tmp;
DBUG_ENTER("my_set_max_open_files");
DBUG_PRINT("enter",("files: %u my_file_limit: %u", files, my_file_limit));
files+= MY_FILE_MIN;
files= set_max_open_files(MY_MIN(files, OS_FILE_LIMIT)); // 获取最大打开文件数
if (files <= MY_NFILE)
DBUG_RETURN(files);
// 分配内存
if (!(tmp= (struct st_my_file_info*) my_malloc(key_memory_my_file_info,
sizeof(*tmp) * files,
MYF(MY_WME))))
DBUG_RETURN(MY_NFILE);
// 初始化
/* Copy any initialized files */
memcpy((char*) tmp, (char*) my_file_info,
sizeof(*tmp) * MY_MIN(my_file_limit, files));
memset((tmp + my_file_limit), 0,
MY_MAX((int) (files - my_file_limit), 0) * sizeof(*tmp));
my_free_open_file_info(); /* Free if already allocated */
my_file_info= tmp;
my_file_limit= files;
DBUG_PRINT("exit",("files: %u", files));
DBUG_RETURN(files);
}
原来 MySQL 会根据最大可打开文件数,提前为每个文件分配和初始化内存,在这个时候就可能分配过多内存,导致 OOM。
解决
启动前设置 ulimit
因为 K8s 目前不支持设置 ulimit,不少 Helm Chart 都在启动前设置 ulimit。
command: ["sh","-c", "ulimit -n 4096 && exec /usr/local/bin/docker-entrypoint.sh mysqld"]
针对mysql镜像重新制作新的镜像,dockerfile如下
FROM mysql:5.7.36
CMD ["/bin/sh", "-c", "ulimit -n 4096 && docker-entrypoint.sh mysqld"]