zoukankan      html  css  js  c++  java
  • MySQL服务读取参数文件my.cnf的规律研究探索

    在MySQL中,它是按什么顺序或规律去读取my.cnf配置文件的呢?其实只要你花一点功夫,实验测试一下就能弄清楚,下面的实验环境为5.7.21 MySQL Community Server。其它版本如有不同,请以实际情况为准。

     

    其实,MySQL是按照下面这个顺序来读取my.cnf:

     

        1: /etc/my.cnf

        2: /etc/mysql/my.cnf

        3: /usr/etc/my.cnf

        4: ~/.my.cnf

     

    也就是说首先它会找/etc/my.cnf 这个文件, 如果这个文件不存在,那么它接下来去找/etc/mysql/my.cnf这个文件,依此类推(这个实验很简单,在此略过,不浪费篇幅),如果最后一个文件~/.my.cnf 也不存在,那么会怎么样呢?

    [root@gettestlnx02 ~]# mysql --help | grep my.cnf
                          order of preference, my.cnf, $MYSQL_TCP_PORT,
    /etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf 
    [root@gettestlnx02 ~]# ls /etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf
    ls: cannot access /etc/mysql/my.cnf: No such file or directory
    ls: cannot access /usr/etc/my.cnf: No such file or directory
    ls: cannot access /root/.my.cnf: No such file or directory
    /etc/my.cnf
    [root@gettestlnx02 ~]# 

     

    如上所示,其实MySQL安装完成后,只生成了/etc/my.cnf这个配置文件。其它路径的my.cnf文件是不存在的。我们先来测试一下,将配置文件移走。在这之前,我们先查看一下log_error的位置。如下所示:

     

     

    mysql> show variables like '%log_error%';
    +---------------------+---------------------+
    | Variable_name       | Value               |
    +---------------------+---------------------+
    | binlog_error_action | ABORT_SERVER        |
    | log_error           | /var/log/mysqld.log |
    | log_error_verbosity | 3                   |
    +---------------------+---------------------+
    3 rows in set (0.00 sec)
     
    mysql> exit
    Bye

     

     

    [root@gettestlnx02 ~]# mv /etc/my.cnf  /tmp/my.cnf
    [root@gettestlnx02 ~]# ls -lrt /etc/my.cnf
    ls: cannot access /etc/my.cnf: No such file or directory
    [root@gettestlnx02 ~]# service mysqld stop
    Stopping mysqld:  [  OK  ]
    [root@gettestlnx02 ~]# service mysqld start
    Starting mysqld:  [  OK  ]
    [root@gettestlnx02 ~]# 

     

     

    clip_image001[4]

     

     

    如上所示,即使没了my.cnf配置文件,MySQL服务依然可以启动,那么这个是怎么回事呢? 我们知道service mysqld start启动MySQL,其实是运行/etc/init.d/mysqld这个脚本。下面是脚本获取给变量datadir、socketfile、errlogifle赋值的部分脚本,如下所示:

     

    # Extract value of a MySQL option from config files
    # Usage: get_mysql_option OPTION DEFAULT SECTION1 SECTION2 SECTIONN
    # Result is returned in $result
    # We use my_print_defaults which prints all options from multiple files,
    # with the more specific ones later; hence take the last match.
    get_mysql_option () {
        option=$1
        default=$2
        shift 2  #移动到第3个参数,详情见下面调试。
        result=$(/usr/bin/my_print_defaults "$@" | sed -n "s/^--${option}=//p" | tail -n 1)
        if [ -z "$result" ]; then
            # not found, use default
            result="${default}"
        fi
    }
     
    get_mysql_option datadir "/var/lib/mysql" mysqld
    datadir="$result"
    get_mysql_option socket "$datadir/mysql.sock" mysqld
    socketfile="$result"
    get_mysql_option log-error "/var/log/mysqld.log" mysqld mysqld_safe
    errlogfile="$result"
    get_mysql_option pid-file "/var/run/mysqld/mysqld.pid" mysqld mysqld_safe
    mypidfile="$result"

     

    如果你对shell很熟,那么可以忽略下面步骤,如果不熟悉,那么我们可以手工调试一下(# sh -x mysqld),看看它是如何获取相关变量的值的呢?

     

     

    clip_image002[4]

     

     

    [root@gettestlnx02 ~]# file /usr/bin/my_print_defaults
    /usr/bin/my_print_defaults: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
    [root@gettestlnx02 ~]# /usr/bin/my_print_defaults mysqld
    [root@gettestlnx02 ~]# 

     

    如上所示,因为/usr/bin/my_print_defaults mysqld输出为空,所以result为空值, 所以result被授予${default}的值,而defualt=$2,其实就是第二个变量,如下所示,第二个变量被标记为红色。

     

    get_mysql_option datadir "/var/lib/mysql" mysqld

    datadir="$result"

     

     

    clip_image003[4]

     

    另外,my.cnf的位置是会影响脚本输出结果的。如下所示:(不在几个默认路径的话,my_print_defaults是没有输出结果的)

     

    [root@gettestlnx02 ~]# ls /tmp/my.cnf
    /tmp/my.cnf
    [root@gettestlnx02 ~]# /usr/bin/my_print_defaults mysqld
    [root@gettestlnx02 ~]# mv /tmp/my.cnf  /etc/my.cnf
    [root@gettestlnx02 ~]# /usr/bin/my_print_defaults mysqld
    --datadir=/var/lib/mysql
    --socket=/var/lib/mysql/mysql.sock
    --symbolic-links=0
    --log-error=/var/log/mysqld.log
    --pid-file=/var/run/mysqld/mysqld.pid

     

     

     

    clip_image004[4]

     

     

    接下来,我们将配置文件my.cnf挪回原位(/etc/my.cnf),然后更改数据库数据存储目录(从/var/lib/mysql挪动到/data/mysqldata/mysql 步骤从略),然后我们再做下面测试:

     

     

    [root@gettestlnx02 ~]# service mysqld stop
    Stopping mysqld:  [  OK  ]
    [root@gettestlnx02 ~]# mv /etc/my.cnf  /tmp/my.cnf
    [root@gettestlnx02 ~]# service mysqld start
    Initializing MySQL database:  2018-03-16T01:26:19.589182Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
    2018-03-16T01:26:20.034494Z 0 [Warning] InnoDB: New log files created, LSN=45790
    2018-03-16T01:26:20.132219Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
    2018-03-16T01:26:20.193504Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 07ee8c42-28b9-11e8-a04a-005056b3ebdf.
    2018-03-16T01:26:20.208662Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
    2018-03-16T01:26:20.209919Z 1 [Note] A temporary password is generated for root@localhost: O;kZmIj+.6jf
    [  OK  ]
    Logging to '/var/lib/mysql/gettestlnx02.err'.
    Starting mysqld:  [  OK  ]

     

    clip_image005[4]

     

     

    MySQL服务居然也启动了,它初始化了数据库,数据文件位于/var/lib/mysql。这个确实让我吃了一惊,原本预测,如果更改数据库数据存储目录,MySQL又没有my.cnf配置文件,MySQL服务应该启动不了。当然这个启动也没有什么意义,因为你的数据和一些账号权限配置都没有了(有点类似于SQL Server里面的重建系统数据库)

     

    [root@gettestlnx02 mysql]# cd /var/lib/mysql
    [root@gettestlnx02 mysql]# ls -lrt
    total 122948
    -rw-r-----. 1 mysql mysql 50331648 Mar 16 09:26 ib_logfile1
    -rw-r-----. 1 mysql mysql       56 Mar 16 09:26 auto.cnf
    drwxr-x---. 2 mysql mysql     4096 Mar 16 09:26 performance_schema
    drwxr-x---. 2 mysql mysql     4096 Mar 16 09:26 mysql
    drwxr-x---. 2 mysql mysql    12288 Mar 16 09:26 sys
    -rw-r-----. 1 mysql mysql      420 Mar 16 09:26 ib_buffer_pool
    -rw-------. 1 mysql mysql     1679 Mar 16 09:26 ca-key.pem
    -rw-r--r--. 1 mysql mysql     1107 Mar 16 09:26 ca.pem
    -rw-------. 1 mysql mysql     1675 Mar 16 09:26 server-key.pem
    -rw-r--r--. 1 mysql mysql     1107 Mar 16 09:26 server-cert.pem
    -rw-------. 1 mysql mysql     1675 Mar 16 09:26 client-key.pem
    -rw-r--r--. 1 mysql mysql     1107 Mar 16 09:26 client-cert.pem
    -rw-------. 1 mysql mysql     1675 Mar 16 09:26 private_key.pem
    -rw-r--r--. 1 mysql mysql      451 Mar 16 09:26 public_key.pem
    -rw-------. 1 mysql mysql        6 Mar 16 09:26 mysql.sock.lock
    srwxrwxrwx. 1 mysql mysql        0 Mar 16 09:26 mysql.sock
    -rw-r-----. 1 mysql mysql 12582912 Mar 16 09:26 ibtmp1
    -rw-r-----. 1 mysql mysql 12582912 Mar 16 09:26 ibdata1
    -rw-r-----. 1 mysql mysql 50331648 Mar 16 09:26 ib_logfile0
    -rw-r-----. 1 mysql mysql     3277 Mar 16 09:27 gettestlnx02.err
    [root@gettestlnx02 mysql]# 

     

    测试、折腾过程发现并不是所有情况下都会成功初始化数据库,如果当/var/lib/mysql下存在一些文件时,初始化会报错initialize specified but the data directory has files in it. Aborting.此时,只要你清空

    /var/lib/mysql下文件,就能成功初始化。

     

    [root@gettestlnx02 ~]# service mysqld stop

    [root@gettestlnx02 ~]# mv /etc/my.cnf  /tmp/my.cnf

    [root@gettestlnx02 ~]# service mysqld start

    Initializing MySQL database:  2018-03-16T03:49:45.190114Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).

    2018-03-16T03:49:45.192215Z 0 [ERROR] --initialize specified but the data directory has files in it. Aborting.

    2018-03-16T03:49:45.192246Z 0 [ERROR] Aborting

     

    [FAILED]

    [root@gettestlnx02 ~]#

     

     

    clip_image006[4]

     

    其实只要稍微花费一点心思,查看一下/etc/init.d/mysqld的代码,就会发现start函数里面在条件满足的情况就会初始化数据库。

     

    start(){
        [ -x $exec ] || exit 5
        # check to see if it's already running
        RESPONSE=$(/usr/bin/mysqladmin --no-defaults --socket="$adminsocket" --user=UNKNOWN_MYSQL_USER ping 2>&1)
        if [ $? = 0 ]; then
            # already running, do nothing
            action $"Starting $prog: " /bin/true
            ret=0
        elif echo "$RESPONSE" | grep -q "Access denied for user"
        then
            # already running, do nothing
            action $"Starting $prog: " /bin/true
            ret=0
        else
            # prepare for start
            if [ ! -e "$errlogfile" -a ! -h "$errlogfile" -a "x$(dirname "$errlogfile")" = "x/var/log" ]; then
                install /dev/null -m0640 -omysql -gmysql "$errlogfile"
            fi
            [ -x /sbin/restorecon ] && /sbin/restorecon "$errlogfile"
            if [ ! -d "$datadir/mysql" ] ; then
                # First, make sure $datadir is there with correct permissions
                if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
                    install -d -m0751 -omysql -gmysql "$datadir" || exit 1
                fi
                if [ ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
                    chown mysql:mysql "$datadir"
                    chmod 0751 "$datadir"
                fi
                if [ -x /sbin/restorecon ]; then
                    /sbin/restorecon "$datadir"
                    for dir in /var/lib/mysql-files /var/lib/mysql-keyring ; do
                        if [ -x /usr/sbin/semanage -a -d /var/lib/mysql -a -d $dir ] ; then
                            /usr/sbin/semanage fcontext -a -e /var/lib/mysql $dir >/dev/null 2>&1
                            /sbin/restorecon -r $dir
                        fi
                    done
                fi
                # Now create the database
                initfile="$(install_validate_password_sql_file)"
                action $"Initializing MySQL database: " /usr/sbin/mysqld --initialize --datadir="$datadir" --user=mysql --init-file="$initfile"
                ret=$?
                rm -f "$initfile"
                [ $ret -ne 0 ] && return $ret
                # Generate certs if needed
                if [ -x /usr/bin/mysql_ssl_rsa_setup -a ! -e "${datadir}/server-key.pem" ] ; then
                    /usr/bin/mysql_ssl_rsa_setup --datadir="$datadir" --uid=mysql >/dev/null 2>&1
                fi

     

     

    另外,在多实例情况下,多实例有两种方案:

     

    1、基于mysqld_multi: 多个实例共用同一个my.cnf配置文件中,利用[mysqld1]、[mysqld2]、[mysqld*]标签实现不同实例的差异化配置;

     

    2、基于多配置文件:每一个实例单独一个my.cnf配置文件

     

     

    多实例启动时都会指定对应的my.cnf,所以虽然这里没有详细测试,其实大致的原理也跟单实例是差不多的。当你有疑问或不解的时候,动手实践是检验真理的唯一标准。

     

     

     

     

  • 相关阅读:
    jQuery的deferred对象详解 jquery回调函数
    Table does not have the identity property. Cannot perform SET operation.
    SQLServer中merge函数用法详解
    jQuery事件命名空间多事件绑定自定义事件js 命名空间 javascript命名空间
    you have mixed tabs and spaces fix this
    java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
    SQLServer 窗口函数
    TFS中查看我的所有签入迁出记录 TFS 怎么查看所有的修改
    日历控件My97DatePicker WdatePicker屏蔽 onchange的解决方法
    【Python】生成词云
  • 原文地址:https://www.cnblogs.com/kerrycode/p/8582249.html
Copyright © 2011-2022 走看看