欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > 【MySQL】MySQL 引擎特性 基于 GTID 复制实现的工作原理

【MySQL】MySQL 引擎特性 基于 GTID 复制实现的工作原理

2024/10/23 23:28:06 来源:https://blog.csdn.net/2203_75283579/article/details/140164069  浏览:    关键词:【MySQL】MySQL 引擎特性 基于 GTID 复制实现的工作原理

GTID (global transaction IDentifier) 是全局事务标识。具有全局唯一性,一个 GTID 在一个服务器上只执行一次,从而避免重复执行导致数据混乱或主从不一致。

  1. GTID 怎么保证的全局唯一性?
    GTID = source_id(数据库uuid即server_uuid) : transaction_id(从1开始自增长的序列号)
  2. 什么是 server_uuid ?
    MySQL5.6 以后采用128位的 server_uuid 代替了32位的 server_id,server_id 依赖于my.cnf的手工配置,可能会有冲突,128位的uuid算法可以保证所有的 MySQL_uuid 不发生冲突。
  3. uuid算法怎么保证不冲突的?
    uuid=时间戳(当前时间戳,格林威治标准时间以来的纳秒数)+节点(机器Mac地址哈希)+时钟序列(随机生成两个字节)
  4. GTID 的优势
    在传统的复制里面,当发生故障需要主从切换时,服务器需要找到 binlog 和 pos 点,然后将其设为新的主节点开启复制,相对来说比较麻烦,也容易出错。在MySQL5.6里面,MySQL会通过内部机制自动匹配GTID断点,不再寻找 binlog 和 pos 点。
  5. MySQL 怎么自动匹配 GTID 断点?
  6. 在每个事务的开头,GTID 被获取并保存在内存中。事务完成后,GTID被记录到二进制日志中,并标记事务已提交。
  7. GTID EXCUTED 是从服务器中已经执行的 GTID 集合,会在内存和磁盘中同步保存,每次从服务器同步完成一个事务后,都会更新这些集合状态。
  8. 在服务器恢复时,MySQL 会读取 GTID 集合并恢复状态。通过对比 GTID 集合,确保恢复后的数据一致性

模拟GTID复制

package mainimport ("fmt""io/ioutil""os""strings""sync""time"
)func initializeFile(filePath string, content string) {ioutil.WriteFile(filePath, []byte(content), 0644)
}func appendToFile(filePath, content string) {f, _ := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, 0644)defer f.Close()f.WriteString(content)
}func readFile(filePath string) string {content, _ := ioutil.ReadFile(filePath)return string(content)
}func monitorSourceFileAndUpdateBinlog(sourceFile, binlogFile string, stopCh chan bool) {ticker := time.NewTicker(2 * time.Second)defer ticker.Stop()var lastContent stringfor {select {case <-stopCh:returncase <-ticker.C:currentContent := readFile(sourceFile)if currentContent != lastContent {gtid := fmt.Sprintf("GTID=%d\n", time.Now().UnixNano())appendToFile(binlogFile, gtid)appendToFile(binlogFile, currentContent[len(lastContent):])lastContent = currentContent}}}
}func monitorBinlogAndUpdateRelaylog(binlogFile, relaylogFile string, stopCh chan bool) {ticker := time.NewTicker(2 * time.Second)defer ticker.Stop()var lastContent stringfor {select {case <-stopCh:returncase <-ticker.C:currentContent := readFile(binlogFile)if currentContent != lastContent {appendToFile(relaylogFile, currentContent[len(lastContent):])lastContent = currentContent}}}
}func monitorRelaylogAndUpdateTarget(relaylogFile, targetFile string, stopCh chan bool) {ticker := time.NewTicker(2 * time.Second)defer ticker.Stop()var lastContent stringfor {select {case <-stopCh:returncase <-ticker.C:currentContent := readFile(relaylogFile)if currentContent != lastContent {// Remove GTID lineslines := strings.Split(currentContent[len(lastContent):], "\n")for _, line := range lines {if !strings.HasPrefix(line, "GTID=") && line != "" {appendToFile(targetFile, line+"\n")}}lastContent = currentContent}}}
}func main() {var wg sync.WaitGroupstopCh := make(chan bool)// 文件路径与初始内容设置sourceFile := "txt1"targetFile := "txt2"binlogFile := "binlog"relaylogFile := "relaylog"// 初始化文件initializeFile(sourceFile, "Initial content\n")initializeFile(targetFile, "")initializeFile(binlogFile, "")initializeFile(relaylogFile, "")// 启动监控协程wg.Add(3)go func() {defer wg.Done()monitorSourceFileAndUpdateBinlog(sourceFile, binlogFile, stopCh)}()go func() {defer wg.Done()monitorBinlogAndUpdateRelaylog(binlogFile, relaylogFile, stopCh)}()go func() {defer wg.Done()monitorRelaylogAndUpdateTarget(relaylogFile, targetFile, stopCh)}()// 模拟用户输入以停止监控fmt.Println("Press Enter to stop monitoring...")fmt.Scanln()// 通知监控协程停止stopCh <- true// 等待所有协程结束wg.Wait()fmt.Println("Replication completed.")
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com