哪些情况下 MySQL 配置文件会被截断?
在初始化 MySQL 实例(版本:5.7.44)的时候报错。
> 作者:龚唐杰,爱可生 DBA 团队成员,主要负责 MySQL 技术支持,擅长 MySQL、PG、国产数据库。 > >爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。 > >本文约 1900 字,预计阅读需要 6 分钟。
背景
在初始化 MySQL 实例(版本:5.7.44)的时候报错。
[root@db1 ~]# /opt/mysql/base/5.7.44/bin/mysqld --defaults-file=/u01/my.cnf --datadir=/u01/3306 --basedir=/opt/mysql/base/5.7.44/ --initialize mysqld: Can't read dir of '/etc/my.cnf.' (Errcode: 2 - No such file or directory) mysqld: [ERROR] Fatal error in defaults handling. Program aborted!
处理步骤
根据报错信息来看,是找不到 /etc/my.cnf.
这个目录。看着比较奇怪,因为目录最后有一个点。
首先,查看 my.cnf
配置文件,发现跟 my.cnf
相关配置的只有 !includedir /etc/my.cnf.d
,然后查看 /etc/my.cnf.d
目录是存在的。
[root@db1 ~]# cat /u01/my.cnf|grep /etc/my.cnf !includedir /etc/my.cnf.d [root@db1 ~]# ls -l /etc/my.cnf.d total 4 -rw-r--r-- 1 root root 232 May 6 2020 mysql-clients.cnf
尝试校验一下配置文件正确性,发现依旧如此。
[root@db1 ~]# /opt/mysql/base/5.7.44/bin/mysqld --defaults-file=/u01/my.cnf --help mysqld: Can't read dir of '/etc/my.cnf.' (Errcode: 2 - No such file or directory) mysqld: [ERROR] Fatal error in defaults handling. Program aborted!
由此怀疑是配置文件有问题。尝试把 !includedir /etc/my.cnf.d
删除后,发现能正常读取。
[root@db1 ~]# cp /u01/my.cnf /u01/my.cnf.bak [root@db1 ~]# vi /u01/my.cnf.bak [root@db1 ~]# /opt/mysql/base/5.7.44/bin/mysqld --defaults-file=/u01/my.cnf.bak --help /opt/mysql/base/5.7.44/bin/mysqld Ver 5.7.44-log for linux-glibc2.12 on x86_64 (MySQL Community Server (GPL)) Copyright (c) 2000, 2023, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Starts the MySQL database server. Usage: /opt/mysql/base/5.7.44/bin/mysqld [OPTIONS] For more help options (several pages), use mysqld --verbose --help.
这就很奇怪了,为什么写的 /etc/my.cnf.d
,但是报错的是 /etc/my.cnf.
?
在对这两个文件进行对比后发现了一个问题,显示:
[root@db1 ~]# diff /u01/my.cnf /u01/my.cnf.bak 169d168 < !includedir /etc/my.cnf.d \ No newline at end of file
No newline at end of file 表示文件末尾没有换行符,正常来说通过 vi 等编译软件编辑后,最后一行会自动加上换行符。比如刚才改的 /u01/my.cnf.bak
文件中最后一行就存在 newline
。通过 tail
命令可直观发现其中的区别。
[root@db1 ~]# tail -1 /u01/my.cnf.bak #validate_password_policy = MEDIUM [root@db1 ~]# tail -1 /u01/my.cnf !includedir /etc/my.cnf.d[root@db1 ~]#
尝试在 /u01/my.cnf
后面手动添加后,初始化成功。
[root@db1 ~]# echo >> /u01/my.cnf [root@db1 ~]# tail -1 /u01/my.cnf !includedir /etc/my.cnf.d [root@db1 ~]# /opt/mysql/base/5.7.44/bin/mysqld --defaults-file=/u01/my.cnf --datadir=/u01/3306 --basedir=/opt/mysql/base/5.7.44/ --initialize
分析原因
先恢复原先的配置文件后使用 strace 进行调试。
strace -T -tt -s 100 -o /tmp/strace.log /opt/mysql/base/5.7.44/bin/mysqld --defaults-file=/u01/my.cnf --datadir=/u01/3306 --basedir=/opt/mysql/base/5.7.44/ --initialize 11:43:17.274860 stat("/u01/my.cnf", {st_mode=S_IFREG|0644, st_size=4581, ...}) = 0 <0.000005> 11:43:17.274886 open("/u01/my.cnf", O_RDONLY) = 3 <0.000006> 11:43:17.274910 fstat(3, {st_mode=S_IFREG|0644, st_size=4581, ...}) = 0 <0.000004> 11:43:17.274927 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa11a196000 <0.000005> 11:43:17.274945 read(3, "[universe]\niops = 0\nmem_limit_mb = 0\ncpu_quota_percentage = 0\nquota_limit_mb = 0\nscsi_pr_level = 0\nu"..., 4096) = 4096 <0.000007> 11:43:17.274997 read(3, "e-schema-consumer-events-stages-history=ON\nperformance-schema-consumer-events-stages-history-long=ON"..., 4096) = 485 <0.000004> 11:43:17.275018 read(3, "", 4096) = 0 <0.000004> 11:43:17.275035 openat(AT_FDCWD, "/etc/my.cnf./", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or directory) <0.000005> 11:43:17.275077 write(2, "mysqld: ", 8) = 8 <0.000009> 11:43:17.275101 write(2, "Can't read dir of '/etc/my.cnf.' (Errcode: 2 - No such file or directory)", 73) = 73 <0.000004> 11:43:17.275120 write(2, "\n", 1) = 1 <0.000004> 11:43:17.275140 close(3) = 0 <0.000005> 11:43:17.275157 munmap(0x7fa11a196000, 4096) = 0 <0.000007> 11:43:17.275179 write(2, "mysqld: ", 8) = 8 <0.000004> 11:43:17.275196 write(2, "[ERROR] Fatal error in defaults handling. Program aborted!", 58) = 58 <0.000004> 11:43:17.275213 write(2, "\n", 1) = 1 <0.000004> 11:43:17.275324 exit_group(1) = ?
配置文件最后加上 newline
后能正常初始化成功,调试的结果如下。
strace -T -tt -s 100 -o /tmp/strace2.log /opt/mysql/base/5.7.44/bin/mysqld --defaults-file=/u01/my.cnf --datadir=/u01/3306 --basedir=/opt/mysql/base/5.7.44/ --initialize 11:48:40.550423 stat("/u01/my.cnf", {st_mode=S_IFREG|0644, st_size=4582, ...}) = 0 <0.000005> 11:48:40.550449 open("/u01/my.cnf", O_RDONLY) = 3 <0.000006> 11:48:40.550473 fstat(3, {st_mode=S_IFREG|0644, st_size=4583, ...}) = 0 <0.000004> 11:48:40.550490 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7faf63733000 <0.000005> 11:48:40.550508 read(3, "[universe]\niops = 0\nmem_limit_mb = 0\ncpu_quota_percentage = 0\nquota_limit_mb = 0\nscsi_pr_level = 0\nu"..., 4096) = 4096 <0.000006> 11:48:40.550560 read(3, "e-schema-consumer-events-stages-history=ON\nperformance-schema-consumer-events-stages-history-long=ON"..., 4096) = 486 <0.000004> 11:48:40.550583 openat(AT_FDCWD, "/etc/my.cnf.d/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4 <0.000005> 11:48:40.550615 brk(NULL) = 0x336d000 <0.000003> 11:48:40.550630 brk(0x338f000) = 0x338f000 <0.000004> 11:48:40.550660 getdents(4, /* 3 entries */, 32768) = 88 <0.000006> 11:48:40.550680 getdents(4, /* 0 entries */, 32768) = 0 <0.000004> 11:48:40.550697 close(4) = 0 <0.000004> 11:48:40.550721 stat("/etc/my.cnf.d/mysql-clients.cnf", {st_mode=S_IFREG|0644, st_size=232, ...}) = 0 <0.000004> 11:48:40.550740 open("/etc/my.cnf.d/mysql-clients.cnf", O_RDONLY) = 4 <0.000004>
当最后一行不是 !includedir
或者 !include
类型并且也没有 newline
时,调试的结果如下,能正常初始化成功。
12:18:10.341731 stat("/u01/my.cnf", {st_mode=S_IFREG|0644, st_size=4599, ...}) = 0 <0.000005> 12:18:10.341756 open("/u01/my.cnf", O_RDONLY) = 3 <0.000006> 12:18:10.341783 fstat(3, {st_mode=S_IFREG|0644, st_size=4599, ...}) = 0 <0.000005> 12:18:10.341807 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f304d65a000 <0.000005> 12:18:10.341827 read(3, "[universe]\niops = 0\nmem_limit_mb = 0\ncpu_quota_percentage = 0\nquota_limit_mb = 0\nscsi_pr_level = 0\nu"..., 4096) = 4096 <0.000009> 12:18:10.341897 read(3, "e-schema-consumer-events-stages-history=ON\nperformance-schema-consumer-events-stages-history-long=ON"..., 4096) = 503 <0.000005> 12:18:10.341923 openat(AT_FDCWD, "/etc/my.cnf.d/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4 <0.000006> 12:18:10.341948 brk(NULL) = 0x34fb000 <0.000003> 12:18:10.341963 brk(0x351d000) = 0x351d000 <0.000005> 12:18:10.341988 getdents(4, /* 3 entries */, 32768) = 88 <0.000007> 12:18:10.342016 getdents(4, /* 0 entries */, 32768) = 0 <0.000005> 12:18:10.342038 close(4) = 0 <0.000004> 12:18:10.342062 stat("/etc/my.cnf.d/mysql-clients.cnf", {st_mode=S_IFREG|0644, st_size=232, ...}) = 0 <0.000004> 12:18:10.342081 open("/etc/my.cnf.d/mysql-clients.cnf", O_RDONLY) = 4 <0.000005>
当最后一行是 !include
类型并且也没有 newline
时,调试的结果如下:
12:24:16.055588 stat("/u01/my.cnf", {st_mode=S_IFREG|0644, st_size=4596, ...}) = 0 <0.000005> 12:24:16.055614 open("/u01/my.cnf", O_RDONLY) = 3 <0.000006> 12:24:16.055653 fstat(3, {st_mode=S_IFREG|0644, st_size=4596, ...}) = 0 <0.000007> 12:24:16.055676 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcb0b65c000 <0.000005> 12:24:16.055695 read(3, "[universe]\niops = 0\nmem_limit_mb = 0\ncpu_quota_percentage = 0\nquota_limit_mb = 0\nscsi_pr_level = 0\nu"..., 4096) = 4096 <0.000006> 12:24:16.055747 read(3, "e-schema-consumer-events-stages-history=ON\nperformance-schema-consumer-events-stages-history-long=ON"..., 4096) = 500 <0.000004> 12:24:16.055768 read(3, "", 4096) = 0 <0.000004> 12:24:16.055788 stat("/etc/my.cnf.d/mysql-clients.cn", 0x7ffd8c379280) = -1 ENOENT (No such file or directory) <0.000004> 12:24:16.055809 read(3, "", 4096) = 0 <0.000004> 12:24:16.055827 close(3) = 0 <0.000005>
根据上面调试显示,每次会以 4096 字节进行读取配置文件,若最后遇到 !includedir
或者 !include
开头的且没有 newline
时,会多进行一次读取 0 字节的操作,由此引发了截断问题。
总结
MySQL 初始化解析配置文件时:
- 当最后一行为
!includedir
类型且没有newline
,会自动截断最后一个字符,所以会报错Can't read dir of '/etc/my.cnf.'
,导致初始化失败。 - 当最后一行为
!include
类型且没有newline
,引用的文件名会被截断一个字符导致找不到该文件,但是不会引起初始化程序 aborted。能正常初始化完成。 - 综上所述,推荐配置文件最后需要添加上
newline
,否则可能导致一些异常的情况。
补充
什么情况会遇到最后一行没有换行符?
根据测试以下两种情况会导致此现象:
echo -n "xx" >> my.cnf
printf "xx" >> my.cnf
若还有其他的情况,可一起交流分享。
更多技术文章,请访问:https://opensource.actionsky.com/
关于 SQLE
SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。
✨ Github:https://github.com/actiontech/sqle
📚 文档:https://actiontech.github.io/sqle-docs/
💻 官网:https://opensource.actionsky.com/sqle/
👥 微信群:请添加小助手加入 ActionOpenSource

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
通过MySQL Workbench 将 SQL Server 迁移到GreatSQL
通过MySQL Workbench 将 SQL Server 迁移到GreatSQL 一、概述 MySQL Workbench 提供了可以将Microsoft SQL Server的表结构和数据迁移到 GreatSQL 的功能,此次将通过MySQL Workbench将SQL Server的数据迁移到GreatSQL。 本文章只是简单演示一下单张表的迁移,如果在项目中使用请根据实际情况进行调整。 二、风险评估 1.数据类型不匹配 两种数据库系统的数据类型可能不完全兼容。在迁移过程中,需要确保数据在不同类型之间的正确转换,否则可能导致数据丢失或不准确。 下表显示了Microsoft SQL Server(源)数据类型和GreatSQL数据类型之间的映射。 Microsoft SQL Server Type GreatSQL Type Comment INT INT TINYINT TINYINT UNSIGNED flag set in MySQL. SMALLINT SMALLINT BIGINT BIGINT BIT TINYINT(1) FLOAT FLOAT Precision ...
- 下一篇
“将所有C++程序用Rust重写,这不可能”
快十年了,Rust 怎么还没有取代C++?在9月27日的【开源漫谈】第14期节目中,开源中国OSChina邀请到了马全一、冯洋以及张汉东三位 Rust 专家深入讨论了这一问题。 马全一:江湖人称 “马道长”,目前在华为负责Rust编程语言在国内的生态建设和推广,曾运营openEuler项目并推动Docker容器社区的发展。 张汉东:资深Rust专家,著有《Rust 编程之道》一书,参与了不少开源项目,当前主要工作是承接Rust咨询。 冯洋:南京大学计算机科学与技术系助理研究员,主要研究方向是复杂软件系统的质量保障,同时在南京大学教授编译原理这一课程。研究Rust已有两年,主要集中在两个方向:一是以Rust为核心支撑的软件工程技术研发,二是带领团队基于Rust的编译技术做一些尝试。 以下内容根据直播整理: "safe C++"新草案 张汉东:今天讨论的主题是为什么C++在过去十年里没有被取代。首先,我们需要定义什么是“取代”。有一种观点是将所有的C++程序用Rust重写,但这是不可能的,因为C++已经发展了多年,拥有庞大的代码遗产。 然而,我们可以看到一些进展。例如,某些基础组件,如浏览...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- 2048小游戏-低调大师作品
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2全家桶,快速入门学习开发网站教程
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS6,CentOS7官方镜像安装Oracle11G