创建多实例的 MariaDB

配置 mysqld_multi

若没有安装,先安装 MySQL, 另外 MySQL root 的 plugin 需采用 mysql_native_password

为了同一台机器上管理两个 MySQL 实例,需要使用 mysqld_multi。 在 /etc/mysql/mariadb.conf.d/50-server.cnf 文档中创建两组实例组态。

# 在您修改 50-server.cnf 之前要 停止 MySQL 非常重要!
sudo systemctl stop mysql

# 需要修改 50-server.cnf,可先备份。
mkdir ~/bak
cp /etc/mysql/mariadb.conf.d/50-server.cnf ~/bak
50-server.cnf 文件位置
Linux

/etc/mysql/mariadb.conf.d/50-server.cnf

Windows

\\%host%\root\etc\mysql\mariadb.conf.d\50-server.cnf

在取代之前,说明一下源文件案
# this is only for the mysqld standalone daemon
[mysqld]

#
# * Basic Settings
#
user		= mysql
pid-file	= /var/run/mysqld/mysqld.pid (1)
socket		= /var/run/mysqld/mysqld.sock
port		= 3306
basedir		= /usr
datadir		= /var/lib/mysql (2)
1 运行时创建的文件。注意! 确认该行是否跟您安装的 MariaDB 一样。
2 数据库文件夹
将下列 (6 行)
# this is only for the mysqld standalone daemon
[mysqld]

#
# * Basic Settings
#
取代 (6 行) 成
# Multiple MySQL server configuration
[mysqld_multi]
mysqld     = /usr/bin/mysqld_safe
mysqladmin = /usr/bin/mysqladmin
log        = /var/log/mysqld_multi.log
user       = multi_admin
password   = 'multipass'(1)

[mysqld2](2)
server-id = 2
innodb_flush_method = O_DIRECT
user		= mysql
pid-file	= /var/run/mysqld/mysqld2.pid
socket		= /var/run/mysqld/mysqld2.sock
port		= 3307
basedir		= /usr
datadir		= /var/lib/mysql2
tmpdir		= /tmp
lc-messages-dir	= /usr/share/mysql
skip-external-locking
bind-address		= 127.0.0.1
key_buffer_size		= 16M
max_allowed_packet	= 16M
thread_stack		= 192K
thread_cache_size       = 8
myisam-recover         = BACKUP
query_cache_limit	= 1M
query_cache_size        = 16M
# log_error = /var/log/mysql/error.log
expire_logs_days	= 10
max_binlog_size   = 100M
character-set-server  = utf8mb4
collation-server      = utf8mb4_general_ci

# this is only for the mysqld standalone daemon
[mysqld1](3)
server-id = 1
innodb_flush_method = O_DIRECT
innodb_flush_log_at_trx_commit = 1
sync_binlog = 0
binlog-format = ROW
binlog_do_db = mybb

#
# * Basic Settings
#
1 multipass 改为您要的密码,建议不要改。
2 增加 [mysqld2] 区段 (其实是拷贝原始的 [mysqld] 再改数据库位置)。
3 原始的 [mysqld] 变成 [mysqld1]。这里会混淆,[mysqld] 区段码覆已被覆盖成 [mysqld1] 区段码,原始的 [mysqld] 内容并没有变化。

最后,把 [mysqld1] (原本的 [mysqld]) 内的 log_error 注解成 # log_error

...
# this is only for the mysqld standalone daemon
[mysqld1]
server-id = 1
...
#
# Error log - should be very few entries.
#

# log_error = /var/log/mysql/error.log (1)
1 注解本行。

为什么? 因为在 /var/log/mysqld_multi.log 会有下列消息,该消息已说明要把 log-error 的组态关闭。

200925 18:46:07 mysqld_safe Can’t log to error log and syslog at the same time. Remove all --log-error configuration options for --syslog to take effect.

安装第二个 MySQL2 实例

创建 mysqld2 (第二个 MySQL 数据库实例)
sudo mysql_install_db --user=mysql --datadir=/var/lib/mysql2 --force
启动 mysqld_multi 数据库
sudo mysqld_multi start
检查 mysqld_multi 数据库状态
显示 mysqld_multi 数据库状态:
sudo mysqld_multi report

Reporting MariaDB servers
MariaDB server from group: mysqld2 is running
MariaDB server from group: mysqld1 is running (1)
1 如果不是上述消息表示有错,查一下 tail /var/log/mysqld_multi.log
检查 MySQL 行程及通信情况
检查 MySQL 行程情况:

ps -e | grep "mysql" (1)

1475 ?        00:00:00 mysqld_safe
1622 ?        00:00:07 mysqld
1889 pts/4    00:00:00 mysqld_safe
2282 pts/4    00:00:02 mysqld

检查 MySQL 通信情况:
sudo netstat -tlpn | grep mysql (1)

tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      1622/mysqld
tcp        0      0 127.0.0.1:3307          0.0.0.0:*               LISTEN      2282/mysqld

检查 3306 3307 通信情况:
sudo netstat -nlt | grep 330

tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:3307          0.0.0.0:*               LISTEN
1 如果 netstat 命令不存在,运行 sudo apt install net-tools -y 安装。

mysqld2 改为原生密码认证

设置密码变量 mysqlpw
mysqlpw='MySQL root 密码'
登录 mysqld2
sudo mysql --host=localhost --port=3307 --protocol=tcp mysql
-- 先显示 root 用户的远程帐号 (在 mysql 内):
select user, host from user where user='root' and host <> 'localhost';

-- 删除 root 除了 localhost 之外的其他远程帐号:
delete from user where user='root' and host <> 'localhost';

-- 原生密码认证需同时设置密码及 plugin:
update mysql.user set password=password('$mysqlpw') where user='root';
update user set plugin='mysql_native_password' where user='root';
flush privileges;

-- 退出 mysql
exit;
以密码认证登录 mysql
mysql -uroot -p$mysqlpw --host=localhost --port=3307 --protocol=tcp mysql
调整时区 (在 mysql 内)
set global time_zone = '+8:00';
set time_zone = '+8:00';
检查调整后的情况:
select timediff(now(), utc_timestamp);

结果如下:
+--------------------------------+
| timediff(now(), utc_timestamp) |
+--------------------------------+
| 08:00:00                       |
+--------------------------------+

mysqld_multi 关闭及启动

登录 mysql 指定 port 时必须加上 protocol=tcp 才有作用
先不指定 protocol:
mysql -uroot -p$mysqlpw --host=localhost --port=3307 -N \
-e "show variables where variable_name = 'port';"

port    3306
登录 3307 但实际却为 3306,显然不正确。

指定 protocol=tcp:
mysql -uroot -p$mysqlpw --host=localhost --port=3307 --protocol=tcp -N \
-e "show variables where variable_name = 'port';"

port    3307
登录参数加上 protocol=tcp 才正确。
授予 multi_admin 关闭数据库权限
# mysqld1 授予 multi_admin 关闭数据库权限
mysql -uroot -p$mysqlpw --host=localhost --port=3306 --protocol=tcp<<EOF
grant shutdown on *.* to 'multi_admin'@'localhost' identified by 'multipass'; (1)
flush privileges;
EOF

#mysqld2 授予 multi_admin 关闭数据库权限
mysql -uroot -p$mysqlpw --host=localhost --port=3307 --protocol=tcp<<EOF
grant shutdown on *.* to 'multi_admin'@'localhost' identified by 'multipass'; (1)
flush privileges;
EOF
1 要跟 50-server.cnf 内的 password='multipass' 一致。
再来测试 mysqld_multi 是否运作正确。
停止 mysqld_multi:
sudo mysqld_multi stop

显示 mysqld_multi 状态:
sudo mysqld_multi report

Reporting MariaDB servers
MariaDB server from group: mysqld2 is not running (1)
MariaDB server from group: mysqld1 is not running

启动 mysqld_multi:
sudo mysqld_multi start

显示 mysqld_multi 状态:
sudo mysqld_multi report

Reporting MariaDB servers
MariaDB server from group: mysqld2 is running
MariaDB server from group: mysqld1 is running

检查 mysqld_multi.log 是否异常:
tail /var/log/mysqld_multi.log -n20
1 如果不是上述消息表示有错, 检查一下前面的 multi_admin 关闭数据库权限。
修改 50-server.cnf 应重启 mysqld_multi (别一起贴, 个别运行)
sudo mysqld_multi stop
sudo mysqld_multi start
sudo mysqld_multi report
(务必要) 停止自动启动 mysql 服务:
sudo systemctl disable mysql (1)
1 mysql 的服务状态可能失效;为正常现像。
显示 mysql 服务状态:
systemctl status mysql

结果如下:
Status: "MariaDB server is down"
Active: inactive (dead)
开机自动启动 mysqld_multi
sudo bash -c 'cat > /etc/init.d/mysqld_multi' << "EOF"
#!/bin/sh

### BEGIN INIT INFO
# Provides:       scriptname
# Required-Start: $remote_fs $syslog
# Required-Stop:  $remote_fs $syslog
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Short-Description: Start daemon at boot time
# Description:    Enable service provided by daemon.
### END INIT INFO

bindir=/usr/bin

if [ -x $bindir/mysqld_multi ]; then(1)
  mysqld_multi="$bindir/mysqld_multi";
else
  echo "Can't execute $bindir/mysqld_multi";
  exit;
fi

bindir=/usr/bin

if test -x $bindir/mysqld_multi
then
  mysqld_multi="$bindir/mysqld_multi";
else
  echo "Can't execute $bindir/mysqld_multi";
  exit;
fi

case "$1" in
  'start' )
    "$mysqld_multi" start $2(2)
   ;;
  'stop' )
    "$mysqld_multi" stop $2
   ;;
  'report' )
    "$mysqld_multi" report $2 >&2
  ;;
  'restart' )
    "$mysqld_multi" stop $2
    "$mysqld_multi" start $2
  ;;
  'status' )
    "$mysqld_multi" report >&2
    status=4
    if [ -f /var/run/mysqld/mysqld.pid ]; then
      if [ -f /var/run/mysqld/mysqld2.pid ]; then
        status=0
      fi
    elif [ ! -f /var/run/mysqld/mysqld2.pid ]; then
      status=3
    fi
    if [ $status -eq 4 ]; then
      echo 'Usage: Make the service show question mark' >&2(3)
    fi
    exit $status
  ;;
  *)
   echo "Usage: $0 {start|stop|report|restart|status}" >&2
  ;;
esac
EOF

sudo chmod +x /etc/init.d/mysqld_multi
sudo update-rc.d mysqld_multi defaults
sudo update-rc.d mysqld_multi enable
1 启动 mysqld_multi 服务是运行 MySQL 已经写好的 /usr/bin/mysqld_multi (参阅: Manage Multiple MySQL Servers )。
2 虽然有实作第二个参数,但如果运行 service mysqld_multi [start | stop | restart] 将忽略第 2 个参数, 另外 service (systemctl) 只会判断主要实例作为是否真正需要运行启动、停止或重启,如果主从数据库状态不一致其运作将会异常。 启动数据库使用 mysqld_multi 即可,不应采用 service
3 让 service 显示成未知状态 ?,参考: service --status-all 为什么会出现问号
检查 mysqld_multi 服务状态
sudo service mysqld_multi status

主从拷贝

说明 /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld1] (1)
server-id = 1
innodb_flush_method = O_DIRECT
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1
binlog-format = ROW (2)
binlog_do_db = mybb (3)
log_bin      = /var/log/mysql/mysql-bin.log (4)
expire_logs_days = 10 (5)
1 [mysqld1] 的设置值;即为源文件案的 [mysqld],下列变量已事先在前文加入。
2 binlog-format 采用 ROW。
3 log_do_db 同步的 database,如果多个 database 那么写成多行。
binlog_do_db = db1
binlog_do_db = db2
4 本行缺省为前置注解 (#),把本行的注解取消。
5 [mysqld] 的原始值 (没有改变),自动删除10 天前 Binary Log (binlog) 文件。

磁盘策略参数说明

innodb_flush_method=O_DIRECT,设置刷新磁盘策略

设置值为 fsync(默认值)、O_DSYNCO_DIRECT,最好的方式是去测试。

测试环境
显示 mysql 版本:
mysql --version

mysql  Ver 15.1 Distrib 10.3.27-MariaDB

查找 innodb_buffer_pool_size :
mysql -uroot -p$mysqlpw --host=localhost --port=3306 --protocol=tcp -N \
-e 'SELECT @@innodb_buffer_pool_size;'

134217728 (默认值 128M)
在没有修改 innodb_flush_method 默认值为 fsync
NAS 测试 drupal 运行 cron:
time drupal cron:execute

fsync 的结果:
real    2m27.843s
user    0m51.667s
sys     0m8.643s
在 50-server.cnf 中的 [mysqld1] 区段中加入 innodb_flush_method = O_DIRECT
NAS 测试 drupal 运行 cron:
time drupal cron:execute

O_DIRECT 的结果:
real    2m23.766s
user    0m51.200s
sys     0m8.595s

上述是 NAS 内的 LXC 的测试结果。

桌面型虚拟器内 LXC 测试结果。
桌面型测试 drupal 运行 cron:
time drupal cron:execute

fsync 的结果:
real    1m20.441s
user    0m6.535s
sys     0m21.448s

O_DIRECT 的结果
real    1m15.751s
user    0m6.801s
sys     0m20.653s
innodb_flush_log_at_trx_commit = 1,设置 Commit 写入磁盘策略。

可将 MySQL 写入到磁盘中流程当做三个实体为 MySQL_logbuff (MySQL 日志缓冲) OS_buff (操作系统缓冲) Disk (磁盘)

设置值 0

MySQL_logbuff 每隔 1 秒 → OS_buff → Disk

速度最快,如果 MySQL 当掉,日志缓冲 (内存) 内的事务 (Transaction) 全部会消失,不过也没有比 2 快多少, 不知道为什么写入 OS_buff 后要即时写入 Disk,如果交由 OS 去管理,速度应该可以更快 (当然风险更高)。

设置值 1

MySQL_logbuff → OS_buff → Disk

即时写入,最安全也是速度最慢的策略。

设置值 2

MySQL_logbuff → OS_buff 每隔 1 秒 → Disk

MySQL 当掉前,事务已经交给 OS_buff,如果操作系统正常,那么事务不会流失,但什么情况 MySQL 当掉但 OS 却是正常?

sync_binlog = 1

设置 MySQL 二进制日志 (Binary log)同步到磁盘的频率。

  • 0 当事务提交之后,MySQL 不做磁盘同步让 OS 自行决定,性能最好。

  • 1 当每进行 1 次事务提交之后,MySQL 将进行磁盘同步强制写入磁盘。

  • n 每进行 n 次事务提交之后,MySQL 将进行磁盘同步强制写入磁盘。

innodb_flush_log_at_trx_commitsync_binlog 依实际情况决定,如果有不断电或者 Slave 只作为备份,两者可设为 0。

主从状态同步

在主实例中创建复制用户 (replication):
mysql -uroot -p$mysqlpw --host=localhost --port=3306 --protocol=tcp<<EOF
create user 'replication'@'localhost' identified by 'replication';
grant replication slave on *.* to 'replication'@'localhost';
flush privileges;
EOF
运行以下命令将 mybb (要同步的其一数据库) 转存:
mysqldump -uroot -p$mysqlpw --host=localhost --port=3306 --protocol=tcp -B \
--master-data=1 mybb > repl-1.sql  (1) (2)
1 如果出错 mysqldump: Error: Binlogging on server not active可能是没有取消 log_bin 注解
2 使用选项 --master-data=1 以便备份的文件 (repl-1.sql) 包含 CHANGE MASTER 的语句。

master-data=1 会将 CHANGE MASTER 语句写入 Dump 文件中,在导入从属数据后不需要配置同步的文件及位置。

repl-1.sql 的内容:
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000007', MASTER_LOG_POS=843487;
将 repl-1.sql 导入到从属实例:
mysql -uroot -p$mysqlpw --host=localhost --port=3307 --protocol=tcp < repl-1.sql (1)
1 若已经激活「从属模式」,则会出现下列消息,并提示要停止从属模式
ERROR 1198 (HY000) at line 22: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first
停止「从属模式」
mysql -uroot -p$mysqlpw --host=localhost --port=3307 --protocol=tcp \
-e 'stop slave;'

停止「从属模式」后再次导入。

启动「从属模式」
mysql -uroot -p$mysqlpw --host=localhost --port=3307 --protocol=tcp \
-e 'start slave;'

手动同步「主从状态」

--master-data=2 选项将 mybb 转存:
mysqldump -uroot -p$mysqlpw --host=localhost --port=3306 --protocol=tcp -B \
--master-data=2 mybb > repl-2.sql
repl-2.sql 的内容
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000007', MASTER_LOG_POS=843487; (1)
1 master-data=1 的差别只在于一个是注解。
将 repl-2.sql 导入到从属实例中:
mysql -uroot -p$mysqlpw --host=localhost --port=3307 --protocol=tcp < repl-2.sql
查出 Master status
mysql -uroot -p$mysqlpw --host=localhost --port=3306 --protocol=tcp -e \
'show master status;'
Master status 结果
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000007 |   843487 | mybb,mybb    |                  | (1)
+------------------+----------+--------------+------------------+
1 Slave 按回传值同步。
进入 Slave 同步 Master 状态
登录 Slave:
mysql -uroot -p$mysqlpw --host=localhost --port=3307 --protocol=tcp

在 mysql 内运行下列:
stop slave;

change master to
  master_host='localhost',
  master_user='replication',
  master_password='replication',
  master_log_file='mysql-bin.000007', (1)
  master_log_pos=843487; (1)

start slave;
1 别照抄按 Master status 的结果修改。

检查 Slave 同步状态是否正确
mysql -uroot -p$mysqlpw --host=localhost --port=3307 --protocol=tcp \
-e 'show slave status \G'
检查结果
Slave_IO_State: Waiting for master to send event
    Master_Host: localhost
    Master_User: replication
    Master_Port: 3306
  Connect_Retry: 60
Master_Log_File: mysql-bin.000007 (1)
Read_Master_Log_Pos: 843487 (1)
 Relay_Log_File: ...
  Relay_Log_Pos: ...
Relay_Master_Log_File: mysql-bin.000007 (1)
...
Exec_Master_Log_Pos: 843487 (1)
...
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
...
Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
...
1 若需要可比对 Master status

phpMyAdmin 设置 Slave Database

config.inc.php 文件位置
Linux

/usr/share/phpmyadmin/config.inc.php

Windows

\\%host%\root\usr\share\phpmyadmin\config.inc.php

将下列 (3 行)
/**
 * phpMyAdmin configuration storage settings.
 */
取代 (3 行) 成
 /**
  * Master Server
  */

$cfg['Servers'][$i]['verbose'] = 'Master';

/**
 * Slave server
 */

$i++;
$cfg['Servers'][$i]['auth_type'] = 'cookie';
$cfg['Servers'][$i]['verbose'] = 'Slave';
$cfg['Servers'][$i]['host'] = '127.0.0.1';
$cfg['Servers'][$i]['port'] = '3307';
$cfg['Servers'][$i]['compress'] = false;
$cfg['Servers'][$i]['AllowNoPassword'] = false;

/**
 * phpMyAdmin configuration storage settings.
 */

升级 MariaDB 10.x 至 10.3

检查 MariaDB(mysql) 版本
mysql --version
备份说明
mysqldump --help

-x, --lock-all-tables 锁定所有表格
-A, --all-databases   所有数据库
备份数据库
备份 (单例及多实例主要数据库):
mysqldump -uroot -p$mysqlpw --host=localhost --port=3306 --protocol=tcp -x -A > db1.sql


备份多实例从属数据库 (单例不用运行):
mysqldump -uroot -p$mysqlpw --host=localhost --port=3307 --protocol=tcp -x -A > db2.sql
停止数据库服务
停止多实例数据库服务:
sudo mysqld_multi stop

停止单例数据库服务:
sudo systemctl stop mysql
在加入 Repository 之前,先列出 sources.list 或备份,如果不小心加错,可用回复:
cat /etc/apt/sources.list
cp /etc/apt/sources.list ~/sources.list.bak

可从官方 MariaDB 的 Repository 安装指定的版本,在 Download MariaDB Server - MariaDB.org 选择 Linux 版本、MariaDB 版本和存储库 (repository) 镜像。
例如选择 18.04 LTS "bionic"、MariaDB 10.3: https://mariadb.org/download/?t=repo-config&d=18.04+LTS+"bionic"&v=10.3&r_m=ossplanet

在网页中有说明 Repository 的位置
# MariaDB 10.3 repository list - created 2023-02-02 12:47 UTC
# https://mariadb.org/download/
deb https://ftp.ubuntu-tw.org/mirror/mariadb/repo/10.3/ubuntu bionic main
# deb-src https://ftp.ubuntu-tw.org/mirror/mariadb/repo/10.3/ubuntu bionic main
运行下列命令将 MariaDB 10.3 加入存储库 (Repository)
sudo apt install software-properties-common
sudo apt-key adv --fetch-keys 'https://mariadb.org/mariadb_release_signing_key.asc'
sudo add-apt-repository 'deb https://ftp.ubuntu-tw.org/mirror/mariadb/repo/10.3/ubuntu bionic main' (1)
1 Ubuntu 20.04 TLS,MariaDB 10.4 为 https://ftp.ubuntu-tw.org/mirror/mariadb/repo/10.4/ubuntu focal main
更新套件及安装 MariaDB server.
sudo apt update
sudo apt install mariadb-server -y
启动数据库服务
启动多实例数据库服务:
sudo mysqld_multi start

显示多实例数据库服务状态:
sudo mysqld_multi report

Reporting MariaDB servers
MariaDB server from group: mysqld2 is running
MariaDB server from group: mysqld1 is running

启动单例数据库服务:
sudo systemctl start mariadb
更新数据库
更新数据库 (单例及多实例主要数据库):
sudo mysql_upgrade --port=3306 --protocol=tcp -uroot -p$mysqlpw

更新多实例从属数据库 (单例不用运行):
sudo mysql_upgrade --port=3307 --protocol=tcp -uroot -p$mysqlpw

多实例从属数据库检查 Slave 同步状态是否正确,如果正确则不需要重新同步。