1. MySQL多实例介绍
- 什么是MySQL多实例
MySQL多实例就是在一台服务器上同时开启多个不同的服务端口(如3306、3307),同时运行多个MySQL服务进程,这些服务进程通过不同的socket监听不同的服务端口来提供服务。
这些MySQL多实例共用一套MySQL安装程序,使用不同的my.cnf配置文件、启动程序(也可以相同)和数据文件。在提供服务时,多实例MySQL在逻辑上看起来是各自独立的,它们根据配置文件的对应设定值来获得服务器相应数量的硬件资源。
打个比方,MySQL多实例就相当于房子的多个卧室,每个实例可以看作是一间卧室,整个服务器就是一套房子,服务器的硬件资源(cpu、mem、disk)、软件资源(CentOS系统)可以看作是房子的卫生间、厨房、客厅,是房子的公用资源。
- MySQL多实例的作用与问题
1、可有效利用服务器资源
2、节约服务器资源
MySQL多实例有它的好处,也有其弊端,比如,会存在资源互相抢占的问题。
2. MySQL多实例的生产应用场景
- 资金紧张型公司的选择
- 并发访问不是特别大的业务
- 门户网站应用MySQL多实例场景
3. MySQL多实例常见的配置方案
- 单一配置文件、单一启动程序多实例部署方案
该方案的缺点是耦合度太高,只有一个配置文件,不好管理。工作开发和运维的统一原则是:降低耦合度。所以不推荐此方案 - 多配置文件、多启动程序部署方案
提示:这里的配置文件my.cnf、启动程序mysql都是独立的文件,数据文件data目录也是独立的
4. 安装并配置多实例MySQL数据库
1、安装MySQL需要的依赖包和编译软件
安装依赖包和gcc环境
[root@oldboy ~]# yum install ncurses-devel libaio-devel -y
[root@oldboy ~]# yum install gcc gcc-c++ -y
[root@oldboy ~]# yum install wget -y ---如果没有wget工具,用yum安装
安装编译MySQL需要的软件
[root@oldboy ~]# yum install cmake -y
2、建立MySQL用户账号
[root@oldboy ~]# useradd -s /sbin/nologin -M mysql ---默认会创建和mysql用户同名的组
[root@oldboy ~]# id mysql
uid=500(mysql) gid=500(mysql) groups=500(mysql)
3、下载mysql软件包
[root@oldboy ~]# mkdir -p /home/oldboy/tools ---建立专门的软件目录
[root@oldboy ~]# cd !$
cd /home/oldboy/tools
[root@oldboy tools]# wget -q http://mirrors.163.com/mysql/Downloads/MySQL-5.6/mysql-5.6.41.tar.gz
[root@oldboy tools]# ls -lh
total 31M
-rw-r--r--. 1 root root 31M Jun 15 2018 mysql-5.6.41.tar.gz
4、解压并配置mysql
[root@oldboy tools]# tar xf mysql-5.6.41.tar.gz
[root@oldboy tools]# cd mysql-5.6.41
[root@oldboy mysql-5.6.41]# cmake . -DCMAKE_INSTALL_PREFIX=/application/mysql-5.6.41 \
-DMYSQL_DATADIR=/application/mysql-5.6.41/data \
-DMYSQL_UNIX_ADDR=/application/mysql-5.6.41/tmp/mysql.sock \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DWITH_EXTRA_CHARSETS=all \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_FEDERATED_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITHOUT_EXAMPLE_STORAGE_ENGINE=1 \
-DWITH_ZLIB=bundled \
-DWITH_SSL=bundled \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_EMBEDDED_SERVER=1 \
-DENABLE_DOWNLOADS=1 \
-DWITH_DEBUG=0
5、编译并安装mysql
[root@oldboy mysql-5.6.41]# make
[root@oldboy mysql-5.6.41]# make install
6、为mysql安装路径设置不带版本号的软链接/application/mysql
[root@oldboy mysql-5.6.41]# ln -s /application/mysql-5.6.41/ /application/mysql
[root@oldboy mysql-5.6.41]# ll /application/
total 4
lrwxrwxrwx. 1 root root 26 Jan 30 03:17 mysql -> /application/mysql-5.6.41/
drwxr-xr-x. 13 root root 4096 Jan 30 02:34 mysql-5.6.41
[root@oldboy mysql-5.6.41]# ls /application/mysql/
bin COPYING data docs include lib man mysql-test README scripts share sql-bench support-files
7、创建MySQL多实例的数据文件目录
下面配置3306、3307两个实例,创建MySQL多实例的目录如下:
[root@oldboy ~]# mkdir -p /data/{3306,3307}/data
[root@oldboy ~]# tree /data/
/data/
├── 3306
│ └── data
└── 3307
└── data
4 directories, 0 files
8、创建MySQL多实例的配置文件
[root@oldboy ~]# cd /home/oldboy/tools/mysql-5.6.41
[root@oldboy mysql-5.6.41]# ll support-files/*.cnf
-rw-r--r--. 1 root root 1126 Jan 29 20:24 support-files/my-default.cnf
[root@oldboy mysql-5.6.41]# mv /etc/my.cnf /etc/my.cnf.bak
[root@oldboy mysql-5.6.41]# vi /data/3306/my.cnf
[client] ---客户端模块
port=3306 ---客户端端口
socket=/data/3306/mysql.sock
[mysqld] ---服务端模块
user=mysql ---用户
port=3306 ---端口
socket=/data/3306/mysql.sock ---socket路径
basedir=/application/mysql ---mysql安装路径
datadir=/data/3306/data ---mysql数据文件
log-bin=/data/3306/mysql-bin ---二进制日志
server-id=6
[mysqld_safe] ---启动服务模块
log-error=/data/3306/oldboy_3306.err ---错误日志
pid-file=/data/3306/mysqld.pid ---进程号文件
:wq
[root@oldboy mysql-5.6.41]# vi /data/3307/my.cnf
[client]
port=3307
socket=/data/3307/mysql.sock
[mysqld]
user=mysql
port=3307
socket=/data/3307/mysql.sock
basedir=/application/mysql
datadir=/data/3307/data
log-bin=/data/3307/mysql-bin
server-id=7
[mysqld_safe]
log-error=/data/3307/oldboy_3307.err
pid-file=/data/3307/mysqld.pid
:wq
[root@oldboy ~]# tree /data/
/data/
├── 3306
│ ├── data
│ └── my.cnf ---3306实例的配置文件
└── 3307
├── data
└── my.cnf ---3307实例的配置文件
4 directories, 2 files
9、创建MySQL多实例的启动文件
vi /data/3306/mysql
#!/bin/sh
#init
port=3306
mysql_user="root"
CmdPath="/application/mysql/bin"
mysql_sock="/data/${port}/mysql.sock"
mysqld_pid_file_path=/data/3306/3306.pid
start() {
if [ ! -e "$mysql_sock" ]; then
printf "Starting MySQL...\n"
/bin/sh ${CmdPath}/mysqld_safe --defaults-file=/data/${port}/my.cnf --pid-file=$mysqld_pid_file_path 2>&1 > /dev/null &
sleep 3
else
printf "MySQL is running...\n"
exit 1
fi
}
stop() {
if [ ! -e "$mysql_sock" ]; then
printf "MySQL is stopped...\n"
exit 1
else
printf "Stopping MySQL...\n"
mysqld_pid=`cat "$mysqld_pid_file_path"`
if (kill -0 $mysqld_pid 2>/dev/null); then
kill $mysqld_pid
sleep 2
fi
fi
}
restart() {
printf "Restarting MySQL...\n"
stop
sleep 2
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
*)
printf "Usage: /data/${port}/mysql {start|stop|restart}\n"
esac
:wq
vi /data/3307/mysql
#!/bin/sh
#init
port=3307
mysql_user="root"
CmdPath="/application/mysql/bin"
mysql_sock="/data/${port}/mysql.sock"
mysqld_pid_file_path=/data/3307/3307.pid
start() {
if [ ! -e "$mysql_sock" ]; then
printf "Starting MySQL...\n"
/bin/sh ${CmdPath}/mysqld_safe --defaults-file=/data/${port}/my.cnf --pid-file=$mysqld_pid_file_path 2>&1 > /dev/null &
sleep 3
else
printf "MySQL is running...\n"
exit 1
fi
}
stop() {
if [ ! -e "$mysql_sock" ]; then
printf "MySQL is stopped...\n"
exit 1
else
printf "Stopping MySQL...\n"
mysqld_pid=`cat "$mysqld_pid_file_path"`
if (kill -0 $mysqld_pid 2>/dev/null)
then
kill $mysqld_pid
sleep 2
fi
fi
}
restart() {
printf "Restarting MySQL...\n"
stop
sleep 2
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
*)
printf "Usage: /data/${port}/mysql {start|stop|restart}\n"
esac
:wq
[root@oldboy ~]# tree /data/
/data/
├── 3306
│ ├── data
│ ├── my.cnf ---3306实例的配置文件
│ └── mysql ---3306实例的启动文件
└── 3307
├── data
├── my.cnf ---3307实例的配置文件
└── mysql ---3307实例的启动文件
4 directories, 4 files
在多实例启动文件中,启动MySQL不同实例服务所执行的命令实质上是有区别的,例如,启动3306实例的命令如下:
mysqld_safe --defaults-file=/data/3306/my.cnf > /dev/null 2>&1 &
启动3307实例的命令如下:
mysqld_safe --defaults-file=/data/3307/my.cnf > /dev/null 2>&1 &
其中,“--defaults-file=/data/3307/my.cnf”表示指定配置文件启动,“> /dev/null 2>&1”表示将正确输出和错误输出定向到空。
如何停止MySQL不同实例服务的命令:
printf "Stopping MySQL...\n"
mysqld_pid=`cat "$mysqld_pid_file_path"` ---获取进程pid
if (kill -0 $mysqld_pid 2>/dev/null) ---测试pid对应的mysql进程是否存在
then
kill $mysqld_pid ---根据进程号杀死进程
sleep 2
fi
10、配置MySQL多实例的文件权限
1)通过下面的命令授权mysql用户和组管理整个多实例的根目录/data:
[root@oldboy ~]# chown -R mysql.mysql /data
[root@oldboy ~]# find /data/ -name mysql|xargs ls -l
-rw-r--r--. 1 mysql mysql 885 Jan 30 05:46 /data/3306/mysql
-rw-r--r--. 1 mysql mysql 1156 Jan 30 05:49 /data/3307/mysql
2)通过下面的命令授权mysql多实例所有启动文件的mysql可执行,设置700权限最佳,注意不要使用755权限,因为启动文件里有数据库管理员密码,会被读取到:
[root@oldboy ~]# find /data/ -name mysql|xargs chmod 700
检查权限是否处理完成:
[root@oldboy ~]# find /data/ -name mysql -exec ls -l {} \;
-rwx------. 1 mysql mysql 1156 Jan 30 05:49 /data/3307/mysql
-rwx------. 1 mysql mysql 885 Jan 30 05:46 /data/3306/mysql
从输出来看,权限已经调整完毕
11、MySQL相关命令加入全局路径的配置
[root@oldboy ~]# ls /application/mysql/bin/mysql ---确认mysql命令所在的路径
/application/mysql/bin/mysql
[root@oldboy ~]# echo 'export PATH=/application/mysql/bin:$PATH' >> /etc/profile ---echo后面是单引号,不能用双引号
[root@oldboy ~]# tail -1 /etc/profile
export PATH=/application/mysql/bin:$PATH ---放在前面是为了防止执行时使用老版本的mysql命令
[root@oldboy ~]# source /etc/profile ---使修改的内容直接生效
[root@oldboy ~]# echo $PATH
/application/mysql/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
12、初始化MySQL多实例的数据库文件
初始化3306实例数据库
[root@oldboy ~]# yum -y install perl perl-devel ---此步骤需要有perl和perl-devel,否则会报错
[root@oldboy ~]# cd /application/mysql/scripts/
[root@oldboy scripts]# ./mysql_install_db --defaults-file=/data/3306/my.cnf --basedir=/application/mysql --datadir=/data/3306/data/ --user=mysql ---中间会有两个OK标志代表初始化成功,没初始化成功会出现登录不了数据库等问题
初始化3307实例数据库
[root@oldboy scripts]# ./mysql_install_db --defaults-file=/data/3307/my.cnf --basedir=/application/mysql --datadir=/data/3307/data/ --user=mysql ---中间会有两个OK标志代表初始化成功,没初始化成功会出现登录不了数据库等问题
13、启动MySQL多实例数据库
[root@oldboy scripts]# mkdir -p /application/mysql-5.6.41/tmp ---编译时指定的socket路径
[root@oldboy scripts]# chown -R mysql.mysql /application/mysql
[root@oldboy scripts]# /data/3306/mysql start
Starting MySQL...
190129 20:38:35 mysqld_safe error: log-error set to '/data/3306/oldboy_3306.err', however file don't exists. Create writable for user 'mysql'. ---提示没有找到3306的错误日志文件,需要自己创建
[root@oldboy scripts]# touch /data/3306/oldboy_3306.err;touch /data/3307/oldboy_3307.err ---创建实例3306和3307的错误日志文件
[root@oldboy scripts]# chown mysql.mysql /data/3306/oldboy_3306.err ---这里要把root改成mysql,不然没权限写入错误日志
[root@oldboy scripts]# chown mysql.mysql /data/3307/oldboy_3307.err
[root@oldboy scripts]# /data/3306/mysql start ---启动3306实例
Starting MySQL...
[root@oldboy scripts]# /data/3307/mysql start ---启动3307实例
Starting MySQL...
[root@oldboy scripts]# netstat -antp | grep 330
tcp 0 0 :::3306 :::* LISTEN 1570/mysqld
tcp 0 0 :::3307 :::* LISTEN 1778/mysqld
注意:如果前面有启动单实例数据库的话,要先停止之前启动的数据库
14、MySQL多实例数据库启动故障排错说明
如果MySQL多实例数据库有服务没有被启动,排查方法如下:
如果发现没有显示MySQL对应实例的端口,则稍微等待几秒再检查,MySQL服务的启动比Web服务等会慢一些。如果还不行,则查看MySQL服务对应的错误日志,错误日志路径在my.cnf配置的最下面定义。例如,3306实例的错误日志:
[root@oldboy scripts]# grep log-error /data/3306/my.cnf|tail -1
log-error=/data/3306/oldboy_3306.err
可以执行“tail -100 /data/3306/oldboy_3306.err”检查mysql错误日志
[root@oldboy ~]# tail /data/3306/oldboy_3306.err ---因为新装的mysql,所以信息不多,不需要用"-100"
2019-01-29 21:24:38 2039 [Note] InnoDB: 128 rollback segment(s) are active.
2019-01-29 21:24:38 2039 [Note] InnoDB: Waiting for purge to start
2019-01-29 21:24:38 2039 [Note] InnoDB: 5.6.41 started; log sequence number 1625997
2019-01-29 21:24:38 2039 [Note] Server hostname (bind-address): '*'; port: 3306
2019-01-29 21:24:38 2039 [Note] IPv6 is available.
2019-01-29 21:24:38 2039 [Note] - '::' resolves to '::';
2019-01-29 21:24:38 2039 [Note] Server socket created on IP: '::'.
2019-01-29 21:24:39 2039 [Note] Event Scheduler: Loaded 0 events
2019-01-29 21:24:39 2039 [Note] /application/mysql/bin/mysqld: ready for connections.
Version: '5.6.41-log' socket: '/data/3306/mysql.sock' port: 3306 Source distribution
如果提示级别都为[Note],则表示没有错误,如果提示[ERROR],则表示有报错信息
此外,还可以通过以下方式来检查:
- 细看所有步骤执行命令返回的屏幕输出,不要忽略关键的输出内容
- 查看mysql错误日志/application/mysql/data/机器名.err
- 辅助查看系统日志/var/log/messages
- 如果是MySQL关联了其他服务,则要同时查看相关服务的日志
- 仔细阅读,重新查看所有操作的步骤是否正确,书写的命令及字符是不是都对
- 数据库服务器磁盘空间满了(可用"df -h"查看磁盘空间是否满)
- 防火墙和selinux是否关闭
15、配置及管理MySQL多实例数据库
- 配置MySQL多实例数据库开机自启动
[root@oldboy ~]# echo "#mysql multi instances" >> /etc/rc.local
[root@oldboy ~]# echo "/data/3306/mysql start" >> /etc/rc.local
[root@oldboy ~]# echo "/data/3307/mysql start" >> /etc/rc.local
[root@oldboy ~]# tail -3 /etc/rc.local
#mysql multi instances
/data/3306/mysql start
/data/3307/mysql start
- 登录MySQL测试
[root@oldboy ~]# mysql -S /data/3306/mysql.sock ---多了 -S /data/3306/mysql.sock,用于区别登录不同的实例
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.41-log Source distribution
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> quit
Bye
- MySQL多实例数据库的管理方法
[root@oldboy ~]# /data/3306/mysql stop
Stopping MySQL...
[root@oldboy ~]# /data/3306/mysql start
Starting MySQL...
[root@oldboy ~]# /data/3306/mysql restart
Restarting MySQL...
Stopping MySQL...
Starting MySQL...
- MySQL安全配置
[root@oldboy ~]# mysqladmin -uroot -S /data/3306/mysql.sock password 'oldboy123' ---空密码不安全,设置新密码
Warning: Using a password on the command line interface can be insecure. ---提示在命令行输入密码不安全,这里其实已经设置好密码,先省略
[root@oldboy ~]# mysqladmin -uroot -S /data/3307/mysql.sock password 'oldboy456'
Warning: Using a password on the command line interface can be insecure.
[root@oldboy ~]# mysql -S /data/3306/mysql.sock
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO) ---空密码登录不成功
[root@oldboy ~]# mysql -S /data/3306/mysql.sock -p
Enter password: ---输入新的密码
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.6.41-log Source distribution
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> quit
Bye
带密码登录不同实例数据库的方法
登录3306实例
[root@oldboy ~]# mysql -uroot -poldboy123 -S /data/3306/mysql.sock
登录3307实例
[root@oldboy ~]# mysql -uroot -poldboy456 -S /data/3307/mysql.sock
修改3307实例的密码
[root@oldboy ~]# mysqladmin -uroot -S /data/3307/mysql.sock -poldboy456 password oldboy123
- 再增加一个MySQL实例
mkdir -p /data/3308/data
cp /data/3306/my.cnf /data/3308/
cp /data/3306/mysql /data/3308/
sed -i 's/3306/3308/g' /data/3308/my.cnf
sed -i 's/server-id=6/server-id=8/g' /data/3308/my.cnf
sed -i 's/3306/3308/g' /data/3308/mysql
chown -R mysql.mysql /data/3308
chmod 700 /data/3308/mysql
cd /application/mysql/scripts
./mysql_install_db --defaults-file=/data/3308/my.cnf --basedir=/application/mysql --datadir=/data/3308/data/ --user=mysql
chown -R mysql.mysql /data/3308
egrep "server-id|log-bin" /data/3308/my.cnf
touch /data/3308/oldboy_3308.err
chown mysql.mysql /data/3308/oldboy_3308.err
/data/3308/mysql start
sleep 5
netstat -lnt | grep 3308
提示:最好把server-id按照IP地址最后一个小数点的数字进行设置或者按照实例端口尾数进行设置
- 多实例MySQL登录问题分析
(1)多实例本地登录MySQL
多实例本地登录一般是通过socket文件来指定登录到哪个实例的,此文件的具体位置是在mysql编译过程或者my.cnf文件里指定的。在本地登录数据库时,登录程序会通过socket文件来判断登录的是哪个数据库实例
例如,通过"mysql -uroot -poldboy123 -S /data/3307/mysql.sock"可知,登录的是3307这个实例。mysql.sock文件是MySQL服务端与本地MySQL客户端进行通信的Unix套接字文件
(2)远程连接登录MySQL实例
远程登录MySQL多实例中的一个实例时,通过TCP端口(port)来指定所要登录的MySQL实例,此端口的配置是在MySQL配置文件my.cnf中指定的
例如,在"mysql -uoldboy -poldboy123 -h 10.0.0.7 -P 3307"中,“-P”为端口参数,后面接具体的实例端口,端口是一种“逻辑连接位置”,是客户端程序被分派到计算机上特殊服务程序的一种方式,强调的是提前在10.0.0.7上对oldboy用户做授权