mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-09-17 08:46:40 +08:00
1006 lines
56 KiB
HTML
1006 lines
56 KiB
HTML
<!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> show variables like "%uuid%";
|
||
+---------------+--------------------------------------+
|
||
| Variable_name | Value |
|
||
+---------------+--------------------------------------+
|
||
| server_uuid | a126fcb6-3706-11e8-b1d5-000c294ebf0d |
|
||
+---------------+--------------------------------------+
|
||
1 row in set (0.00 sec)
|
||
|
||
mysql> \! 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>例如"gtid_executed 5ad9cb8e-2092-11e7-ac95-000c29bf823d:1-6",表示该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> grant replication slave on *.* to <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8dffe8fde1cd">[email protected]</a>'192.168.100.%' identified by '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7a2a3a09090d15081e4b">[email protected]</a>!';
|
||
</code></pre>
|
||
<p>因为master上的binlog没有删除过,所以在slave上直接<code>change master to</code>配置连接参数。</p>
|
||
<pre><code class="language-mysql"># slave上执行
|
||
mysql> 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> start slave user='repl' password='<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="9cccdcefefebf3eef8ad">[email protected]</a>!';
|
||
</code></pre>
|
||
<p>查看io线程和sql线程是否正常。</p>
|
||
<pre><code># slave上执行,为了排版,缩减了一些无关紧要的字段
|
||
mysql> 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> 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 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> flush logs;
|
||
mysql> purge master logs to 'master-bin.000005';
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="82f0ededf6c2faf7e7faeb">[email protected]</a> ~]# cat /data/master-bin.index
|
||
/data/master-bin.000005
|
||
</code></pre>
|
||
<p>但无论master是否purge过binlog,配置基于gtid的复制都极其方便,而且方法众多(只要理解了GTID的生命周期,可以随意折腾,基本上都能很轻松地维护好),这是它"迷人"的优点。</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 protected]</a> ~]# mkdir /backdir # 备份目录
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7b0914140f3b030e1e0312">[email protected]</a> ~]# innobackupex -uroot <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6d401d3d2d1e1e1a021f095c">[email protected]</a>! -S /data/mysql.sock /backdir/ # 准备数据
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="54263b3b20142c21312c3d">[email 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 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 protected]</a> ~]# systemctl stop mysqld
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="33415c5c47734b46564b5a">[email protected]</a> ~]# rm -rf /data/* # 恢复前必须先清空数据目录
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="35475a5a41754d40504d5c">[email 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 protected]</a> ~]# chown -R mysql.mysql /data
|
||
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="35475a5a41754d40504d5c">[email 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 "gtid_executed";</code>中获取,它表示master中已执行过的事务。</p>
|
||
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d9abb6b6ad99a1acbca1b0">[email 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 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> 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> reset master;
|
||
mysql> set @@global.gtid_purged='a659234f-6aea-11e8-a361-000c29ed4cf4:1-54';
|
||
</code></pre>
|
||
<p>设置好gtid_purged之后,就可以开启复制线程了。</p>
|
||
<pre><code>mysql> change master to
|
||
master_host='192.168.100.21',
|
||
master_port=3306,
|
||
master_auto_position=1;
|
||
mysql> start slave user='repl' password='<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d08090a3a3a7bfa2b4e1">[email protected]</a>!';
|
||
</code></pre>
|
||
<p>查看slave的状态,看是否正确启动了复制功能。如果没错,再在master上修改一部分数据,检查是否同步到slave1和slave2。</p>
|
||
<p><strong>4.回到master,purge掉已同步的binlog。</strong></p>
|
||
<p>当slave指定gtid_purged并实现了同步之后,为了下次重启mysqld实例不用再次设置gtid_purged(甚至可能会在启动的时候自动开启复制线程),所以应该去master上将已经同步的binlog给purged掉。</p>
|
||
<pre><code># master上执行:
|
||
mysql> flush logs; # flush之后滚动到新的日志master-bin.000006
|
||
# 在确保所有slave都复制完000006之前的所有事务后,purge掉旧日志
|
||
mysql> purge master logs to "master-bin.000006";
|
||
</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 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 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 protected]</a>_COMPLETION_TYPE*/;
|
||
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
|
||
</code></pre>
|
||
<p>其中:</p>
|
||
<ul>
|
||
<li>"注意行1"中<code>Previous-GTIDs</code>代表的gtid集合是曾经的gtid,换句话说是被purge掉的事务。</li>
|
||
<li>"注意行2"和"注意行4"是两个事务的gtid信息。它们写在每个事务的前面。</li>
|
||
<li>"注意行3"和"注意行5"设置了GTID_NEXT的值,表示读取到了该事务后,那么必须要执行的是稍后列出的这个事务。</li>
|
||
<li>"注意行6"是在所有事务执行结束时设置的,表示自动获取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线程都跳过这些gtid,slave上设置时应该让此项的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> 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为"1-->A1",备份到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开启复制,唯一需要考虑的是"是否需要设置 <em>gtid_purged</em> 跳过一部分gtid以避免重复执行"。</p>
|
||
<p>备份数据到slave上,方式可以是mysqldump、冷备份、xtrabackup备份都行。由于gtid复制的特性,所需要的操作都很少,也很简单,前提是理解了"gtid的生命周期"。</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>
|