【第七篇】MySQL主从复制原理详解【重点】

1.1 简介

小公司业务代码一般存于一个服务器上,而这个服务器有的时候可能会宕机,导致业务停顿,造成不必要的影响。这个时候就需要做高可用,比如两个ngix+两个tomcat+两个mysql实现高可用,避免单点问题

主从复制: 指一台服务器充当主数据库服务器,另一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器之中。对于多级复制,数据库服务器即可充当主机,也可充当从机。MySQL主从复制的基础是主服务器对数据库修改记录二进制日志,从服务器通过主服务器的二进制日志自动执行更新

1.2 MySQL支持的复制类型

1、基于语句的复制 : 主库把sql语句写入到bin log中,完成复制
2、基于行数据的复制: 主库把每一行数据变化的信息作为事件,写入到bin log,完成复制
3、混合复制: 上面两个结合体,默认用语句复制,出问题时候自动切换成行数据复制

提示:和上面相对应的日志格式也有三种【STATEMENT,ROW,MIXED】

  • STATEMENT模式(SBR)
    每一条会修改数据的sql语句会记录到binlog中。优点是并不需要记录每一条sql语句和每一行的数据变化,减少了binlog日志量,节约IO,提高性能。缺点是在某些情况下会导致master-slave中的数据不一致(如sleep()函数, last_insert_id(),以及user-defined functions(udf)等会出现问题)

  • ROW模式(RBR)
    不记录每条sql语句的上下文信息,仅需记录哪条数据被修改了,修改成什么样了。而且不会出现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的问题。缺点是会产生大量的日志,尤其是alter table的时候会让日志暴涨。

  • MIXED模式(MBR)
    以上两种模式的混合使用,一般的复制使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog,MySQL会根据执行的SQL语句选择日志保存方式。

1.3 MySQL主从复制流程

【第七篇】MySQL主从复制原理详解【重点】_第1张图片

1、主库db的更新事件(update、insert、delete)被写到binlog

2、主库创建一个binlog dump thread,把binlog的内容发送到从库

3、从库启动并发起连接,连接到主库

4、从库启动之后,创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log

5、从库启动之后,创建一个SQL线程,从relay log里面读取内容,从Exec_Master_Log_Pos位置开始执行读取到的更新事件,将更新内容写入到slave的db

1.4 主从复制(读写分离)的好处

通俗来讲,如果对数据库的读和写都在同一个数据库服务器中操作,业务系统性能会降低。
为了提升业务系统性能,优化用户体验,可以通过做主从复制(读写分离)来减轻主数据库的负载
而且如果主数据库宕机,可快速将业务系统切换到从数据库上,可避免数据丢失。

1.4.1 MySQL主从复制(读写分离)和集群的区别

1.4.1.1 主从复制(读写分离)

一般需要两台及以上数据库服务器即可(一台用于写入数据,一台用于同步主的数据并用于数据查询操作

1、局限性: 配置好主从复制之后,同一张表,只能对一个服务器写操作。如果在从上执行了写操作,而之后主也操作了这张表,或导致主从不同步
2、主数据库服务器宕机,需要手动将业务系统切换到从数据库服务器。无法做到高可用性(除非再通过部署keepalive做成高可用方案)。

1.4.1.2 集群

集群是由N台数据库服务器组成,数据的写入和查询是随机到任意一台数据库服务器的,其他数据库服务器会自动同步数据库的操作
任何一台数据库宕机,不会对整个集群造成大的影响

局限性:我经过测试才知道目前mysql集群版本(MySQL Cluster)只能对NDB存储引擎的数据进行集群同步,如果是INNODB或其他的MySQL存储引擎是不行的。这个也导致了我放弃了在业务系统中应用这种方案。

1.5 主从复制原理解析

MySQL主从复制是一个异步的复制过程,主库发送更新事件到从库,从库读取更新记录,并执行更新记录,使得从库的内容与主库保持一致

1.5.1 binlog

binary log,主库中保存所有更新事件日志的二进制文件。binlog是数据库服务启动的一刻起,保存数据库所有变更记录(数据库结构和内容)的文件。在主库中,只要有更新事件出现,就会被依次地写入到binlog中,之后会推送到从库中作为从库进行复制的数据源。

1.5.2 binlog输出线程

binlog输出线程,每当有从库连接到主库的时候,主库都会创建一个线程然后发送binlog内容到从库。 对于每一个即将发送给从库的sql事件,binlog输出线程会将其锁住。一旦该事件被线程读取完之后,该锁会被释放,即使在该事件完全发送到从库的时候,该锁也会被释放。

在从库中,当复制开始时,从库就会创建从库I/O线程和从库的SQL线程进行复制处理。

1.5.3 从库I/O线程

从库I/O线程,当START SLAVE语句在从库开始执行之后,从库创建一个I/O线程,该线程连接到主库并请求主库发送binlog里面的更新记录到从库上。 从库I/O线程读取主库的binlog输出线程发送的更新并拷贝这些更新到本地文件,其中包括relay log文件

1.5.4 从库的SQL线程

从库的SQL线程,从库创建一个SQL线程,这个线程读取从库I/O线程写到relay log的更新事件并执行。

1.5.5 小结

对于每一个主从复制的连接,都有三个线程。拥有多个从库的主库为每一个连接到主库的从库创建一个binlog输出线程,每一个从库都有它自己的I/O线程和SQL线程

从库通过创建两个独立的线程,使得在进行复制时,从库的读和写进行了分离。因此,即使负责执行的线程运行较慢,负责读取更新语句的线程并不会因此变得缓慢。比如说,如果从库有一段时间没运行了,当它在此启动的时候,尽管它的SQL线程执行比较慢,它的I/O线程可以快速地从主库里读取所有的binlog内容。这样一来,即使从库在SQL线程执行完所有读取到的语句前停止运行了,I/O线程也至少完全读取了所有的内容,并将其安全地备份在从库本地的relay log,随时准备在从库下一次启动的时候执行语句

1.6 配置MySQL主从复制详解

1.6.1 环境准备

本地安装两个mysql,或者使用虚拟机,或者使用docker安装,需要准备两个mysql。

环境:
mysql:5.6
mysql1(master): 172.17.0.3:3307
mysql2(slave): 172.17.0.2:3308

1.6.2 MySQL配置文件配置

mysql1(master): 172.17.0.3 my.cnf 配置文件设置,mysql

#mysql master1 config 
[mysqld]
server-id = 1        # 节点ID,确保唯一
# log config
log-bin = mysql-bin     #开启mysql的binlog日志功能
sync_binlog = 1         #控制数据库的binlog刷到磁盘上去 , 0 不控制,性能最好,1每次事物提交都会刷到日志文件中,性能最差,最安全
binlog_format = mixed   #binlog日志格式,mysql默认采用statement,建议使用mixed
expire_logs_days = 7                           #binlog过期清理时间
max_binlog_size = 100m                    #binlog每个日志文件大小
binlog_cache_size = 4m                        #binlog缓存大小
max_binlog_cache_size= 512m              #最大binlog缓存大
binlog-ignore-db=mysql #不生成日志文件的数据库,多个忽略数据库可以用逗号拼接,或者 复制这句话,写多行

auto-increment-offset = 1     # 自增值的偏移量
auto-increment-increment = 1  # 自增值的自增量
slave-skip-errors = all #跳过从库错误

mysql2(slave): 172.17.0.2 mysql.cnf 配置

[mysqld]
server-id = 2
log-bin=mysql-bin
relay-log = mysql-relay-bin
replicate-wild-ignore-table=mysql.%
replicate-wild-ignore-table=test.%
replicate-wild-ignore-table=information_schema.%

重启两个mysql,让配置生效

1.6.3 master数据库,创建复制用户并授权

1.6.3.1 进入master的数据库,为master创建复制用户

CREATE USER repl_user IDENTIFIED BY 'repl_passwd';

1.6.3.2 赋予该用户复制的权利

grant replication slave on *.* to 'repl_user'@'172.17.0.2'  identified by 'repl_passwd';

FLUSH PRIVILEGES;

1.6.3.3 查看master的状态

show master status;
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000005      120|              | mysql            |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

1.6.3.4 配置从库

mysql> CHANGE MASTER TO 
MASTER_HOST = '172.17.0.3',  
MASTER_USER = 'repl_user', 
MASTER_PASSWORD = 'repl_passwd',
MASTER_PORT = 3307,
MASTER_LOG_FILE='mysql-bin.000005',
MASTER_LOG_POS=120,
MASTER_RETRY_COUNT = 60,
MASTER_HEARTBEAT_PERIOD = 10000; 

# MASTER_LOG_FILE='mysql-bin.000005',#与主库File 保持一致
# MASTER_LOG_POS=120 , #与主库Position 保持一致

启动从库slave进程

mysql> slave start;
Query OK, 0 rows affected (0.04 sec)

查看是否配置成功

SHOW slave STATUS \G

【第七篇】MySQL主从复制原理详解【重点】_第2张图片
如果下面两个参数都是Yes,则说明主从配置成功!

你可能感兴趣的:(java,高可用,主从复制,读写分离,MySQL)