learn.lianglianglee.com/文章/MySQL 主从复制 基于GTID复制.md.html
2022-05-11 19:04:14 +08:00

1006 lines
56 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>MySQL 主从复制 基于GTID复制.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/文章/AQS 万字图文全面解析.md.html">AQS 万字图文全面解析.md.html</a>
</li>
<li>
<a href="/文章/Docker 镜像构建原理及源码分析.md.html">Docker 镜像构建原理及源码分析.md.html</a>
</li>
<li>
<a href="/文章/ElasticSearch 小白从入门到精通.md.html">ElasticSearch 小白从入门到精通.md.html</a>
</li>
<li>
<a href="/文章/JVM CPU Profiler技术原理及源码深度解析.md.html">JVM CPU Profiler技术原理及源码深度解析.md.html</a>
</li>
<li>
<a href="/文章/JVM 垃圾收集器.md.html">JVM 垃圾收集器.md.html</a>
</li>
<li>
<a href="/文章/JVM 面试的 30 个知识点.md.html">JVM 面试的 30 个知识点.md.html</a>
</li>
<li>
<a href="/文章/Java IO 体系、线程模型大总结.md.html">Java IO 体系、线程模型大总结.md.html</a>
</li>
<li>
<a href="/文章/Java NIO浅析.md.html">Java NIO浅析.md.html</a>
</li>
<li>
<a href="/文章/Java 面试题集锦(网络篇).md.html">Java 面试题集锦(网络篇).md.html</a>
</li>
<li>
<a href="/文章/Java-直接内存 DirectMemory 详解.md.html">Java-直接内存 DirectMemory 详解.md.html</a>
</li>
<li>
<a href="/文章/Java中9种常见的CMS GC问题分析与解决.md.html">Java中9种常见的CMS GC问题分析与解决.md.html</a>
</li>
<li>
<a href="/文章/Java中9种常见的CMS GC问题分析与解决.md.html">Java中9种常见的CMS GC问题分析与解决.md.html</a>
</li>
<li>
<a href="/文章/Java中的SPI.md.html">Java中的SPI.md.html</a>
</li>
<li>
<a href="/文章/Java中的ThreadLocal.md.html">Java中的ThreadLocal.md.html</a>
</li>
<li>
<a href="/文章/Java线程池实现原理及其在美团业务中的实践.md.html">Java线程池实现原理及其在美团业务中的实践.md.html</a>
</li>
<li>
<a href="/文章/Java魔法类Unsafe应用解析.md.html">Java魔法类Unsafe应用解析.md.html</a>
</li>
<li>
<a href="/文章/Kafka 源码阅读笔记.md.html">Kafka 源码阅读笔记.md.html</a>
</li>
<li>
<a href="/文章/Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理.md.html">Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB Buffer Pool.md.html">MySQL · 引擎特性 · InnoDB Buffer Pool.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB IO子系统.md.html">MySQL · 引擎特性 · InnoDB IO子系统.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 事务系统.md.html">MySQL · 引擎特性 · InnoDB 事务系统.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 同步机制.md.html">MySQL · 引擎特性 · InnoDB 同步机制.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 数据页解析.md.html">MySQL · 引擎特性 · InnoDB 数据页解析.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB崩溃恢复.md.html">MySQL · 引擎特性 · InnoDB崩溃恢复.md.html</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · 临时表那些事儿.md.html">MySQL · 引擎特性 · 临时表那些事儿.md.html</a>
</li>
<li>
<a href="/文章/MySQL 主从复制 半同步复制.md.html">MySQL 主从复制 半同步复制.md.html</a>
</li>
<li>
<a class="current-tab" href="/文章/MySQL 主从复制 基于GTID复制.md.html">MySQL 主从复制 基于GTID复制.md.html</a>
</li>
<li>
<a href="/文章/MySQL 主从复制.md.html">MySQL 主从复制.md.html</a>
</li>
<li>
<a href="/文章/MySQL 事务日志(redo log和undo log).md.html">MySQL 事务日志(redo log和undo log).md.html</a>
</li>
<li>
<a href="/文章/MySQL 亿级别数据迁移实战代码分享.md.html">MySQL 亿级别数据迁移实战代码分享.md.html</a>
</li>
<li>
<a href="/文章/MySQL 从一条数据说起-InnoDB行存储数据结构.md.html">MySQL 从一条数据说起-InnoDB行存储数据结构.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:事务和锁的面纱.md.html">MySQL 地基基础:事务和锁的面纱.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:数据字典.md.html">MySQL 地基基础:数据字典.md.html</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:数据库字符集.md.html">MySQL 地基基础:数据库字符集.md.html</a>
</li>
<li>
<a href="/文章/MySQL 性能优化:碎片整理.md.html">MySQL 性能优化:碎片整理.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:一个 ALTER TALBE 执行了很久,你慌不慌?.md.html">MySQL 故障诊断:一个 ALTER TALBE 执行了很久,你慌不慌?.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:如何在日志中轻松定位大事务.md.html">MySQL 故障诊断:如何在日志中轻松定位大事务.md.html</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:教你快速定位加锁的 SQL.md.html">MySQL 故障诊断:教你快速定位加锁的 SQL.md.html</a>
</li>
<li>
<a href="/文章/MySQL 日志详解.md.html">MySQL 日志详解.md.html</a>
</li>
<li>
<a href="/文章/MySQL 的半同步是什么?.md.html">MySQL 的半同步是什么?.md.html</a>
</li>
<li>
<a href="/文章/MySQL中的事务和MVCC.md.html">MySQL中的事务和MVCC.md.html</a>
</li>
<li>
<a href="/文章/MySQL事务_事务隔离级别详解.md.html">MySQL事务_事务隔离级别详解.md.html</a>
</li>
<li>
<a href="/文章/MySQL优化优化 select count().md.html">MySQL优化优化 select count().md.html</a>
</li>
<li>
<a href="/文章/MySQL共享锁、排他锁、悲观锁、乐观锁.md.html">MySQL共享锁、排他锁、悲观锁、乐观锁.md.html</a>
</li>
<li>
<a href="/文章/MySQL的MVCC多版本并发控制.md.html">MySQL的MVCC多版本并发控制.md.html</a>
</li>
<li>
<a href="/文章/QingStor 对象存储架构设计及最佳实践.md.html">QingStor 对象存储架构设计及最佳实践.md.html</a>
</li>
<li>
<a href="/文章/RocketMQ 面试题集锦.md.html">RocketMQ 面试题集锦.md.html</a>
</li>
<li>
<a href="/文章/SnowFlake 雪花算法生成分布式 ID.md.html">SnowFlake 雪花算法生成分布式 ID.md.html</a>
</li>
<li>
<a href="/文章/Spring Boot 2.x 结合 k8s 实现分布式微服务架构.md.html">Spring Boot 2.x 结合 k8s 实现分布式微服务架构.md.html</a>
</li>
<li>
<a href="/文章/Spring Boot 教程:如何开发一个 starter.md.html">Spring Boot 教程:如何开发一个 starter.md.html</a>
</li>
<li>
<a href="/文章/Spring MVC 原理.md.html">Spring MVC 原理.md.html</a>
</li>
<li>
<a href="/文章/Spring MyBatis和Spring整合的奥秘.md.html">Spring MyBatis和Spring整合的奥秘.md.html</a>
</li>
<li>
<a href="/文章/Spring 帮助你更好的理解Spring循环依赖.md.html">Spring 帮助你更好的理解Spring循环依赖.md.html</a>
</li>
<li>
<a href="/文章/Spring 循环依赖及解决方式.md.html">Spring 循环依赖及解决方式.md.html</a>
</li>
<li>
<a href="/文章/Spring中眼花缭乱的BeanDefinition.md.html">Spring中眼花缭乱的BeanDefinition.md.html</a>
</li>
<li>
<a href="/文章/Vert.x 基础入门.md.html">Vert.x 基础入门.md.html</a>
</li>
<li>
<a href="/文章/eBay 的 Elasticsearch 性能调优实践.md.html">eBay 的 Elasticsearch 性能调优实践.md.html</a>
</li>
<li>
<a href="/文章/不可不说的Java“锁”事.md.html">不可不说的Java“锁”事.md.html</a>
</li>
<li>
<a href="/文章/互联网并发限流实战.md.html">互联网并发限流实战.md.html</a>
</li>
<li>
<a href="/文章/从ReentrantLock的实现看AQS的原理及应用.md.html">从ReentrantLock的实现看AQS的原理及应用.md.html</a>
</li>
<li>
<a href="/文章/从SpringCloud开始聊微服务架构.md.html">从SpringCloud开始聊微服务架构.md.html</a>
</li>
<li>
<a href="/文章/全面了解 JDK 线程池实现原理.md.html">全面了解 JDK 线程池实现原理.md.html</a>
</li>
<li>
<a href="/文章/分布式一致性理论与算法.md.html">分布式一致性理论与算法.md.html</a>
</li>
<li>
<a href="/文章/分布式一致性算法 Raft.md.html">分布式一致性算法 Raft.md.html</a>
</li>
<li>
<a href="/文章/分布式唯一 ID 解析.md.html">分布式唯一 ID 解析.md.html</a>
</li>
<li>
<a href="/文章/分布式链路追踪:集群管理设计.md.html">分布式链路追踪:集群管理设计.md.html</a>
</li>
<li>
<a href="/文章/动态代理种类及原理,你知道多少?.md.html">动态代理种类及原理,你知道多少?.md.html</a>
</li>
<li>
<a href="/文章/响应式架构与 RxJava 在有赞零售的实践.md.html">响应式架构与 RxJava 在有赞零售的实践.md.html</a>
</li>
<li>
<a href="/文章/大数据算法——布隆过滤器.md.html">大数据算法——布隆过滤器.md.html</a>
</li>
<li>
<a href="/文章/如何优雅地记录操作日志?.md.html">如何优雅地记录操作日志?.md.html</a>
</li>
<li>
<a href="/文章/如何设计一个亿级消息量的 IM 系统.md.html">如何设计一个亿级消息量的 IM 系统.md.html</a>
</li>
<li>
<a href="/文章/异步网络模型.md.html">异步网络模型.md.html</a>
</li>
<li>
<a href="/文章/当我们在讨论CQRS时我们在讨论些神马.md.html">当我们在讨论CQRS时我们在讨论些神马.md.html</a>
</li>
<li>
<a href="/文章/彻底理解 MySQL 的索引机制.md.html">彻底理解 MySQL 的索引机制.md.html</a>
</li>
<li>
<a href="/文章/最全的 116 道 Redis 面试题解答.md.html">最全的 116 道 Redis 面试题解答.md.html</a>
</li>
<li>
<a href="/文章/有赞权限系统(SAM).md.html">有赞权限系统(SAM).md.html</a>
</li>
<li>
<a href="/文章/有赞零售中台建设方法的探索与实践.md.html">有赞零售中台建设方法的探索与实践.md.html</a>
</li>
<li>
<a href="/文章/服务注册与发现原理剖析Eureka、Zookeeper、Nacos.md.html">服务注册与发现原理剖析Eureka、Zookeeper、Nacos.md.html</a>
</li>
<li>
<a href="/文章/深入浅出Cache.md.html">深入浅出Cache.md.html</a>
</li>
<li>
<a href="/文章/深入理解 MySQL 底层实现.md.html">深入理解 MySQL 底层实现.md.html</a>
</li>
<li>
<a href="/文章/漫画讲解 git rebase VS git merge.md.html">漫画讲解 git rebase VS git merge.md.html</a>
</li>
<li>
<a href="/文章/生成浏览器唯一稳定 ID 的探索.md.html">生成浏览器唯一稳定 ID 的探索.md.html</a>
</li>
<li>
<a href="/文章/缓存 如何保证缓存与数据库的双写一致性?.md.html">缓存 如何保证缓存与数据库的双写一致性?.md.html</a>
</li>
<li>
<a href="/文章/网易严选怎么做全链路监控的?.md.html">网易严选怎么做全链路监控的?.md.html</a>
</li>
<li>
<a href="/文章/美团万亿级 KV 存储架构与实践.md.html">美团万亿级 KV 存储架构与实践.md.html</a>
</li>
<li>
<a href="/文章/美团点评Kubernetes集群管理实践.md.html">美团点评Kubernetes集群管理实践.md.html</a>
</li>
<li>
<a href="/文章/美团百亿规模API网关服务Shepherd的设计与实现.md.html">美团百亿规模API网关服务Shepherd的设计与实现.md.html</a>
</li>
<li>
<a href="/文章/解读《阿里巴巴 Java 开发手册》背后的思考.md.html">解读《阿里巴巴 Java 开发手册》背后的思考.md.html</a>
</li>
<li>
<a href="/文章/认识 MySQL 和 Redis 的数据一致性问题.md.html">认识 MySQL 和 Redis 的数据一致性问题.md.html</a>
</li>
<li>
<a href="/文章/进阶Dockerfile 高阶使用指南及镜像优化.md.html">进阶Dockerfile 高阶使用指南及镜像优化.md.html</a>
</li>
<li>
<a href="/文章/铁总在用的高性能分布式缓存计算框架 Geode.md.html">铁总在用的高性能分布式缓存计算框架 Geode.md.html</a>
</li>
<li>
<a href="/文章/阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html">阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html</a>
</li>
<li>
<a href="/文章/阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html">阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html</a>
</li>
<li>
<a href="/文章/面试最常被问的 Java 后端题.md.html">面试最常被问的 Java 后端题.md.html</a>
</li>
<li>
<a href="/文章/领域驱动设计在互联网业务开发中的实践.md.html">领域驱动设计在互联网业务开发中的实践.md.html</a>
</li>
<li>
<a href="/文章/领域驱动设计的菱形对称架构.md.html">领域驱动设计的菱形对称架构.md.html</a>
</li>
<li>
<a href="/文章/高效构建 Docker 镜像的最佳实践.md.html">高效构建 Docker 镜像的最佳实践.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>MySQL 主从复制 基于GTID复制</h1>
<p>相比传统的MySQL复制gtid复制无论是配置还是维护都要轻松的多。本文对gtid复制稍作介绍。</p>
<p>MySQL基于GTID复制官方手册<a href="https://dev.mysql.com/doc/refman/5.7/en/replication-gtids.html">https://dev.mysql.com/doc/refman/5.7/en/replication-gtids.html</a></p>
<h1>1.gtid基本概念</h1>
<p>传统的基于binlog position复制的方式有个严重的缺点如果slave连接master时指定的binlog文件错误或者position错误会造成遗漏或者重复很多时候前后数据是有依赖性的这样就会出错而导致数据不一致。</p>
<p>从MYSQL5.6开始mysql开始支持GTID复制。GTID的全称是global transaction id表示的是全局事务ID。GTID的分配方式为<code>uuid:trans_id</code>,其中:</p>
<ul>
<li><code>uuid</code>是每个mysql服务器都唯一的记录在<code>$datadir/auto.cnf</code>中。如果复制结构中任意两台服务器uuid重复的话(比如直接冷备份时auto.conf中的内容是一致的)在启动复制功能的时候会报错。这时可以删除auto.conf文件再重启mysqld。</li>
</ul>
<pre><code>mysql&gt; show variables like &quot;%uuid%&quot;;
+---------------+--------------------------------------+
| Variable_name | Value |
+---------------+--------------------------------------+
| server_uuid | a126fcb6-3706-11e8-b1d5-000c294ebf0d |
+---------------+--------------------------------------+
1 row in set (0.00 sec)
 
mysql&gt; \! cat /data/auto.cnf
[auto]
server-uuid=a126fcb6-3706-11e8-b1d5-000c294ebf0d
</code></pre>
<ul>
<li><code>trans_id</code>是事务ID可以唯一标记某MySQL服务器上执行的某个事务。事务号从1开始每提交一个事务事务号加1。</li>
</ul>
<p>例如&quot;gtid_executed 5ad9cb8e-2092-11e7-ac95-000c29bf823d:1-6&quot;表示该server_uuid上执行了从1到6的事务。</p>
<h1>2.gtid的生命周期</h1>
<p><strong>gtid的生命周期对于配置和维护基于gtid的复制至关重要</strong>。所以,请尽可能理解以下几个过程。</p>
<p>gtid在master和slave上是一直<strong>持久化保存</strong>(即使删除了日志也会记录到Previous_GTID中)的。它在master和slave上的生命周期如下</p>
<ol>
<li>
<p>客户端发送DDL/DML给master上master首先对此事务生成一个唯一的gtid假如为<code>uuid_xxx:1</code>,然后立即执行该事务中的操作。</p>
<p>注意主从复制的情况下sync-binlog基本上都会设置为1这表示在每次提交事务时将缓存中的binlog刷盘。所以在事务提交前gtid以及事务相关操作的信息都在缓存中提交后它们才写入到binlog file中然后才会被dump线程dump出去。</p>
<p>换句话说,<strong>只有提交了的事务gtid和对应的事务操作才会记录到binlog文件中。记录的格式是先记录gtid紧跟着再记录事务相关的操作。</strong></p>
</li>
<li>
<p>当binlog传送到relay log中后slave上的SQL线程首先读取该gtid并设置变量 <em>gtid_next</em> 的值为该gtid表示下一个要操作的事务是该gtid。 <em>gtid_next</em> <strong>是基于会话的不同会话的gtid_next不同。</strong></p>
</li>
<li>
<p>随后slave检测该gtid在自己的binlog中是否存在。如果存在则放弃此gtid事务如果不存在则将此gtid写入到<strong>自己的binlog中</strong>然后立刻执行该事务并在自己的binlog中记录该事务相关的操作。</p>
<p>注意,<strong>slave上replay的时候gtid不是提交后才写到自己的binlog file的而是判断gtid不存在后立即写入binlog file。</strong></p>
<p>通过这种在执行事务前先检查并写gtid到binlog的机制不仅可以保证当前会话在此之前没有执行过该事务还能保证没有其他会话读取了该gtid却没有提交。因为如果其他会话读取了该gtid会立即写入到binlog(不管是否已经开始执行事务)所以当前会话总能读取到binlog中的该gtid于是当前会话就会放弃该事务。总之一个gtid事务是决不允许多次执行、多个会话并行执行的。</p>
</li>
<li>
<p>slave在重放relay log中的事务时不会自己生成gtid所以所有的slave(无论是何种方式的一主一从或一主多从复制架构)通过重放relay log中事务获取的gtid都来源于master并永久保存在slave上。</p>
</li>
</ol>
<h1>3.基于gtid复制的好处</h1>
<p>从上面可以看出gtid复制的优点大致有</p>
<ol>
<li><strong>保证同一个事务在某slave上绝对只执行一次没有执行过的gtid事务总是会被执行。</strong></li>
<li><strong>不用像传统复制那样保证binlog的坐标准确因为根本不需要binlog以及坐标。</strong></li>
<li><strong>故障转移到新的master的时候很方便简化了很多任务。</strong></li>
<li><strong>很容易判断master和slave的数据是否一致。只要master上提交的事务在slave上也提交了那么一定是一致的。</strong></li>
</ol>
<p>当然MySQL提供了选项可以控制跳过某些gtid事务防止slave第一次启动复制时执行master上的所有事务而导致耗时过久。</p>
<p>虽然对于row-based和statement-based的格式都能进行gtid复制但建议采用row-based格式。</p>
<h1>4.配置一主一从的gtid复制</h1>
<p>环境:</p>
<table>
<thead>
<tr>
<th align="center">主机IP</th>
<th align="center">OS版本</th>
<th align="center">MySQL版本</th>
<th align="center">角色(master/slave)</th>
<th align="center">数据状态</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">192.168.100.21</td>
<td align="center">centos 7</td>
<td align="center">MySQL 5.7.22</td>
<td align="center">master_gtid</td>
<td align="center">全新实例</td>
</tr>
<tr>
<td align="center">192.168.100.22</td>
<td align="center">centos 7</td>
<td align="center">MySQL 5.7.22</td>
<td align="center">slave1_gtid</td>
<td align="center">全新实例</td>
</tr>
</tbody>
</table>
<p>因为是用作master和slave的mysql实例都是全新环境所以这里简单配置一下即可。</p>
<p>master的配置文件</p>
<pre><code>[mysqld]
datadir=/data
socket=/data/mysql.sock
log-bin=/data/master-bin # 必须项
sync-binlog=1 # 建议项
binlog_format=row # 建议项
server-id=100 # 必须项
log-error=/data/error.log
pid-file=/data/mysqld.pid
enforce_gtid_consistency=on # gtid复制需要加上的必须项
gtid_mode=on # gtid复制需要加上的必须项
</code></pre>
<p>关于后面的两项是gtid复制所必须开启的项这里指定它开启就行了它们的意义以及更多gtid相关的选项见后文解释。</p>
<p>slave的配置文件</p>
<pre><code>[mysqld]
datadir=/data
socket=/data/mysql.sock
log-bin=/data/master-slave-bin # mysql 5.6必须项mysql 5.7非必须项
sync-binlog=1 # 建议项
binlog_format=row # 建议项
relay-log=/data/slave-bin # 必须项
server-id=110 # 必须项
log-error=/data/error.log
pid-file=/data/mysqld.pid
enforce_gtid_consistency=on # 必须项
gtid_mode=on # 必须项
</code></pre>
<p>我的环境是mysql 5.7如果是mysql 5.6,那么在上面两个配置文件中需要加上<code>log-slave-updates</code>选项。</p>
<p>重启master和slave后在master上创建一个用于复制的用户<code>repl</code></p>
<pre><code class="language-mysql"># master上执行
mysql&gt; grant replication slave on *.* to <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8dffe8fde1cd">[email&#160;protected]</a>'192.168.100.%' identified by '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7a2a3a09090d15081e4b">[email&#160;protected]</a>!';
</code></pre>
<p>因为master上的binlog没有删除过所以在slave上直接<code>change master to</code>配置连接参数。</p>
<pre><code class="language-mysql"># slave上执行
mysql&gt; change master to
master_host='192.168.100.21',
master_port=3306,
master_auto_position=1; # gtid复制必须设置此项
</code></pre>
<p>因为是MySQL 5.7,没有在<code>change master to</code>语句中加入user和password项而是在<code>start slave</code>语句中使用,否则会警告。</p>
<p>现在启动slave上的两个复制线程。</p>
<pre><code class="language-mysql"># slave上执行
mysql&gt; start slave user='repl' password='<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9cccdcefefebf3eef8ad">[email&#160;protected]</a>!';
</code></pre>
<p>查看io线程和sql线程是否正常。</p>
<pre><code># slave上执行为了排版缩减了一些无关紧要的字段
mysql&gt; show processlist;
+----+-------------+---------+--------------------------------------------------------+
| Id | User | Command | State |
+----+-------------+---------+--------------------------------------------------------+
| 9 | root | Query | starting |
| 10 | system user | Connect | Waiting for master to send event |
| 11 | system user | Connect | Slave has read all relay log; waiting for more updates |
+----+-------------+---------+--------------------------------------------------------+
</code></pre>
<p>最后验证gtid复制是否生效。</p>
<p>在master上插入一些数据。这里使用<a href="https://www.cnblogs.com/f-ck-need-u/p/9155003.html">上一篇文章</a>中使用的存储过程<code>proc_num1</code><code>proc_num2</code>分别向数值辅助表<code>backup.num_isam</code><code>backup.num_innodb</code>中插入一些数据,该存储过程的代码见:<a href="https://www.cnblogs.com/f-ck-need-u/p/9155003.html#blognum。">https://www.cnblogs.com/f-ck-need-u/p/9155003.html#blognum。</a></p>
<pre><code># 向MyISAM数值辅助表backup.num_isam插入100W行数据
call proc_num1(1000000);
# 向InnoDB数值辅助表backup.num_innodb插入100W行数据
call proc_num2(1000000);
</code></pre>
<p>在slave上查看slave的状态以下是同步结束后的状态信息。</p>
<pre><code># slave上执行
mysql&gt; show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.100.21
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000004
Read_Master_Log_Pos: 10057867
Relay_Log_File: slave-bin.000003
Relay_Log_Pos: 457
Relay_Master_Log_File: master-bin.000004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 10057867
Relay_Log_Space: 10058586
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 100
Master_UUID: a659234f-6aea-11e8-a361-000c29ed4cf4
Master_Info_File: /data/master.info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: a659234f-6aea-11e8-a361-000c29ed4cf4:1-54
Executed_Gtid_Set: a659234f-6aea-11e8-a361-000c29ed4cf4:1-54
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
</code></pre>
<h1>5.添加新的slave到gtid复制结构中</h1>
<p>GTID复制是基于事务ID的确切地说是binlog中的GTID所以事务ID对GTID复制来说是命脉。</p>
<p>当master没有删除过任何binlog时可以随意地向复制结构中添加新的slave因为slave会复制所有的binlog到自己relay log中并replay。这样的操作尽管可能速度不佳但胜在操作极其简便。</p>
<p>当master删除过一部分binlog后在向复制结构中添加新的slave时必须先获取到master binlog中当前已记录的第一个gtid之前的所有数据然后恢复到slave上。只有slave上具有了这部分基准数据才能保证和master的数据一致性。</p>
<p>而在实际环境中往往会定期删除一部分binlog。所以为了配置更通用的gtid复制环境这里把前文的master的binlog给purge掉一部分。</p>
<p>目前master上的binlog使用情况如下不难发现绝大多数操作都集中在<code>master-bin.000004</code>这个binlog中。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1f6d70706b5f676a7a6776">[email&#160;protected]</a> ~]# ls -l /data/*bin*
-rw-r----- 1 mysql mysql 177 Jun 8 15:07 /data/master-bin.000001
-rw-r----- 1 mysql mysql 727 Jun 8 15:42 /data/master-bin.000002
-rw-r----- 1 mysql mysql 177 Jun 9 09:50 /data/master-bin.000003
-rw-r----- 1 mysql mysql 10057867 Jun 9 10:17 /data/master-bin.000004
-rw-r----- 1 mysql mysql 96 Jun 9 09:50 /data/master-bin.index
</code></pre>
<p>purge已有的binlog。</p>
<pre><code>
mysql&gt; flush logs;
mysql&gt; purge master logs to 'master-bin.000005';
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="82f0ededf6c2faf7e7faeb">[email&#160;protected]</a> ~]# cat /data/master-bin.index
/data/master-bin.000005
</code></pre>
<p>但无论master是否purge过binlog配置基于gtid的复制都极其方便而且方法众多(只要理解了GTID的生命周期可以随意折腾基本上都能很轻松地维护好),这是它&quot;迷人&quot;的优点。</p>
<p>现在的测试环境是这样的:</p>
<table>
<thead>
<tr>
<th align="center">主机IP</th>
<th align="center">OS版本</th>
<th align="center">MySQL版本</th>
<th align="center">角色(master/slave)</th>
<th align="center">数据状态</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">192.168.100.21</td>
<td align="center">centos 7</td>
<td align="center">MySQL 5.7.22</td>
<td align="center">master_gtid</td>
<td align="center">已purge过binlog</td>
</tr>
<tr>
<td align="center">192.168.100.22</td>
<td align="center">centos 7</td>
<td align="center">MySQL 5.7.22</td>
<td align="center">slave1_gtid</td>
<td align="center">已同步</td>
</tr>
<tr>
<td align="center">192.168.100.23</td>
<td align="center">centos 7</td>
<td align="center">MySQL 5.7.22</td>
<td align="center">slave2_gtid</td>
<td align="center">全新实例</td>
</tr>
</tbody>
</table>
<p>其中slave2的配置文件和slave1的配置文件完全相同</p>
<pre><code>[mysqld]
datadir=/data
socket=/data/mysql.sock
log-bin=/data/master-slave-bin # 必须项
sync-binlog=1 # 建议项
binlog_format=row # 建议项
relay-log=/data/slave-bin # 必须项
server-id=110 # 必须项
log-error=/data/error.log
pid-file=/data/mysqld.pid
enforce_gtid_consistency=on # 必须项
gtid_mode=on # 必须项
</code></pre>
<p><strong>1.备份master。</strong></p>
<p>我选择的是xtrabackup的innobackupex工具因为它速度快操作简单而且在线备份也比较安全。如果不知道xtrabackup备份的使用方法见我的另一篇文章<a href="https://www.cnblogs.com/f-ck-need-u/p/9018716.html">xtrabackup用法和原理详述</a>。当然你也可以采用mysqldump和冷备份的方式因为gtid复制的特性这些备份方式也都很安全。</p>
<pre><code># master上执行备份所有数据
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="03716c6c77437b76667b6a">[email&#160;protected]</a> ~]# mkdir /backdir # 备份目录
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7b0914140f3b030e1e0312">[email&#160;protected]</a> ~]# innobackupex -uroot <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6d401d3d2d1e1e1a021f095c">[email&#160;protected]</a>! -S /data/mysql.sock /backdir/ # 准备数据
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="54263b3b20142c21312c3d">[email&#160;protected]</a> ~]# innobackupex --apply-log /backdir/2018-06-09_20-02-24/ # 应用数据
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2e5c41415a6e565b4b5647">[email&#160;protected]</a> ~]# scp -pr /backdir/2018-06-09_20-02-24/ 192.168.100.23:/tmp
</code></pre>
<p><strong>2.将备份恢复到slave2。</strong></p>
<p>在slave2上执行</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a2d0cdcdd6e2dad7c7dacb">[email&#160;protected]</a> ~]# systemctl stop mysqld
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="33415c5c47734b46564b5a">[email&#160;protected]</a> ~]# rm -rf /data/* # 恢复前必须先清空数据目录
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="35475a5a41754d40504d5c">[email&#160;protected]</a> ~]# innobackupex --copy-back /tmp/2018-06-09_20-02-24/ # 恢复备份数据
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="92e0fdfde6d2eae7f7eafb">[email&#160;protected]</a> ~]# chown -R mysql.mysql /data
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="35475a5a41754d40504d5c">[email&#160;protected]</a> ~]# systemctl start mysqld
</code></pre>
<p><strong>3.设置gtid_purged连接master开启复制功能。</strong></p>
<p>由于xtrabackup备份数据集却不备份binlog所以必须先获取此次备份结束时的最后一个事务ID并在slave上明确指定跳过这些事务否则slave会再次从master上复制这些binlog并执行导致数据重复执行。</p>
<p>可以从slave2数据目录中的<code>xtrabackup_info</code>文件中获取。如果不是xtrabackup备份的那么可以直接从master的<code>show global variables like &quot;gtid_executed&quot;;</code>中获取它表示master中已执行过的事务。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d9abb6b6ad99a1acbca1b0">[email&#160;protected]</a> ~]# cat /data/xtrabackup_info
uuid = fc3de8c1-6bdc-11e8-832d-000c29ed4cf4
name =
tool_name = innobackupex
tool_command = -uroot <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d4f9a48494a7a7a3bba6b0e5">[email&#160;protected]</a>! -S /data/mysql.sock /backdir/
tool_version = 2.4.11
ibbackup_version = 2.4.11
server_version = 5.7.22-log
start_time = 2018-06-09 20:02:28
end_time = 2018-06-09 20:02:30
lock_time = 0
binlog_pos = filename 'master-bin.000005', position '194', GTID of the last change 'a659234f-6aea-11e8-a361-000c29ed4cf4:1-54'
innodb_from_lsn = 0
innodb_to_lsn = 51235233
partial = N
incremental = N
format = file
compact = N
compressed = N
encrypted = N
</code></pre>
<p>其中<code>binlog_pos</code>中的GTID对应的就是已备份的数据对应的事务。换句话说这里的gtid集合1-54表示这54个事务不需要进行复制。</p>
<p>或者在master上直接查看executed的值注意不是gtid_purged的值master上的gtid_purged表示的是曾经删除掉的binlog。</p>
<pre><code>mysql&gt; show global variables like '%gtid%';
+----------------------------------+-------------------------------------------+
| Variable_name | Value |
+----------------------------------+-------------------------------------------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed | a659234f-6aea-11e8-a361-000c29ed4cf4:1-54 |
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | a659234f-6aea-11e8-a361-000c29ed4cf4:1-54 |
| session_track_gtids | OFF |
+----------------------------------+-------------------------------------------+
</code></pre>
<p>可以**在启动slave线程之前使用gtid_purged变量来指定需要跳过的gtid集合。**但因为要设置gtid_purged必须保证全局变量gtid_executed为空所以先在slave上执行<code>reset master</code>(注意不是reset slave)再设置gtid_purged。</p>
<pre><code># slave2上执行
mysql&gt; reset master;
mysql&gt; set @@global.gtid_purged='a659234f-6aea-11e8-a361-000c29ed4cf4:1-54';
</code></pre>
<p>设置好gtid_purged之后就可以开启复制线程了。</p>
<pre><code>mysql&gt; change master to
master_host='192.168.100.21',
master_port=3306,
master_auto_position=1;
mysql&gt; start slave user='repl' password='<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d08090a3a3a7bfa2b4e1">[email&#160;protected]</a>!';
</code></pre>
<p>查看slave的状态看是否正确启动了复制功能。如果没错再在master上修改一部分数据检查是否同步到slave1和slave2。</p>
<p><strong>4.回到masterpurge掉已同步的binlog。</strong></p>
<p>当slave指定gtid_purged并实现了同步之后为了下次重启mysqld实例不用再次设置gtid_purged(甚至可能会在启动的时候自动开启复制线程)所以应该去master上将已经同步的binlog给purged掉。</p>
<pre><code># master上执行
mysql&gt; flush logs; # flush之后滚动到新的日志master-bin.000006
# 在确保所有slave都复制完000006之前的所有事务后purge掉旧日志
mysql&gt; purge master logs to &quot;master-bin.000006&quot;;
</code></pre>
<h1>6.GTID复制相关的状态信息和变量</h1>
<h2>6.1 <code>show slave status</code>中和gtid复制相关的状态行</h2>
<pre><code>Retrieved_Gtid_Set: a659234f-6aea-11e8-a361-000c29ed4cf4:1-54
Executed_Gtid_Set: a659234f-6aea-11e8-a361-000c29ed4cf4:1-54
Auto_Position: 1
</code></pre>
<p>其中:</p>
<ul>
<li><code>Retrieved_Gtid_Set</code>在开启了gtid复制(即gtid_mode=on)时slave在启动io线程的时候会检查自己的relay log并从中检索出gtid集合。也就是说这代表的是slave已经从master中复制了哪些事务过来。检索出来的gtid不会再请求master发送过来。</li>
<li><code>Executed_Gtid_Set</code>在开启了gtid复制(即gtid_mode=on)时它表示已经向自己的binlog中写入了哪些gtid集合。注意这个值是根据一些状态信息计算出来的并非binlog中能看到的那些。举个特殊一点的例子可能slave的binlog还是空的但这里已经显示一些已执行gtid集合了。</li>
<li><code>Auto_Position</code>开启gtid时是否自动获取binlog坐标。1表示开启这是gtid复制的默认值。</li>
</ul>
<h2>6.2 binlog中关于gtid的信息</h2>
<p>例如:</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="afddc0c0dbefd7dacad7c6">[email&#160;protected]</a> ~]# mysqlbinlog /data/master-bin.000007
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="de91929a819d91938e929b8a979190818a878e9be39e">[email&#160;protected]</a>@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#180610 1:34:08 server id 100 end_log_pos 123 CRC32 0x4a6e9510 Start: binlog v 4, server v 5.7.22-log created 180610 1:34:08
# Warning: this binlog is either in use or was not closed properly.
BINLOG '
kA8cWw9kAAAAdwAAAHsAAAABAAQANS43LjIyLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
ARCVbko=
'/*!*/;
# at 123
#180610 1:34:08 server id 100 end_log_pos 194 CRC32 0x0f6ba409 Previous-GTIDs
# a659234f-6aea-11e8-a361-000c29ed4cf4:1-57 #### 注意行1
# at 194
#180610 2:06:31 server id 100 end_log_pos 259 CRC32 0xfef9194e GTID last_committed=0 sequence_number=1 rbr_only=no #### 注意行2
SET @@SESSION.GTID_NEXT= 'a659234f-6aea-11e8-a361-000c29ed4cf4:58'/*!*/; #### 注意行3
# at 259
#180610 2:06:31 server id 100 end_log_pos 359 CRC32 0x5a561d94 Query thread_id=2 exec_time=0 error_code=0
use `backup`/*!*/;
SET TIMESTAMP=1528567591/*!*/;
SET @@session.pseudo_thread_id=2/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
create table t1(n int)
/*!*/;
# at 359
#180610 2:09:36 server id 100 end_log_pos 424 CRC32 0x82564e69 GTID last_committed=1 sequence_number=2 rbr_only=no #### 注意行4
SET @@SESSION.GTID_NEXT= 'a659234f-6aea-11e8-a361-000c29ed4cf4:59'/*!*/; #### 注意行5
# at 424
#180610 2:09:36 server id 100 end_log_pos 524 CRC32 0xbc21683a Query thread_id=2 exec_time=0 error_code=0
SET TIMESTAMP=1528567776/*!*/;
create table t2(n int)
/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; #### 注意行6
DELIMITER ;
# End of log file
/*!50003 SET <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fab9b5b7aab6bfaeb3b5b4a5aea3aabfc7bab5b6be">[email&#160;protected]</a>_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
</code></pre>
<p>其中:</p>
<ul>
<li>&quot;注意行1&quot;<code>Previous-GTIDs</code>代表的gtid集合是曾经的gtid换句话说是被purge掉的事务。</li>
<li>&quot;注意行2&quot;&quot;注意行4&quot;是两个事务的gtid信息。它们写在每个事务的前面。</li>
<li>&quot;注意行3&quot;&quot;注意行5&quot;设置了GTID_NEXT的值表示读取到了该事务后那么必须要执行的是稍后列出的这个事务。</li>
<li>&quot;注意行6&quot;是在所有事务执行结束时设置的表示自动获取gtid的值。它对复制是隐身的(也就是说不会dump线程不会将它dump出去)该行的结尾也说了这一行是mysqlbinlog添加的。</li>
</ul>
<h2>6.3 一些重要的变量</h2>
<ul>
<li>
<p><code>gtid_mode</code>是否开启gtid复制模式。只允许on/off类的布尔值不允许其他类型(如1/0)的布尔值,实际上这个变量是枚举类型的。要设置 <em>gtid_mode=on</em> ,必须同时设置 <em>enforce_gtid_consistency</em> 开。在MySQL 5.6中,还必须开启 <em>log_slave_updates</em> 即使是master也要开启。</p>
</li>
<li>
<pre><code>enforce_gtid_consistency
</code></pre>
<p>:强制要求只允许复制事务安全的事务。</p>
<p>gtid_mode=on时必须显式设置该项如果不给定值则默认为on。应该尽量将该选项放在gtid_mode的前面减少启动mysqld时的检查。</p>
<ul>
<li>不能在事务内部创建和删除临时表。只能在事务外部进行且autocommit需要设置为1。</li>
<li>不能执行 <em>create table ... select</em> 语句。该语句除了创建一张新表并填充一些数据,其他什么事也没干。</li>
<li>不能在事务内既更新事务表又更新非事务表。</li>
</ul>
</li>
<li>
<p><code>gtid_executed</code>已经执行过的GTID。 <em>reset master</em> 会清空该项的全局变量值。</p>
</li>
<li>
<p><code>gtid_purged</code>已经purge掉的gtid。要设置该项必须先保证 <em>gtid_executed</em> 已经为空这意味着也一定会同时设置该项为空。在slave上设置该项时表示稍后启动io线程和SQL线程都跳过这些gtidslave上设置时应该让此项的gtid集合等于master上 <em>gtid_executed</em> 的值。</p>
</li>
<li>
<p><code>gtid_next</code>表示下一个要执行的gtid事务。</p>
</li>
</ul>
<p>需要注意master和slave上都有<code>gtid_executed</code><code>gtid_purged</code>,它们代表的意义有时候是不同的。</p>
<p>还有一些变量,可能用到的不会多。如有需要,可翻官方手册。</p>
<h2>6.4 mysql.gtid_executed表</h2>
<p>MySQL 5.7中添加了一张记录已执行gtid的表<code>mysql.gtid_executed</code>所以slave上的binlog不是必须开启的。</p>
<pre><code>mysql&gt; select * from mysql.gtid_executed;
+--------------------------------------+----------------+--------------+
| source_uuid | interval_start | interval_end |
+--------------------------------------+----------------+--------------+
| a659234f-6aea-11e8-a361-000c29ed4cf4 | 1 | 57 |
| a659234f-6aea-11e8-a361-000c29ed4cf4 | 58 | 58 |
| a659234f-6aea-11e8-a361-000c29ed4cf4 | 59 | 59 |
+--------------------------------------+----------------+--------------+
</code></pre>
<h1>7.一张图说明GTID复制</h1>
<p>在前面第6节中使用了xtrabackup备份的方式提供gtid复制的基准数据。其中涉及到一些gtid检查、设置的操作。通过这些操作大概可以感受的到gtid复制的几个概念。</p>
<p>用一张图来说明:</p>
<p><img src="assets/733013-20180610232911355-1454041164.png" alt="img" /></p>
<p>假如当前master的gtid为A3已经purge掉的gtid为&quot;1--&gt;A1&quot;备份到slave上的数据为1-A2部分。</p>
<p>如果<code>A1 = 0</code>表示master的binlog没有被Purge过。slave可以直接开启gtid复制但这样可能速度较慢因为slave要复制所有binlog。也可以将master数据备份到slave上然后设置 <em>gtid_purged</em> 跳过备份结束时的gtid这样速度较快。</p>
<p>如果<code>A1 != 0</code>表示master上的binlog中删除了一部分gtid。此时slave上必须先从master处恢复purge掉的那部分日志对应的数据。上图中备份结束时的GTID为A2。然后slave开启复制唯一需要考虑的是&quot;是否需要设置 <em>gtid_purged</em> 跳过一部分gtid以避免重复执行&quot;</p>
<p>备份数据到slave上方式可以是mysqldump、冷备份、xtrabackup备份都行。由于gtid复制的特性所需要的操作都很少也很简单前提是理解了&quot;gtid的生命周期&quot;</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/文章/MySQL 主从复制 半同步复制.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/文章/MySQL 主从复制.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997fe4de838b66","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>