前言

听说大家现在都在积极响应国家号召,没事的时候会推着三轮车去街角、天桥摆个地摊。博主刚刚收摊回来,顺手写了篇MySQL。

MySQL相信大家都很熟悉了,单节点MySQL出现性能瓶颈的时候,大家首先想到的是优化SQL。但是单节点毕竟能力有限,所以在优化之后,还是无法满足性能要求时,就会想到部署MySQL读写分离,也就是主从复制。除了性能瓶颈之外,还有单节点故障、单节点容量等问题,都必须依靠集群才能解决。本篇主要讲解MySQL从单机到集群的原理和实践。

环境

  • VMware Workstation 15
  • CentOS Linux release 7.7.1908
  • MySQL 5.7.30

注意事项

  • 三个节点ip分别为192.168.1.101192.168.1.102192.168.1.103
  • 确保三个节点都能访问互联网,并且三个节点能够相互通信
  • 确保Linux的yumwget等基础命令可用
  • 建议先关闭防火墙,Centos 7操作如下
    firewall-cmd --state ## 查看防火墙状态 not running表示已经关闭
    systemctl stop firewalld.service ## 关闭防火墙
    systemctl disable firewalld.service ## 禁止开机启动防火墙
    

需要搭建的主从复制集群如下

单机安装

安装

整个过程请保持网络畅通

wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm
yum -y install mysql57-community-release-el7-10.noarch.rpm
yum -y install mysql-community-server

到这一步,MySQL服务的安装已经完成

启动

启动MySQL

systemctl start  mysqld.service

查看运行状态

systemctl status mysqld.service

执行结果

● mysqld.service - MySQL ServerLoaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)Active: active (running) since 二 2020-06-02 21:58:25 CST; 11s agoDocs: man:mysqld(8)http://dev.mysql.com/doc/refman/en/using-systemd.htmlProcess: 2160 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid $MYSQLD_OPTS (code=exited, status=0/SUCCESS)Process: 2111 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)Main PID: 2163 (mysqld)CGroup: /system.slice/mysqld.service└─2163 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid6月 02 21:58:18 localhost.localdomain systemd[1]: Starting MySQL Server...
6月 02 21:58:25 localhost.localdomain systemd[1]: Started MySQL Server.

根据日志可以看到MySQL Server已经成功启动

找到临时密码

在MySQL的启动日志中,会打印一个临时密码用于登录,用户名是root

cat /var/log/mysqld.log |grep password

执行结果

2020-06-02T13:58:21.946584Z 1 [Note] A temporary password is generated for root@localhost: cScTwtyMl4;*

可以看到我此处的临时密码是cScTwtyMl4;*
用这个密码登录,登录之后需要修改密码,才能进行其他的操作,且密码要满足一定的复杂度

alter user 'root'@'localhost' identified by 'your password';

因为安装了Yum Repository,以后每次yum操作都会自动更新,需要把这个卸载掉

yum -y remove mysql57-community-release-el7-10.noarch

至此,此时MySQL的单机安装已经完成。其余节点均可按照此方法安装。

异步复制

原理

不仅是MySQL,几乎所有的主从复制集群,都是master/slave模式,也就是slave节点从master节点上同步数据。MySQL主从复制的整个过程如下图所示

整个过程可以分为三个步骤

  • master节点把对数据的修改记录到bin log中,所以master节点必须开启bin log
  • slave节点会从指定的位置(logfile和偏移量pos)开始读取masterbin log,把读取到的日志写入自己的relay log
  • slave节点根据relay log中的日志进行重放(replay),slave节点可以配置是否需要写入自己的bin log

了解了MySQL主从复制的基本原理,再来进行主从复制的搭建,就会容易理解很多。

异步复制缺点

为了了解异步复制的缺点,先看如下图

如图所示,描述了一主两从的异步复制集群,相信大家也很容易看出缺点。假设master节点commit之后就宕机了,而此时slave节点可能还没有读到master的全部bin log,就会导致数据丢失

异步复制不仅不能保证masterslave之间的数据一致性,甚至不能保证slaveslave之间的数据一致性。

半同步复制

MySQL5.6对异步复制做了改进,引入半同步复制

半同步复制过程如下

半同步复制在MySQL5.6中被引入,相比于异步复制,主要的改进就是在master写完bin log之后不会直接commit,而是收到slave节点的ACK之后才会commit,期间mastercommit操作被阻塞。当然,为了防止部分slave节点故障导致master迟迟收到不ACKmastercommit操作可以设置超时时间,超时之后,半同步复制降级为异步复制

有经验的同学应该可以看出来,这其实就是两阶段提交master节点commit的时候,slave已经读取了master的完整bin log。即使此时master宕机,slave节点也能通过重放,实现和master节点的数据同步。

基于GTID复制

前文说讲的主从复制集群是依靠logfile + pos的方式实现,除了这种方式外,还有一种就是基于GTID的主从复制。GTID (Global Transaction ID)是全局事务ID

GTID的结构如下:source_id:transaction_id,组成分成两个部分source_idtransaction_id,分别代表执行事务的主机UUID,和事务ID。事务ID是递增的,保证不重复。

  • master节点修改数据时,把GTID写入bin log
  • slave读取master节点的bin log,写入到自己的relay log
  • slave节点的sql_threadrelay log获取GTID,查找自己的bin log中是否有对应的记录
  • 如果有,说明该GTID的事务已经在slave上执行,slave会忽略该事务
  • 如果没有,slave就会从relay log中执行该事务,并记录到bin log

整个过程与logfile + pos方式几乎一致,只是获取执行偏移的方式不同。并且slave节点必须开启bin log

基于GTID的复制和基于日志点的复制有什么区别?

  • 基于日志点的复制是MySQL实现的第一种复制方式,几乎所有的MySQL分支版本都支持
  • 基于日志点的复制,slave请求master的增量日志依赖于日志偏移量
  • 基于日志点的复制配置复制链路时,需要指定master_log_filemaster_log_pos参数,一旦master宕机,很难从新的master中找到正确的偏移量的值
基于日志点的复制 基于GTID的复制
兼容性好 老版本MySQLMariaDB不兼容
支持MMMMHA架构 仅支持MHA架构
主从切换后很难找到新的同步点 基于事务ID的复制,可以很方便的找到未完成的同步的事务ID
可以方便的跳过复制错误 只能置入空事务的方式跳过复制

优先选择基于GTID的复制,不能选择GTID的复制方式时,再使用基于日志点的复制。

实践

异步复制

  • 开启bin log,使用如下命令查看bin log是否开启

    show variables like '%log_bin%';
    +---------------------------------+-------+
    | Variable_name                   | Value |
    +---------------------------------+-------+
    | log_bin                         | OFF   |
    | log_bin_basename                |       |
    | log_bin_index                   |       |
    | log_bin_trust_function_creators | OFF   |
    | log_bin_use_v1_row_events       | OFF   |
    | sql_log_bin                     | ON    |
    +---------------------------------+-------+
    6 rows in set (0.00 sec)
    

    log_binOFF表示未开启,可以使用如下方式开启bin log

    vim /etc/my.cnf
    

    配置如下内容

    ## 开启bin log
    log-bin=/var/lib/mysql/mysql-bin## 服务节点ID,每个节点不一样
    server-id=101## 开启GTID复制模式(如果只想用基于日志点复制,不需要配置这里)
    gtid-mode=on
    enforce-gtid-consistency=1
    

    重启MySQL之后,再次查看bin log开启状态,可以看到bin log已经开启

    show variables like '%log_bin%';
    +---------------------------------+--------------------------------+
    | Variable_name                   | Value                          |
    +---------------------------------+--------------------------------+
    | log_bin                         | ON                             |
    | log_bin_basename                | /var/lib/mysql/mysql-bin       |
    | log_bin_index                   | /var/lib/mysql/mysql-bin.index |
    | log_bin_trust_function_creators | OFF                            |
    | log_bin_use_v1_row_events       | OFF                            |
    | sql_log_bin                     | ON                             |
    +---------------------------------+--------------------------------+
    6 rows in set (0.00 sec)
    

    slave节点均按照此方式配置

  • master创建复制账号并授权
    需要自己指定密码

    create user repl@'192.168.1.%' identified by 'your password';
    grant replication slave on *.* to repl@'192.168.1.%';
    
  • 备份master数据

    mysqldump --single-transaction -uroot -p --routines --triggers --events --master-data=2 --all-databases > sicimike.sql
    

    可以查看备份的文件中,有GTIDlogfile:pos相关的信息

    将备份的文件导入到slave节点的数据库。

  • slave节点上配置复制链路

    ## MASTER_LOG_FILE和MASTER_LOG_POS的值在前一步中可以找到
    change master to master_host='192.168.1.101', MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=2615;
    

    执行成功后,可以查看slave节点的状态

    show slave status\G;
    *************************** 1. row ***************************Slave_IO_State:Master_Host: 192.168.1.101Master_User:Master_Port: 3306Connect_Retry: 60Master_Log_File: mysql-bin.000002Read_Master_Log_Pos: 2615Relay_Log_File: localhost-relay-bin.000001Relay_Log_Pos: 4Relay_Master_Log_File: mysql-bin.000002Slave_IO_Running: NoSlave_SQL_Running: No......
    
  • 启动复制链路

    ## 用户名和密码就是在master上配置的用户名和密码
    start slave user='repl' password= 'your password';
    

    再次查看slave节点的状态

    show slave status\G;
    *************************** 1. row ***************************Slave_IO_State: Waiting for master to send eventMaster_Host: 192.168.1.101Master_User: replMaster_Port: 3306Connect_Retry: 60Master_Log_File: mysql-bin.000002Read_Master_Log_Pos: 2615Relay_Log_File: localhost-relay-bin.000002Relay_Log_Pos: 320Relay_Master_Log_File: mysql-bin.000002Slave_IO_Running: YesSlave_SQL_Running: Yes......
    

    可以看到Slave_IO_RunningSlave_SQL_Running都变成了Yes状态,这两个线程就是前文主从复制原理图io_threadsql_thread

    其余的节点也是以同样的方式配置成slave节点。

至此,基于logfile:pos模式的异步复制已经配置完成。在master节点上进行数据的修改,马上就会同步到slave库

可以在master节点上执行show slave hosts查看追随自己的所有slave节点

show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|       103 |      | 3306 |       101 | d6532e2a-a592-11ea-99c3-000c297f5b55 |
|       102 |      | 3306 |       101 | 1dbd5375-a4d9-11ea-9eef-000c29cf4cca |
+-----------+------+------+-----------+--------------------------------------+
2 rows in set (0.00 sec)

接下来开始配置半同步复制

半同步复制

  • 首先查看master是否安装了半同步复制插件rpl_semi_sync_master,可以使用如下命令查看

    show plugins;
    

    如果没有安装的话,使用如下命令安装

    install plugin rpl_semi_sync_master soname 'semisync_master.so';
    
  • 配置master相关变量
    首先查看半同步复制相关的变量

    show variables like 'rpl%';
    +-------------------------------------------+------------+
    | Variable_name                             | Value      |
    +-------------------------------------------+------------+
    | rpl_semi_sync_master_enabled              | OFF        |
    | rpl_semi_sync_master_timeout              | 10000      |
    | rpl_semi_sync_master_trace_level          | 32         |
    | rpl_semi_sync_master_wait_for_slave_count | 1          |
    | rpl_semi_sync_master_wait_no_slave        | ON         |
    | rpl_semi_sync_master_wait_point           | AFTER_SYNC |
    | rpl_stop_slave_timeout                    | 31536000   |
    +-------------------------------------------+------------+
    7 rows in set (0.01 sec)
    

    rpl_semi_sync_master_enabled变量需要改成ON
    rpl_semi_sync_master_timeout表示半同步复制的超时时间,可以适当修改
    依然是修改/etc/my.cof文件,配置如下内容

    rpl_semi_sync_master_enabled=on
    rpl_semi_sync_master_timeout=500
    

    配置完成后重启MySQL即可

  • 查看slave是否安装了半同步复制插件rpl_semi_sync_slave可以使用如下命令
    show plugins;
    

    如果没有安装的话,使用如下命令安装

    install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
    
  • 配置slave相关变量
    首先查看半同步复制相关的变量

    show variables like 'rpl%';
    +---------------------------------+----------+
    | Variable_name                   | Value    |
    +---------------------------------+----------+
    | rpl_semi_sync_slave_enabled     | OFF      |
    | rpl_semi_sync_slave_trace_level | 32       |
    | rpl_stop_slave_timeout          | 31536000 |
    +---------------------------------+----------+
    3 rows in set (0.01 sec)
    

    rpl_semi_sync_slave_enabled变量需要改成ON,需要修改/etc/my.cof文件,配置如下内容

    rpl_semi_sync_slave_enabled=on
    

    slave完成配置,重启MySQL后,再次查看slave的状态

    show slave status\G;
    *************************** 1. row ***************************Slave_IO_State:Master_Host: 192.168.1.101Master_User:Master_Port: 3306Connect_Retry: 60Master_Log_File: mysql-bin.000003Read_Master_Log_Pos: 194Relay_Log_File: localhost-relay-bin.000005Relay_Log_Pos: 4Relay_Master_Log_File: mysql-bin.000003Slave_IO_Running: NoSlave_SQL_Running: Yes.....
    

    可以看到,Slave_SQL_Running依然是Yes,只有Slave_IO_RunningNO,所以只需要重启slave的IO线程即可

    start slave io_thread user='repl' password = 'your password';
    

    启动完成后,基于logfile:pos模式的半同步复制也就配置完成。

GTID复制

由于上面的实验,我们已经启动了logfile + pos方式的复制链路,所以要改成GTID方式,先要停止slave,再重新配置复制链路

  • 停止slave
    slave节点上执行如下命令

    stop slave;
    
  • 配置复制链路
    change master to master_host='192.168.1.101', master_user='repl', master_password='your password', master_auto_position=1;
    
  • 启动复制链路
    start slave;
    

查看链路状态

show slave status \G;
*************************** 1. row ***************************Slave_IO_State: Waiting for master to send eventMaster_Host: 192.168.1.101Master_User: replMaster_Port: 3306Connect_Retry: 60Master_Log_File: mysql-bin.000003Read_Master_Log_Pos: 811Relay_Log_File: localhost-relay-bin.000002Relay_Log_Pos: 414Relay_Master_Log_File: mysql-bin.000003Slave_IO_Running: YesSlave_SQL_Running: Yes......Master_SSL_Crl:Master_SSL_Crlpath:Retrieved_Gtid_Set:Executed_Gtid_Set: 1dbd5375-a4d9-11ea-9eef-000c29cf4cca:1,
81502f9e-a592-11ea-b912-000c2928707c:1-11Auto_Position: 1......

可以看到Auto_Position变成了1,说明启动了基于GTID方式的复制。

主从复制延迟

主从复制是一种异步复制模型,延迟自然是不可避免。只要延迟在业务能够接受的范围之内,都是可以容忍的。但是有时候主从复制的延迟会很大,可以总结为以下原因

  • master上执行了大事务,大事务是指耗时很长的事务。改进办法是把大事务转换成多个小事务
  • masterslave之间网络波动
  • 单个master节点下挂载的slave节点过多,可能会把master网卡带宽打满。改进办法就是减少单个master挂载slave的数量
  • master节点会有多个线程同时写入,而slave节点进行replaysql_thread只有一个。改进办法就是使用MySQL 5.7的多线程复制的方式、或者使用MGR复制架构。

总结

本篇主要从理论到实践,完整的讲解了MySQL的几种主从模型。根据复制点的选取方式,可以分成基于日志点的方式和基于GTID的方式。根据master节点事务的提交方式可以分成异步复制半同步复制

至于文中提到的MMMMHA架构,留待下一篇再详细讲解。

参考

  • https://www.cnblogs.com/bigbrotherer/p/7241845.html
  • https://blog.51cto.com/13434336/2178937

摆摊也要抽时间学的MySQL主从复制相关推荐

  1. 学一点 mysql 双机异地热备份----快速理解mysql主从,主主备份原理及实践

    学一点 mysql 双机异地热备份----快速理解mysql主从,主主备份原理及实践 原文 学一点 mysql 双机异地热备份----快速理解mysql主从,主主备份原理及实践 感谢大家在上一篇 学一 ...

  2. 重学数据库MySQL

    重学MySql 第一次草率的学的学完了MySql之后,学会了基本的增删改查,但是其中的事务.索引.视图.存储引擎和SQL优化还是不是特别明白,今天再一次学习数据库. #insert 插入操作 INSE ...

  3. 向mysql中插入时间_Java向mysql中插入时间的方法

    ava向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明);部分资料参考网络资源 java向MySQL插入当前时间的四种方式 第一种:将java.util.Date类型的时 ...

  4. mysql xp系统时间_【MySQL】时间函数

    获取当前日期时间函数 now() 获得当前日期+时间(date + time) mysql> select now(); +---------------------+ | now() | +- ...

  5. MySQL主从复制我学废了

    MySQL主从复制 数据库 主从复制 如何实现主从复制 主从延迟怎么产生的? 主从延迟怎么处理 数据库持久化的两种实现方式 MySQL持久化方式 Redis持久化方式 线程和进程区别 mysql存在几 ...

  6. 新概念每天学多少合适? 新概念学习方法汇总?上班族该如何分配时间学新概念?

    新概念每天学多少合适 每天不要过多的记忆,有5-6句话足以,多了什么也记不住.科学的说法是一天记忆8句话,我们还是不要那么标准了,少点好.最好能把学到的组成简单的对话,这样一问一答自己都可以练习口语了 ...

  7. 为什么要抽时间读书?为什么要写读书笔记?

    为什么要抽时间读书?     读书太重要了.     尤其作为一个理工科的学生,一定要加强自己的文学修养.一方面可调剂单调的生活,另一方面文理结合,相得益彰.     读书的裨益不在一朝一夕,而在长期 ...

  8. java计算机毕业设计时间管理系统源程序+mysql+系统+lw文档+远程调试

    java计算机毕业设计时间管理系统源程序+mysql+系统+lw文档+远程调试 java计算机毕业设计时间管理系统源程序+mysql+系统+lw文档+远程调试 本源码技术栈: 项目架构:B/S架构 开 ...

  9. mysql版本 时间_【MySQL】MySQL版本时间线和MySQL各版本的区别

    MySQL各版本的区别 https://yq.aliyun.com/articles/607474 http://blog.sina.com.cn/s/blog_62b37bfe0101he5t.ht ...

最新文章

  1. c++引用的自我见解
  2. linux设置数据库定时备份,linux中使用计划任务进行数据库定期备份
  3. Java 动态代理机制分析及扩展
  4. QML和C++混合编程--(三)
  5. 联想服务器开启虚拟化,联想电脑虚拟化开启方法
  6. 修改weblogic端口的方法
  7. OpenCV学习笔记(四):XML,YAML(.txt,.doc)文件读写操作
  8. java垃圾回收理解与算法
  9. 为什么需要学习编程?
  10. 生活杂谈-空调的修理
  11. 手动解除浏览器跨域限制
  12. Python爬虫基础:验证码概述及打码平台
  13. 记录Win10因为管理员权限而出现的访问COM口被占用的问题
  14. 计算机软件硬件结构造图,个人计算机的存储器系统 说说内核与计算机硬件结构(3)...
  15. 社会上大多数人,都有同一种根深蒂固的思维习惯,而成功的人只是社会少数人。
  16. js jQuery方法join()
  17. 【Conic】最优性条件与对偶(1)
  18. 计算机桌面图标快捷键,windows7打开计算机的快捷键是什么
  19. word分散对齐调整宽度_Word文档如何让不同字数对齐
  20. hdu5594 ZYB's Prime

热门文章

  1. 阿里等大厂的需求研发/开发流程,进去前了解一下
  2. 相比幸存女孩,动车没有停运才是奇迹
  3. 扫地机器人 基于stm32f103ze扫地机器人程序
  4. 什么对象都有prototype吗?
  5. asp.net core MVC程序通过AJAX上传文件报“400 Bad Request”
  6. 软件测试 保险公司人寿保险保费计算程序的等价类
  7. SHELL脚本--expr命令全解
  8. 2、AD新建项目及编辑界面介绍
  9. 技术干货 | 一文读懂GPU显卡10个重要参数
  10. Deepin 微信经常出现假死问题解决办法。