配置 MariaDB 主从同步

MariaDB 主从同步

MariaDB/MySQL 内建的复制功能是构建大型,高性能应用程序的基础。将 MySQL 的数据分布到多个系统上去,这种分布的机制,是通过将 MySQL 的某一台主机的数据复制到其它主机(slaves)上,并重新执行一遍来实现的。复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。当一个从服务器连接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,然后封锁并等待主服务器通知新的更新。

请注意当你进行复制时,所有对复制中的表的更新必须在主服务器上进行。否则,你必须要小心,以避免用户对主服务器上的表进行的更新与对从服务器上的表所进行的更新之间的冲突。

1. mysql 支持的复制类型:

  • 基于语句的复制:在主服务器上执行的 SQL 语句,在从服务器上执行同样的语句。MySQL 默认采用基于语句的复制,效率比较高。
    一旦发现没法精确复制时,会自动选着基于行的复制。
  • 基于行的复制:把改变的内容复制过去,而不是把命令在从服务器上执行一遍。 从 mysql5.0 开始支持。
  • 混合类型的复制: 默认采用基于语句的复制,一旦发现基于语句的无法精确的复制时,就会采用基于行的复制。

2. 复制解决的问题

MySQL 复制技术有以下一些特点:

  • 数据分布 (Data distribution )
  • 负载平衡 (load balancing)
  • 备份 (Backups)
  • 高可用性和容错行 High availability and failover

3. 复制如何工作

整体上来说,复制有 3 个步骤:

  • master 将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events);
  • slave 将 master 的 binary log events 拷贝到它的中继日志(relay log);
  • slave 重做中继日志中的事件,将改变反映它自己的数据。

mariadb主从复制示意图.png

该过程的第一部分就是 master 记录二进制日志。在每个事务更新数据完成之前,master 在二日志记录这些改变。MySQL 将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master 通知存储引擎提交事务。

下一步就是 slave 将 master 的 binary log 拷贝到它自己的中继日志。首先,slave 开始一个工作线程 ―― I/O线程。I/O线程在 master 上打开一个普通的连接,然后开始 binlog dump process。Binlog dump process 从 master 的二进制日志中读取事件,如果已经跟上 master,它会睡眠并等待 master 产生新的事件。I/O线程将这些事件写入中继日志。

SQL slave thread(SQL从线程)处理该过程的最后一步。SQL 线程从中继日志读取事件,并重放其中的事件而更新 slave 的数据,使其与 master 中的数据一致。只要该线程与I/O线程保持一致,中继日志通常会位于 OS 的缓存中,所以中继日志的开销很小。

此外,在 master 中也有一个工作线程:和其它 MySQL 的连接一样,slave 在 master 中打开一个连接也会使得 master 开始一个线程。复制过程有一个很重要的限制 ―― 复制在 slave 上是串行化的,也就是说 master 上的并行更新操作不能在 slave 上并行操作。

复制配置过程简介

有两台 MySQL 数据库服务器 MASTER 和 SLAVE,MASTER 为主服务器,SLAVE 为从服务器,初始状态时,MASTER 和 MASTER 中的数据信息相同,当 MASTER 中的数据发生变化时,SLAVE 也跟着发生相应的变化,使得 MASTER 和 SLAVE 的数据信息同步,达到备份的目的。

要点:
负责在主、从服务器传输各种修改动作的媒介是主服务器的二进制变更日志,这个日志记载着需要传输给从服务器的各种修改动作。因此,主服务器必须激活二进制日志功能。从服务器必须具备足以让它连接主服务器并请求主服务器把二进制变更日志传输给它的权限。

配置主从复制的过程:

  1. 主节点操作步骤
    • 启用二进制日志
    • 设置一个在当前集群中唯一的 server-id;
    • 创建一个有复制权限(replication slave,replication client)帐号;
  2. slave 节点的操作步骤
    • 启用中继日志;
    • 设置一个在当前集群中唯一的 server-id;
    • 使用有复制权限的用户帐号连接至主服务器,并启动复制线程;

注意:

  • 服务器版本:主从服务器版本一致;
    如果版本不一致,必须保证从服务器的版本高于主服务器的版本;
  • 如果 mysql 数据库的隔离级别为可读,其二进制日志格式尽量使用基于行的;

实验环境:
服务器版本为:CentOS 7.2

实验拓扑图:
mariadb主从复制拓扑图.png

关闭 SELinux

setenforce = 0
vim /etc/systemctl/selinux
SELINUX=permissive

开启防火墙服务

systemctl mask iptables
firewall-cmd --permanent --add-service=mysql
firewall-cmd --reload

数据库软件版本为:mariadb-5.5.46-linux-x86_64.tar.gz

  • MASTER的IP地址:192.168.1.10/24
  • SLAVE1的IP地址:192.168.1.20/24
  • SLAVE2的IP地址:192.168.1.30/24

若 master 数据库已运行一段时间,可导出 master 数据库内容,使用 scp 命令拷贝至从服务器并导入。

具体命令如下:

# 导出数据库
mysqldump -uroot -p --quick --all-databases --flush-logs --delete-master-logs --single-transaction > sync.sql
# 拷贝至从服务器
scp sync.sql root@slave1:/mydata
# 导入至从服务器
mysql -uroot -p < sync.sql

安装 Mariadb 通用二进制包,
下载二进制包:

]# wget http://mirrors.neusoft.edu.cn/mariadb//mariadb-5.5.56/bintar-linux-x86_64/mariadb-5.5.56-linux-x86_64.tar.gz
]# tar xf mariadb-5.5.56-linux-x86_64.tar.gz -C /usr/local

配置系统环境(主从服务器都适用)

(1). 新建数据库目录,并设置属主属组

]# mkdir /mydata/{data,binlogs} -pv
mkdir: created directory ‘/mydata’
mkdir: created directory ‘/mydata/data’
mkdir: created directory ‘/mydata/binlogs’
]# chown mysql.mysql /mydata -R

(2). 新建用户并配置安装包属主为 mysql

]# useradd -r -s /sbin/nologin mysql
]# id mysql
uid=992(mysql) gid=990(mysql) groups=990(mysql)
]# cd /usr/local
]# chown mysql.root mariadb-5.5.56-linux-x86_64/ -R

(3). 链接安装包目录为 mysql(便于管理)

]# ln -sv mariadb-5.5.56-linux-x86_64/ mysql
‘mysql’ -> ‘mariadb-5.5.56-linux-x86_64/’

]# ll mysql/
total 176
drwxr-xr-x.  2 mysql root   4096 May 22 19:47 bin
-rw-r--r--.  1 mysql root  17987 Apr 30 19:09 COPYING
drwxr-xr-x.  3 mysql root     17 May 22 19:47 data
-rw-r--r--.  1 mysql root   8245 Apr 30 19:09 EXCEPTIONS-CLIENT
drwxr-xr-x.  3 mysql root     18 May 22 19:47 include
-rw-r--r--.  1 mysql root   8694 Apr 30 19:09 INSTALL-BINARY
drwxr-xr-x.  3 mysql root   4096 May 22 19:47 lib
drwxr-xr-x.  4 mysql root     28 May 22 19:47 man
drwxr-xr-x. 11 mysql root   4096 May 22 19:47 mysql-test
-rw-r--r--.  1 mysql root 108813 Apr 30 19:09 README
drwxr-xr-x.  2 mysql root     29 May 22 19:47 scripts
drwxr-xr-x. 27 mysql root   4096 May 22 19:47 share
drwxr-xr-x.  4 mysql root   4096 May 22 19:47 sql-bench
drwxr-xr-x.  3 mysql root   4096 May 22 19:47 support-files

(4). 拷贝并编辑 my.cnf 文件

]# cp support-files/my-large.cnf /etc/my.cnf
cp: overwrite ‘/etc/my.cnf’? y
master
]# vim /etc/my.cnf
log-bin=/mydata/binlogs/mysql-bin
datadir=/mydata/data
skip_name_resolve=on
innodb_file_per_table=on

(5). 初始化数据库并查看生成的文件

]# scripts/mysql_install_db --user=mysql --datadir=/myata/data

]# ls /mydata/{data,binlogs}
/mydata/binlogs:
mysql-bin.000001  mysql-bin.000002  mysql-bin.index

/mydata/data:
aria_log.00000001  aria_log_control  mysql  performance_schema  test

(6). 链接 mysql 运行所需的头文件与库文件

]# ln -sv /usr/local/mysql/include/ /usr/include/mysql
‘/usr/include/mysql’ -> ‘/usr/local/mysql/include/’

# 指定动态链接库文件搜寻目录
[root@master mysql]# vim /etc/ld.so.conf.d/mysql
    /usr/local/mysql/lib
]# ldconfig
]# ldconfig -p | grep mysql         查看动态链接库文件
    libmysqld.so.18 (libc6,x86-64) => /usr/local/mysql/lib/libmysqld.so.18
    libmysqld.so (libc6,x86-64) => /usr/local/mysql/lib/libmysqld.so
    libmysqlclient.so.18 (libc6,x86-64) => /usr/lib64/mysql/libmysqlclient.so.18
    libmysqlclient.so.18 (libc6,x86-64) => /usr/local/mysql/lib/libmysqlclient.so.18
    libmysqlclient.so (libc6,x86-64) => /usr/local/mysql/lib/libmysqlclient.so

(7). 编辑 mariadb 启动单元,以 systemctl 控制

]# vim /etc/systemd/system/mariadb.service
[Unit]
Description=MariaDB database server
After=syslog.target
After=network.target

[Service]
Type=simple
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld_safe  --basedir=/usr/local/mysql
TimeoutSec=300
PrivateTmp=false

[Install]
WantedBy=multi-user.target

]# chmod +x /etc/systemd/system/mariadb.service
]# systemctl daemon-reload  #更新守护进程

(8). 启动 mariadb,并查看端口状态

]# systemctl start mariadb.service    #如为未启动成功,再次启动一次即可(原因未知)
]# ss -nl | grep 3306
tcp    LISTEN     0      50                     *:3306                  *:*

(9). 配置系统环境变量

]# vim /etc/profile.d/mysql.sh      #profile.d目录下的文件开机会自动执行一次
export PATH=/usr/local/mysql/bin:$PATH

]# source /etc/profile.d/mysql.sh    #读取shell脚本
]# echo $PATH
/usr/local/mysql/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

(10). 安全初始化数据库

]# mysql_secure_installation 

Enter current password for root (enter for none): 
OK, successfully used password, moving on...

Set root password? [Y/n] y                  #是否设置root密码
New password: 
Re-enter new password: 
Password updated successfully!
Reloading privilege tables..
 ... Success!

 Remove anonymous users? [Y/n] y           #是否删除匿名用户
 ... Success!

Disallow root login remotely? [Y/n] y       #是否允许root用户远程登录
 ... Success!

Remove test database and access to it? [Y/n] y      #是否删除测试数据库
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reload privilege tables now? [Y/n] y        #是否立即更新权限
 ... Success!

配置 master 服务器

(1). 编辑 master 的 my.cnf 配置文件并重启服务

[root@master mysql]# vim /etc/my.cnf
log-bin=/mydata/binlogs/mysql-bin    #二进制日志文件路径
datadir=/mydata/data                 #数据库文件路径
binlog_format=mixed                  #二进制日志文件保存格式为混合模式(语句,行)
server-id       = 1                  #服务器id号

[root@master mysql]# systemctl restart mariadb.service   #重启服务

(2). 登录 mysql,并创建有复制权限的用户

[root@master mysql]# mysql -uroot -p

MariaDB [(none)]> GRANT REPLICATION CLIENT,REPLICATION SLAVE ON *.* TO 'backup1'@'slave1' IDENTIFIED BY 'backpass';         #创建有复制权限,并制定登录主机的用户
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> SHOW MASTER STATUS;      #查看master的日志和pos点
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 |     1832 |              |                  |
+------------------+----------+--------------+------------------+

配置 slave1 服务器

(1). 编辑 slave1 的 my.cnf 配置文件并重启服务

[root@slave1 mysql]# vim /etc/my.cnf

log-bin=/mydata/binlogs/mysql-bin
datadir=/mydata/data
relay-log=/mydata/binlogs                       #中继日志文件路径
relay-log_index=/mydata/binlogs/relay-bin.index #中继日志文件索引路径名称
log_slave_updates=on                            #将复制事件写进自己的二进制日志
skip_name_resolve=on                            #跳过名称解析
innodb_file_per_table=on                        #开启innodb引擎独立表空间
read_only=on                                    #开启只读防止改变数据
binlog_format=mixed                             #二进制日志文件保存格式为混合模式(语句,行)
server-id       = 2                             #id号不得与其他服务器相同

[root@slave1 mysql]# systemctl restart mariadb.service   #重启服务

(2). 登录 slave1 的数据库

[root@slave1 mysql]# mysql -uroot -p

MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='master',\  #主服务器主机名称
    -> MASTER_USER='backup1',\                             #用于复制的用户
    -> MASTER_PASSWORD='backpass',\                        #复制用户的密码
    -> MASTER_PORT=3306,\                                  #连接使用的端口
    -> MASTER_LOG_FILE='mysql-bin.000003',\                #起点日志文件
    -> MASTER_LOG_POS=1832,\                               #起点位置
    -> MASTER_CONNECT_RETRY=10,\                           #连接重试间隔
    -> MASTER_HEARTBEAT_PERIOD=2;                          #心跳间隔时间
Query OK, 0 rows affected (0.00 sec)

(3). 启动同步并查看从服务器同步状态

MariaDB [(none)]> START SLAVE;                            #启动同步进程
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> SHOW SLAVE STATUS\G                     #查看从服务器线程的关键参数的信息
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: master
                  Master_User: backup1                    #被用于连接主服务器的当前用户
                  Master_Port: 3306
                Connect_Retry: 10                         #连接重试间隔
              Master_Log_File: mysql-bin.000003           #I/O线程当前正在读取的主服务器二进制日志文件的名称
          Read_Master_Log_Pos: 1832                       #在当前的主服务器二进制日志中,I/O线程已经读取的位置
               Relay_Log_File: relay-bin.000003           #SQL线程当前正在读取和执行的中继日志文件的名称
                Relay_Log_Pos: 529                        #在当前的中继日志中,SQL线程已读取和执行的位置
        Relay_Master_Log_File: mysql-bin.000003           #由SQL线程执行的包含多数近期事件的主服务器二进制日志文件的名称
             Slave_IO_Running: Yes                              #I/O线程是否被启动并成功地连接到主服务器上
            Slave_SQL_Running: Yes                              #SQL线程是否被启动
            ...
             Master_Server_Id: 2

(4). 建立有复制权限的用户,让 slave2 可以复制本地 binlog

MariaDB [(none)]> GRANT REPLICATION CLIENT,REPLICATION SLAVE ON *.* TO 'backup2'@'slave2' IDENTIFIED BY 'backpass';
Query OK, 0 rows affected, 1 warning (0.00 sec)

MariaDB [(none)]> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 |     1655 |              |                  |
+------------------+----------+--------------+------------------+

配置 slave2 服务器

(1). 编辑 slave2 的 my.cnf 配置文件并重启服务

[root@slave2 mysql]# vim /etc/my.cnf
datadir=/mydata/data
relay-log=/mydata/binlogs                                     #中继日志文件路径
relay-log_index=/mydata/binlogs/relay-bin.index               #中继日志文件索引路径名称
log_slave_updates=on                                          #将复制事件写进自己的二进制日志
skip_name_resolve=on                                          #跳过名称解析
innodb_file_per_table=on                                      #开启innodb引擎独立表空间
read_only=on                                                  #开启只读防止改变数据
binlog_format=mixed                                           #二进制日志文件保存格式为混合模式(语句,行)
server-id       = 3                                           #id号不得与其他服务器相同

[root@slave2 mysql]# systemctl restart mariadb.service   #重启服务

(2). 登录 slave2 数据库

[root@slave1 mysql]# mysql -uroot -p

MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST='slave1',\    #服务器主机名称
    -> MASTER_USER='backup2',\                               #用于复制的用户
    -> MASTER_PASSWORD='backpass',\                          #复制用户的密码
    -> MASTER_PORT=3306,\                                    #连接使用的端口
    -> MASTER_LOG_FILE='mysql-bin.000003',\                  #起点日志文件
    -> MASTER_LOG_POS=1655,\                                 #起点位置
    -> MASTER_CONNECT_RETRY=10,\                             #连接重试间隔
    -> MASTER_HEARTBEAT_PERIOD=2;                            #心跳间隔时间
Query OK, 0 rows affected (0.00 sec)

(3). 启动同步并查看从服务器同步状态

MariaDB [(none)]> START SLAVE;                              #启动同步进程
Query OK, 0 rows affected, 1 warning (0.00 sec)

MariaDB [(none)]> SHOW SLAVE STATUS\G                       #查看从服务器线程的关键参数的信息
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: slave1
                  Master_User: backup2
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 3038
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 1912
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes                          #I/O线程是否被启动并成功地连接到主服务器上
            Slave_SQL_Running: Yes                          #SQL线程是否被启动
            ...
             Master_Server_Id: 2

主从同步测试

(1). 在主服务器导入数据库(让数据库发生改变即可)

[root@master mysql]# mysql -uroot -p < hellodb.sql   #导入数据库文件
[root@master mysql]# mysql -uroot -p

MariaDB [(none)]> SHOW DATABASES;                    #查看数据库
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hellodb            |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)

MariaDB [(none)]> USE hellodb                        #进入数据库
Database changed
MariaDB [hellodb]> SHOW TABLES;                      #查看表
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes           |
| coc               |
| courses           |
| scores            |
| students          |
| teachers          |
| toc               |
+-------------------+
7 rows in set (0.00 sec)

(2). 登录 slave2 从服务器查看同步是否成功

[root@slave2 mysql]# mysql -uroot -p
MariaDB [(none)]> SHOW DATABASES;                       #查看数据库同步是否更新     
+--------------------+
| Database           |
+--------------------+
| information_schema |
| hellodb            |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.00 sec)

MariaDB [(none)]> USE hellodb;                         #进入数据库
Database changed
MariaDB [hellodb]> SHOW TABLES;                        #查看表
+-------------------+
| Tables_in_hellodb |
+-------------------+
| classes           |
| coc               |
| courses           |
| scores            |
| students          |
| teachers          |
| toc               |
+-------------------+
7 rows in set (0.00 sec)

(3). 查看 slave2 的主服务器的 pos 点,与本地的中继 pos 点

MariaDB [(none)]> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: slave1
                  Master_User: backup2
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 10718                    #在当前的主服务器二进制日志中,I/O线程已经读取的位置已改变
               Relay_Log_File: relay-bin.000002
                Relay_Log_Pos: 9592                     #在当前的中继日志中,SQL线程已读取和执行的位置已改变
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
            ...

同步成功,读写分离实验待续。。。

如果觉得这对你有用,请随意赞赏,给与作者支持
评论 0
最新评论