.版本
1)操作系统
cat /etc/issue
CentOS release 6.9 (Final)
Kernel \r on an \m
cat /proc/version
Linux version 2.6.32-696.el6.x86_64 ([email protected]) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-18) (GCC) ) #1 SMP Tue Mar 21 19:29:05 UTC 2017
2)mysql数据库版本
mysql --version
mysql Ver 14.14 Distrib 5.6.26, for linux-glibc2.5 (x86_64) using EditLine wrapper
2. 问题描述
2.1 发现问题
新公司数据库全部安装在/opt/路径下(二进制安装),在这之前我是所有的数据库都是按照官方文档部署在/usr/local目录下的。本来觉得这不是什么事,但是发现在/opt/下面安装完mysql 后 使用 mysqld_safe --defaults-file=/etc/my3306.cnf & 启动数据库的时候确报如下错误(my3306.cnf 文件中指已经指定了 basedir=/opt/mysql)
[root@dba-test-1-25 ~]# mysqld_safe --defaults-file=/etc/my3306.cnf &
[1] 42815
[root@dba-test-1-25 ~]# 180502 09:36:53 mysqld_safe Logging to '/data/mysql/mysql3306/log/error3306.log'.
180502 09:36:53 mysqld_safe The file /usr/local/mysql/bin/mysqld
does not exist or is not executable. Please cd to the mysql installation
directory and restart this script from there as follows:
./bin/mysqld_safe&
See http://dev.mysql.com/doc/mysql/en/mysqld-safe.html for more information
[1]+ Exit 1 mysqld_safe --defaults-file=/etc/my3306.cnf
##启动的时候报找不到 /usr/local/mysql/bin/mysqld 可执行文件,我在配置文件中 指定了 basedir = /opt/mysql,怎么还会去/usr/local/mysql/bin下面找mysqld,应该是去/opt/mysql/bin/下面找才对啊。
2.2 问题原因
想要知道真正的原因,那我们就去看一下 mysqld_safe 到底是怎么去找 mysqld 文件,然后启动数据库的,下面我们截取 mysqld_safe脚本中 跟本问题 相关的部分代码(大家可以直接看自己mysqld_safe完整代码)
#
# First, try to find BASEDIR and ledir (where mysqld is)
#
####这部分就是 mysqld_safe 中用来判断 basedir 的那部分代码
if echo '/usr/local/mysql/share' | grep '^/usr/local/mysql' > /dev/null
then
relpkgdata=`echo '/usr/local/mysql/share' | sed -e 's,^/usr/local/mysql,,' -e 's,^/,,' -e 's,^,./,'`
else
# pkgdatadir is not relative to prefix
# pkgdatadir is not relative to prefix
relpkgdata='/usr/local/mysql/share'
fi
####上面的if循环 最后给变量赋值为 relpkgdata='./share'
MY_PWD=`pwd`
####注意了这个 MY_PWD 变量就是问题的关键,这里把当前路径值赋值给 MY_PWD 这个变量
# Check for the directories we would expect from a binary release install
if test -n "$MY_BASEDIR_VERSION" -a -d "$MY_BASEDIR_VERSION"
####注意了 MY_BASEDIR_VERSION 这个变量也是个关键点,mysqld_safe 脚本中的parse_arguments函数会通过启动时指定的配置文件和命令行参数,对该参数进行赋值,如果该参数在配置文件和命令中都出现,则命令行中的值覆盖配置文件中的(其实就是把basedir赋值给该变量)。但是因为脚本中parse_arguments函数的调用是在 "find BASEDIR and ledir" 这部分代码之后,所以,这里的 if test -n "$MY_BASEDIR_VERSION" 为false
then
# BASEDIR is already overridden on command line. Do not re-set.
# Use BASEDIR to discover le.
if test -x "$MY_BASEDIR_VERSION/libexec/mysqld"
then
ledir="$MY_BASEDIR_VERSION/libexec"
elif test -x "$MY_BASEDIR_VERSION/sbin/mysqld"
then
ledir="$MY_BASEDIR_VERSION/sbin"
else
ledir="$MY_BASEDIR_VERSION/bin"
fi
####上面的if循环用来在 MY_BASEDIR_VERSION 变量存在且是目录的时候,生成相应的basedir(如上面分析因为脚本中还未生成MY_BASEDIR_VERSION,我们也没有在执行脚本之前手动设置MY_BASEDIR_VERSION变量,所以脚本不会走到该部分)
elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/bin/mysqld"
then
####如果MY_BASEDIR_VERSION为空,或者不是目录,那么执行上面的 elif判断 "$relpkgdata"/english/errmsg.sys 是否为文件,并且"$MY_PWD/bin/mysqld"是否为可执行文件,如果条件成立,执行then部分(relpkgdata变量上面已经给出)
MY_BASEDIR_VERSION="$MY_PWD" # Where bin, share and data are
####这里是指定basedir目录
ledir="$MY_PWD/bin" # Where mysqld is
####这里是指定 mysqld 可执行文件路径
# Check for the directories we would expect from a source install
####下面的elif判断都类似上面的分析(用来指定basedir目录,和 mysqld 可执行文件路径)
elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/libexec/mysqld"
then
MY_BASEDIR_VERSION="$MY_PWD" # Where libexec, share and var are
ledir="$MY_PWD/libexec" # Where mysqld is
elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/sbin/mysqld"
then
MY_BASEDIR_VERSION="$MY_PWD" # Where sbin, share and var are
ledir="$MY_PWD/sbin" # Where mysqld is
# Since we didn't find anything, used the compiled-in defaults
else
MY_BASEDIR_VERSION='/usr/local/mysql'
ledir='/usr/local/mysql/bin'
####最后else这部分也是关键,就是在前面判断都不成立的情况下,就设置 basedir 为/usr/local/mysql,可执行文件路径为/usr/local/mysql/bin(这就是我执行mysqld_safe时报/usr/local/mysql/bin/mysqld 不存在的原因)
fi
在mysqld_safe脚本的开始部分,我们可以看到如下部分内容,也就是说,二进制安装如果我们的basedir没有用默认的/usr/local/mysql,那么我们必须在basedir 目录下执行mysqld_safe:
# This should be executed in the MySQL base directory if you are using a
# binary installation that is not installed in its compile-time default
# location
通过上面对mysqld_safe 中“First, try to find BASEDIR and ledir (where mysqld is)”这部分代码的分析,我们已经指定问题的原因了,下面总结一下:
其实代码中 MY_BASEDIR_VERSION(basedir) 的判断可以分为三部分:
第一部分 通过MY_BASEDIR_VERSION变量来判断basedir,把MY_BASEDIR_VERSION变量值赋值给 basedir
第二部分 通过 执行mysqld_safe命令的当前路径(pwd)来判断 basedir,把pwd赋值给 basedir
第三部分 如果前面的判断都不符合,则最后设置 MY_BASEDIR_VERSION=/usr/local/mysql (上面例子中执行失败就是因为MY_BASEDIR_VERSION被设置成了 /usr/local/mysql,ledir='/usr/local/mysql/bin')
3. 问题解决
3.1 方案1
如果二进制安装,并且安装路径不是/usr/local/mysql(即basedir 不为 /usr/local/mysql),按要求在 basedir 下执行mysqld_safe 命令
3.2 方案2
在执行 mysqld_safe 命令前,先手动设置 MY_BASEDIR_VERSION 变量为当前 basedir
export MY_BASEDIR_VERSION=/opt/mysql
##这样在 “First, try to find BASEDIR and ledir (where mysqld is)” 时可以使用该变量,就能对 basedir进行正确的赋值
##注意 mysqld_safe “# Second, try to find the data directory”这部分代码中也会用到 MY_BASEDIR_VERSION变量
3.3 方案3
改写 mysqld_safe 脚本,具体怎么改写在这里就不具体说了,如果有需要的朋友可以私下交流