成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

MySQL:主從HASH SCAN算法可能導致從庫數據錯誤

數據庫 MySQL
本文主要以hash scan全表為基礎進行分析,而不涉及到hash scan索引,實際上都會遇到這個問題。

本文主要以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.com/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中的數據,因此比較一定成功,進入修改流程。 這個時候實際上就是把表中的第一行數據給修改了。也就是這個時候數據已經不對了,再次進行修改在錯誤數據上進行修改自然就可能查不到數據的情況。這實際就是一個crc32碰撞后邏輯錯誤導致的問題。

五、總結

  • 數據量和本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修復的。
  • 8.0 hash scan 已經成為了默認的算法,因此概率大大提高。
  • 看來主鍵越來越重要了,有主鍵自然不會觸發這個問題,還是重要事情說三遍吧,加主鍵、加主鍵、加主鍵。
責任編輯:趙寧寧 來源: MySQL學習
相關推薦

2011-04-14 11:09:14

MySQL數據庫

2021-05-11 10:18:07

數據泄露云安全云計算

2011-08-29 14:00:26

MySQL主從延時

2020-08-12 08:25:43

數據庫MySQL技術

2021-05-19 08:21:09

MySQL數據庫GTID

2018-01-04 10:08:08

2013-01-14 13:39:22

Windows 8Linux

2023-09-05 19:50:03

2017-01-17 15:14:49

MySQL數據庫自動化

2024-11-28 09:23:09

2010-10-15 16:03:03

Mysql分表處理

2016-03-29 10:21:24

大數據數據分析數據管理

2022-04-18 09:31:21

數據庫查詢MySQL

2018-09-04 05:05:57

2024-08-12 15:26:42

2023-09-08 00:12:40

2011-04-06 09:59:00

MySQL數據庫主從復制

2010-11-03 08:41:55

MySQL

2023-12-11 07:44:36

MySQL架構高可用

2016-12-19 15:54:17

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产片一区二区三区 | 国产精品99久久久精品免费观看 | 久久精品91| 国产线视频精品免费观看视频 | 久久99精品久久久久久 | 国产99免费视频 | 国产精品久久久久久妇女6080 | 免费av在线 | 一区二区三区国产 | 欧美美乳 | 精品粉嫩aⅴ一区二区三区四区 | www日日日 | 亚洲高清一区二区三区 | 毛片网站在线观看视频 | 雨宫琴音一区二区在线 | 91热在线 | 欧美精品一区二区三区一线天视频 | 中文字幕蜜臀av | 91精品国产综合久久精品 | 秋霞在线一区二区 | 国产美女在线免费观看 | 国产亚洲精品久久19p | 日韩在线精品视频 | 日日日视频 | 成人亚洲综合 | 免费黄色a视频 | 久久久久久国产精品 | 国产一区二区三区在线 | 久久亚洲免费 | 欧美女优在线观看 | 久久久中文 | 999久久久 | 中文字幕亚洲一区二区va在线 | 99久久婷婷国产综合精品电影 | 亚洲一区二区三区在线播放 | 欧美人成在线视频 | 欧美在线资源 | 国产不卡视频在线 | 亚洲国产激情 | 色综合视频| 91精品在线播放 |