MySQL:主从HASH SCAN算法可能导致从库数据错误

news2024/11/19 3:34:10

本文主要以hash scan全表为基础进行分析,而不涉及到hash scan索引,实际上都会遇到这个问题。本文主要描述的是update event,delete event也是一样的,测试包含8022,8026,8028均包含这个问题。
约定:bi为update row event的before image


一、问题描述

这里简单看一下报错的我们直接用metalink 上的文章来看,实际上作为做oracle的老人,还是比较查metalink的,在metalink上也有一些MySQL相关的文章,但是很少,如下:

 错误就是那个错误,解决办法也比较简单就是加上主键重做,这个问题我个人已经遇到N次了,每次都这么处理的,隐约的觉得hash scan 有BUG。

二、关于hash scan算法简介

在8.0中 hash scan 使用一个std::unordered_multimap的hash容器,记录其key - value值,每个key - value 代表修改的一行值,因为multimap容器允许重复的key - value,因此可以存在相同的行记录,这和5.7的实现不同,5.7是自己写的,而8.0 用的容器。其中

  • key为当前表中根据每个字段计算出来的crc32值,句函数为Hash_slave_rows::make_hash_key,也就是checksum_crc32函数
  • value为当前本行在event buffer中的位置,也就是指向实际的数据。

当然这里是简化了,实际value还包含一个std::unordered_multimap的迭代器和删除器,其中迭代器的作用是通过相同的key 调用,std::next 来查找下一个相同key的记录。
当一个event扫描结束后会将所有这个event的记录存储到这个hash容器中,函数Hash_slave_rows::put。而查找阶段会全表扫描本表,每次获取一行数据,然后在hash容器中进行查找,并进行处理,如下:

->循环1 读取表中的每条数据
  计算本行数据的crc32值,并且在event的hash 结构查找对应的entry
  ->循环2 
    拷贝读取到的行从record0到record1,也就是record1为扫描到的行
    ->循环3 
      从查找的entry中获取bi记录的位置,并且放入到record0中
      比对record0和record1的值是否相等,也就是record0是event对应的bi数据,而record1是扫描的本行数据
      如果比对不成功这获取查找到entry key在event中的下一条记录
    <-循环3结束条件为退出条件为找到了一条匹配记录或者entry为NULL
    ->如果查找到对应的entry且比对成功,也就是entry不为NULL
      恢复record1到record0中
      并且删除hash 结构中的这个entry
      进行数据修改
  <-循环2结束条件为再次使用record0也就是扫描的行在event的hash结构查找不到对应的entry,很显然后面逻辑只要匹配到了就会就会从event的hash结构查找中删除掉    

这样做的目的很明确就是将全表扫描的次数减少,每个event才做一次,这样自然提高了性能。

三、BUG出场

这个BUG是同事查询到后给我的,BUG如下:

  • https://bugs.mysql.combug/bug.php?id=101828

在这个BUG中,出现了2行记录crc32一致的情况,如下2个字符串的crc32也是一致的:

mysql> select crc32("b5a7b602ab754d7ab30fb42c4fb28d82");
+-------------------------------------------+
| crc32("b5a7b602ab754d7ab30fb42c4fb28d82") |
+-------------------------------------------+
|                                2575120314 |
+-------------------------------------------+
1 row in set (3.16 sec)

mysql> select crc32("d19f2e9e82d14b96be4fa12b8a27ee9f");
+-------------------------------------------+
| crc32("d19f2e9e82d14b96be4fa12b8a27ee9f") |
+-------------------------------------------+
|                                2575120314 |
+-------------------------------------------+

但是在整个hash scan 逻辑中,实际上比对crc32相同过后还是做了实际值的比较,也就是不完全依赖crc32值。这个BUG的流程如下:

  • 第一阶段,数据准备阶段
CREATE TABLE t1 (
  a bigint unsigned not null,
  b bigint unsigned not null
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into t1 values(0xa8e8ee744ced7ca8, 0x6850119e455ee4ed),(0x135cd25c170db910, 0x6916c5057592c796);

这两行数据的crc32值一样。

  • 第二阶段,数据错误阶段
    主库执行:
update t1 set a=1 where a=0x135cd25c170db910 and b=0x6916c5057592c796;

显然这条语句更改是第二行数据,但是到了从库由于BUG存在更改的是第一条数据,这个时候数据已经错误了。这个时候主库数据如下:

mysql> select * from t1;
+----------------------+---------------------+
| a                    | b                   |
+----------------------+---------------------+
| 12171240176243014824 | 7516527149547709677 |
|                    1 | 7572456450708129686 |
+----------------------+---------------------+
2 rows in set (0.00 sec)

从库数据如下:

mysql> select * from t1;
+---------------------+---------------------+
| a                   | b                   |
+---------------------+---------------------+
|                   1 | 7516527149547709677 |
| 1395221277543610640 | 7572456450708129686 |
+---------------------+---------------------+
2 rows in set (0.00 sec)
  • 第三阶段,报错阶段
update t1 set a=2 where a=1;

这里主库修改是第二行记录,也就是

a=1
b=7572456450708129686

但是到了从库,因为a=1和b=7572456450708129686的hash crc32值和表中任何一个记录都不匹配 ,这报错。

四、原因

在上面的逻辑中来看一下为什么出现问题。
在例子中如果我们修改了1行数据,并且这行数据在表中有2数据存在相同的crc32值,主库修改的是2行数据,那么可能存在下面的问题:

从库首先在循环1中获取第1行数据,然后在hash结构中查找,找到相同的crc32值,进入循环2拷贝record后进入循环3首先对比record0到record1的值也就是event中的数据,也就是第2行数据和第1行数据对比,显然实际的值肯定不同,这获取event相同crc32的下一条记录,显然不存在因为就更改了1条数据,返回为NULL,循环3结束,继续,因为entry为NULL,恢复record0的操作和更改数据的操作都不会做。
然后循环2循环条件再次通过扫描到的行数据查找hash结构的entry依旧是第1行数据的entry,进行下一次循环,这个时候因为record0没有恢复,还是event对应的bi数据,因此拷贝后record1也就是event对应的bi数据,接着进入循环3,这个时候进行比较,实际上比较都是event中的数据,因此比较一定成功,进入修改流程。
这个时候实际上就是把表中的第一行数据给修改了。也就是这个时候数据已经不对了,再次进行修改在错误数据上进行修改自然就可能查不到数据的情况。

五、总结

  • 数据量和本BUG相关,如果数据量大则crc32 不同记录产生相同CRC32的可能性就高一些。
  • 本BUG一直未修复,BUG提交者提交了patch,实际上就是当entry为NULL的时候结束循环2,这样就会扫描表的下一条数据,而不是直接修改本行数据。不知道官方是否觉得BUG中提交的patch不合适,还是其他原因。
  • 这个BUG看起来和Bug#28846386: RBR + STORED FUNCTION WITHOUT PRIMARY KEY - CAN'T FIND RECORD IN 有关,可能是修复一个BUG引入的新的BUG,这是8017修复的。
  • 看来主键越来越重要了,有主键自然不会触发这个问题,还是重要事情说三遍吧,加主键、加主键、加主键。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/633732.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

myBatis-plus之CRUD

文章目录 查询普通查询根据 ID 查询根据ID批量查询根据MAP查询 条件构造器查询构造器声明&#xff1a;QueryWrapper方法常用方法&#xff0c;以及简单使用方式实体作为条件构造器构造方法的参数lambda条件构造器 更新普通更新根据 ID 修改 条件构造器更新 删除普通删除根据 ID …

【Flutter 布局】001-Flex 布局

【Flutter 布局】001-Flex 布局 文章目录 【Flutter 布局】001-Flex 布局一、Flex1、概述简介构造函数 2、基本使用代码示例运行结果 3、方向取值范围代码示例 4、水平方向&#xff1a;主轴对齐方式取值范围代码示例运行结果 5、垂直方向&#xff1a;主轴对齐方式代码示例运行结…

【活动】如何对待工作中的失误

序言 作为一名软件开发程序员&#xff0c;我们每天都面临着无数的挑战和压力。 在这个充满竞争和变化的行业中&#xff0c;难免会犯错。 然而&#xff0c;如何正确地对待和处理这些失误&#xff0c;是必须要学会的重要技能。这不仅仅影响到我们的工作表现&#xff0c;更关乎我…

java SSM 游戏账号租售平台myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM 游戏账号租售平台是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主要采…

算法刷题-链表-环形链表

找到有没有环已经很不容易了&#xff0c;还要让我找到环的入口? 142.环形链表II 力扣题目链接 题意&#xff1a; 给定一个链表&#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 为了表示给定链表中的环&#xff0c;使用整数 pos 来表示链…

算法刷题-哈希表-有效的字母异位词

有效的字母异位词 242.有效的字母异位词思路其他语言版本相关题目 数组就是简单的哈希表&#xff0c;但是数组的大小可不是无限开辟的 242.有效的字母异位词 力扣题目链接 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 示例 1: 输入: s…

对数据进行模糊匹配搜索(动态规划、最长公共子串、最长公共子序列)

在搜索时常常在输入一半或者输入错误时&#xff0c;搜索引擎就给出智能提示。 已知的搜索推荐主要包括以下几个方面&#xff1a; 包含&#xff1a;“清华” 和 “清华大学”相似&#xff1a;“聊天软件” 和 “通讯软件”相关&#xff1a;“明星” 和 “刘亦菲”纠错&#xff…

Uni-app学习从0到1开发一个app——(4)生命周期

文章目录 0 引入1、应用生命周期2、页面生命周期3、组件生命周期4、引用 0 引入 uin-app生命周期是以小程序的生命周期为基础实现的&#xff0c;分为应用生命周期、页面生命周期、和组件生命周期&#xff0c;其中组件生命周期就是Vue的生命周期。 官方文档可见&#xff1a;ht…

java之反射机制和注解(更新中......)

Reflect在文档中的位置&#xff1a; 文档链接&#xff1a;https://docs.oracle.com/javase/8/docs/api/index.html 用于获取类或对象的反射信息。 常用的反射机制重要的类&#xff1a; java.lang.Class&#xff1a;整个字节码&#xff0c;代表一个类型。包含了以下三块内容&a…

算法刷题-了解哈希表

哈希表 首先什么是 哈希表&#xff0c;哈希表&#xff08;英文名字为Hash table&#xff0c;国内也有一些算法书籍翻译为散列表&#xff0c;大家看到这两个名称知道都是指hash table就可以了&#xff09;。 哈希表是根据关键码的值而直接进行访问的数据结构。 这么这官方的解释…

Spring Boot 基本配置

大家好&#xff01;我是今越。简单记录一下在 Spring Boot 中的一些基本配置。 Banner 配置 配置文件 application.properties # 设置路径和名称&#xff0c;默认路径名称 resources/banner.txt spring.banner.locationclasspath:banner1.txt # 启动项目时&#xff0c;关闭 b…

语法篇JQuery基础

目录 一、初识JQuery 1.1JQuery介绍 导入方式 常用公式 1.2快速入门 二、JQuery入门 2.1文档就绪函数 2.2名称冲突 2.3JQuery选择器 表单选择器 2.4JQuery过滤器 基础过滤器(Basic Fiter) 子元素过滤器 内容过滤器 可见性过滤器 三、JQuery事件与特效 3.1JQuery…

set/map学习

我们要开始学习map和set的使用&#xff0c;虽然使用更加复杂&#xff0c;但是STL整体的设计&#xff0c;本身就具有很强的前瞻性和延续性&#xff0c;比如说迭代器等&#xff0c;我们顺着文档来看。这也是除了vector之外最重要的容器&#xff0c;当然还有unordered_map 和 unor…

g++ 编译选项

1&#xff0c;基本编译过程 g可以用于编译C代码生成可执行程序&#xff0c;从原始代码到生成可执行过程中实际经历了以下4个步骤&#xff1a; 1. 预处理&#xff1a;宏替换&#xff0c;注释消除&#xff0c;查找相关库文件等[使用-E参数]。 # 只激活预处理&#xff0c;不会自…

集成正态云和动态扰动的哈里斯鹰优化算法(IHHO)-附代码

集成正态云和动态扰动的哈里斯鹰优化算法(IHHO) 文章目录 集成正态云和动态扰动的哈里斯鹰优化算法(IHHO)1.哈里斯鹰优化算法2.改进哈里斯鹰优化算法2.1 正态云模型2.2 随机反向学习思想2.3 动态扰动策略 3.实验结果4.参考文献5.Matlab代码6.python代码 摘要&#xff1a; 针对基…

Uni-app学习从0到1开发一个app——(3)简单小工程内容介绍

文章目录 工程文件 看看一个标准的hello微信小程序工程文件的组成和作用。 工程文件 可以参考官方教程&#xff1a;传送门 之前的文章有详细的开发环境介绍&#xff0c;传送门Uni-app学习从0到1开发一个app——(2)windowns环境搭配&#xff0c;这里我们先建一个简单的示例微信…

【工具】Xshell-7和Xftp-7下载安装使用教程

目录 一、Xshell和Xftp 二、安装包下载(Xshell和Xftp) 三、Xshell安装、使用和常用设置 1. Xshell安装&#xff1a; 2. Xshell使用: 3. Xshell常用设置 三、Xftp安装、使用 1. Xftp安装 2. Xftp使用 一、Xshell和Xftp Xshell&#xff1a; Xshell是一款强大的SSH&#xff…

【数据结构与算法分析】树上漫步之探究前序、中序、后序、广度优先遍历算法的实现与优化

文章目录 前言二叉树的遍历方式构建二叉树递归遍历二叉树非递归遍历二叉树层次遍历 示例二叉树结果总结 前言 二叉树是数据结构中最基本的数据结构之一&#xff0c;它在计算机科学中有着非常重要的应用。二叉树的遍历是指按照一定的顺序遍历二叉树中的所有节点&#xff0c;是二…

DML——数据库查询语言

查询——select SELECT [DISTINCT/ALL/] {*|column|expression [alias],…} FROM table [Natuarl join /] where子句; Natuarl join 自然连接只考虑那些在两个关系模式中都出现的属性上取值相同的元祖队。 列名&#xff08;属性名&#xff09;完成相同值相同去除重复列拓展&…

【Typora+Lsky】在deepin使用YGXB-net/lsky-upload上传图片

本文首发于 慕雪的寒舍 在win和deepin上使用lsky-upload上传图片 1.说明 先前使用lsky图床的时候&#xff0c;我一直用的是picgo的插件来上传图片。 但最近picgo总是遇到卡上传的问题 https://github.com/Molunerfinn/PicGo/issues/1060 后来在gitee上面搜到了这个项目&…