MySQL主从复制虽好,能完美解决数据库单点问题吗?

一、单个数据库服务器的缺点

  • 数据库服务器存在单点问题;
  • 数据库服务器资源无法满足增长的读写请求;
  • 高峰时数据库连接数经常超过上限。

二、如何解决单点问题

  • 增加额外的数据库服务器,组建数据库集群;
  • 同一集群中的数据库服务器需要具有相同的数据;
  • 集群中的任一服务器宕机后,其它服务器可以取代宕机服务器。

三、MySQL主从复制架构
1、主库将变更写入到主库的binlog中

  • 一些MySQL版本并不会开启二进制日志,所以一定要检查是否开启;
  • 如果刚开始没有开启,后面再进行开启的话,需要重启数据库才能生效,而且数据库的重启往往会对业务造成很大的影响;
  • 尽管二进制日志对性能有稍许的影响,所以还是建议大家无论是否使用复制功能,都要开启MySQL二进制日志,因为增量备份也需要二进制日志。

2、从库的IO线程在指定位置读取主库binlog内容存储到本地的中继日志(Relay Log)中

  • 要完成二进制日志的传输过程,MySQL会在从服务器上启动一个工作线程,称为IO线程,这个IO线程会跟主数据库建立一个普通的客户端连接,然后在主服务器上启动一个特殊的二进制转储线程称为binlogdown线程。
  • 从库上的IO线程通过这个二进制转储线程来读取主库上的二进制事件,如果该事件追赶上主库,则会进入sleep状态,直到主库发起信号通知有新事件产生时,才会被唤醒,relay log的格式和binlog格式是完全相同的,
  • 可以使用mysqlbinlog来读取relay log中的内容。
    3、从库的SQL线程读取Relay Log日志中的内容,并在从库中重放
    SQL线程所执行的事件,我们可以通过配置选项来决定是否要写入到从服务器的二进制日志中。
    目前MySQL支持两种复制类型:

  • 基于二进制日志点的复制
  • 基于GTID的复制(MySQL>=5.7推荐使用)

四. 主从复制的一些缺点

虽然主从复制增加了一个数据库副本,但从数据库和主数据库的数据最终会是一致的。之所以说是最终一致,因为MySQL复制是异步的,正常情况下主从复制数据之间会有一个微小的延迟。
通过这个数据库副本看似解决了数据库单点问题,但并不完美:因为这种架构下,如果主服务器宕机,需要手动切换从服务器,业务中断不能忍受,不能满足应用高可用的要求。

1.主从简介

在现代企业中,数据显得尤为重要,而存储数据的数据库选择又五花八门,但无论是何种数据库,均存在着一种隐患。
想几个问题:

  • 用一台数据库存放数据,若此数据库服务器宕机了导致数据丢失怎么办?
  • 业务量大了,数据多了,访问的人多了,一台数据库无法保证服务质量了怎么办?

1.1 主从作用

  • 实时灾备,用于故障切换
  • 读写分离,提供查询服务
  • 备份,避免影响业务(这里说的备份是备份sql服务器,而不是备份数据)
  • 1.2 主从形式
    Mysql主从_第1张图片

  • 一主一从
  • 主主复制
  • 一主多从—扩展系统读取的性能,因为读是在从库读取的
  • 多主一从—5.7开始支持
  • 联级复制

2. 主从复制原理

主从复制步骤:

  • 主库将所有的写操作记录到binlog日志中并生成一个log dump线程,将binlog日志传给从库的I/O线程
  • 从库生成两个线程,一个I/O线程,一个SQL线程
  • I/O线程去请求主库的binlog,并将得到的binlog日志写到relay log(中继日志) 文件中
  • SQL线程,会读取relay log文件中的日志,并解析成具体操作,然后重放,来实现主从的操作一致,达到最终数据一致的目的

3. 主从复制配置

主从复制配置步骤:

  • 确保从数据库与主数据库里的数据一样
  • 在主数据库里创建一个同步账号授权给从数据库使用
  • 配置主数据库(修改配置文件)
  • 配置从数据库(修改配置文件)

需求:
搭建两台MySQL服务器,一台作为主服务器,一台作为从服务器,主服务器进行写操作,从服务器进行读操作
环境说明:Red Hat Enterprise Linux 8.0 (Ootpa)
Mysql主从

3.1mysql安装

分别在主从两台机上二进制安装mysql-5.7版本,此处略过安装步骤

3.2 mysql主从配置(2个新的mysql服务器)

这里的都是二进制安装的Mysql

3.2.1 确保从数据库与主数据库里的数据一样

为确保从数据库与主数据库里的数据一样,先全备主数据库并还原到从数据库中

//查看数据库
主库的数据库
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| wlw                |
| www                |
+--------------------+
6 rows in set (0.00 sec)
从库的数据库
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)
//全备主库
mysql> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)
//备份主库并将备份文件传送到从库
[root@zhu ~]# mysqldump -uroot -pw --all-databases > /opt/all-202005071900.sql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
[root@zhu ~]# ls /opt/
1  all-202005071900.sql  data
[root@zhu ~]# scp /opt/all-202005071900.sql [email protected]:/opt
The authenticity of host '192.168.66.128 (192.168.66.128)' can't be established.
ECDSA key fingerprint is SHA256:lpKqeNs7QFkySWsYsJ1IMnidcmZotljVvyB/y1YuWW4.
ECDSA key fingerprint is MD5:ad:d8:3d:e7:7e:aa:fd:07:79:3c:7f:ca:82:0c:42:2f.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.66.128' (ECDSA) to the list of known hosts.
[email protected]'s password: 
all-202005071900.sql                                                            100%  774KB  47.5MB/s   00:00    

//在从库上恢复主库的备份并查看,与主库保持一致
[root@cong ~]# ls /opt/
all-202005071900.sql  data
[root@cong ~]# mysql < /opt/all-202005071900.sql 
[root@cong ~]# mysql -e 'show databases;'
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| wlw                |
| www                |
+--------------------+

3.2.2在主数据库里创建一个同步账号授权给从数据库使用

//在主库里面创建一个同步账号授权给从数据库
mysql> create user 'wlw'@'192.168.66.128' identified by 'w' ;
Query OK, 0 rows affected (0.00 sec)

mysql> grant replication slave on *.* to 'wlw'@'192.168.66.128';
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

3.2.3配置主数据库

//配置主库
[root@zhu ~]# vim /etc/my.cnf
[mysql]
basedir = /usr/local/mysql
datadir = /opt/data
socket = /tmp/mysql.sock
port = 3306
pid-file = /opt/data/mysql.pid
user = mysql
skip-name-resolve
log-bin=mysql-bin  //启用binlog日志
server-id=1     //数据库服务器唯一的标识符,主库的值一定要大于从库
relay-log=mysql-relay-bin
symbolic-links=0

log-error=/var/log/mysqld.log

//重启mysql服务
[root@zhu ~]# service mysqld restart
Shutting down MySQL.. SUCCESS! 
Starting MySQL. SUCCESS!
Failed to restart mysqld.service: Unit not found.
[root@zhu ~]# ss -antl
State      Recv-Q Send-Q            Local Address:Port                           Peer Address:Port              
LISTEN     0      128                           *:22                                        *:*                  
LISTEN     0      100                   127.0.0.1:25                                        *:*                  
LISTEN     0      128                          :::22                                       :::*                  
LISTEN     0      100                         ::1:25                                       :::*                  
LISTEN     0      80                           :::3306                                     :::*

[root@zhu ~]# systemctl stop firewalld
[root@zhu ~]# systemctl disable firewalld
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@zhu ~]# vim /etc/selinux/config 
[root@zhu ~]# setenforce 0

3.2.4配置从数据库

//配置从库
[root@cong ~]# vim /etc/my.cnf
[mysql]
basedir = /usr/local/mysql
datadir = /opt/data
socket = /tmp/mysql.sock
port = 3306
pid-file = /opt/data/mysql.pid
user = mysql
skip-name-resolve
log-bin=mysql-bin  //启用binlog日志
server-id=2     //数据库服务器唯一的标识符,主库的值一定要大于从库
relay-log=mysql-relay-bin
symbolic-links=0

log-error=/var/log/mysqld.log

//重启mysql服务
[root@cong ~]# service mysqld restart
Shutting down MySQL.. SUCCESS! 
Starting MySQL. SUCCESS!
[root@cong ~]# ss -antl
State      Recv-Q Send-Q            Local Address:Port                           Peer Address:Port              
LISTEN     0      128                           *:22                                        *:* 
[root@cong ~]# systemctl stop firewalld
[root@cong ~]# systemctl disable firewalld
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@cong ~]# vim /etc/selinux/config 
[root@cong ~]# setenforce 0

LISTEN     0      100                   127.0.0.1:25                                        *:*                  
LISTEN     0      128                          :::22                                       :::*                  
LISTEN     0      100                         ::1:25                                       :::*                  
LISTEN     0      80                           :::3306                                     :::*
//配置并启动主从复制
mysql> CHANGE MASTER TO
 -> MASTER_HOST='192.168.66.128',
 -> MASTER_USER='wlw',
 -> MASTER_PASSWORD='w',
 -> MASTER_LOG_FILE='mysql-bin.000001',
 -> MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.33 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
//查看服务器状态
mysql> show slave status \G
*************************** 1. row ***************************
 Slave_IO_State: Waiting for master to send event
 Master_Host: 192.168.66128
 Master_User: wlw
 Master_Port: 3306
 Connect_Retry: 60
 Master_Log_File: mysql-bin.000001
 Read_Master_Log_Pos: 154
 Relay_Log_File: mysql-relay-bin.000002
 Relay_Log_Pos: 320
 Relay_Master_Log_File: mysql-bin.000001
 Slave_IO_Running: Yes //ྌ॒஠ᶳԅYes
 Slave_SQL_Running: Yes //ྌ॒஠ᶳԅYes
 Replicate_Do_DB:
 Replicate_Ignore_DB: 

3.2.5测试验证

//验证
 在主库表中创建内容
 mysql> use wlw;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from w;
+----+------+------+
| id | name | age  |
+----+------+------+
|  1 | q    |   20 |
|  2 | w    |   23 |
|  3 | e    |   25 |
|  4 | r    |   28 |
+----+------+------+
4 rows in set (0.00 sec)

mysql>  insert into w values (5,'sean',20),(6,'tom',23),(7,'jerry',30);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from w;
+----+-------+------+
| id | name  | age  |
+----+-------+------+
|  1 | q     |   20 |
|  2 | w     |   23 |
|  3 | e     |   25 |
|  4 | r     |   28 |
|  5 | sean  |   20 |
|  6 | tom   |   23 |
|  7 | jerry |   30 |
+----+-------+------+
7 rows in set (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

在从库查看是否同步
mysql> select * from w;
+----+-------+------+
| id | name  | age  |
+----+-------+------+
|  1 | q     |   20 |
|  2 | w     |   23 |
|  3 | e     |   25 |
|  4 | r     |   28 |
|  5 | sean  |   20 |
|  6 | tom   |   23 |
|  7 | jerry |   30 |
+----+-------+------+
7 rows in set (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)