.版本
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 脚本,具体怎么改写在这里就不具体说了,如果有需要的朋友可以私下交流