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

MySQL 8.0/8.4執行DDL會丟數據?是,但影響有限

數據庫 MySQL
在線上生產環境中,除了必要的增刪字段、增刪索引、修改字段定義外,直接執行 ALTER TABLE ... ENGINE=InnoDB? 或 OPTIMIZE TABLE? 重建整個表空間的行為還是比較少的,尤其是操作大表時,也基本上都習慣了用類似 gt-osc 之類的第三方輔助工具來完成。

先說解決辦法,從簡單到麻煩:

  1. 執行 ALTER TABLE 時,顯式指定ALGORITHM=INSTANT/COPY,反正不要使用 INPLACE。
  2. 適當調大 innodb_ddl_buffer_size 參數值,其默認值1MB,例如調大到100MB就可以應對大部分業務表的DDL操作場景。
  3. 利用 pt-osc 或 gh-ost 等工具進行 Online DDL 操作。
  4. 在業務低谷時段執行DDL操作,有條件的話甚至可以在業務維護期間再執行DDL操作。
  5. 升級版本到已修復的 Percona 分支版本(下文會提到)。

問題來源

在 MySQL 8.0.27 版本中新增并行DDL功能后才“引入”了這個問題。目前在最新的 8.1.x/8.3.x/8.3.x/8.4.x/9.0.x/9.1.x 等版本中依然存在,預計到 MySQL 8.0.41 新版本會修復。

For online DDL operations, storage is usually the bottleneck. To address this issue, CPU utilization and index building has been improved. Indexes can now be built simultaneously instead of serially. Memory management has also been tightened to respect memory configuration limits set by the user.

詳見:https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-27.html

觸發原因:在INPLACE模式的DDL操作中重建主鍵索引時,因錯誤處理會略過部分記錄,導致數據丟失。

觸發條件:只影響INPLACE模式的DDL操作,不影響COPY和INSTANT模式的DDL操作。以下是幾種常見的可能觸發問題的DDL操作場景:

  • 場景1:ALTER TABLE ENGINE=INNODB 重整表空間操作,需要重建主鍵索引。
  • 場景2:ALTER TABLE ADD NEW-COL ...,ALGORITHM=INPLACE,新增列操作,因指定了INPLACE模式,需要重建主鍵索引。

其他例如INSTANT模式加新字段,增刪索引則不會觸發該問題。

關于該問題的詳細解讀詳見幾篇文章:

  • 八怪老師推文  8027后關于DDL 丟數據問題https://www.jianshu.com/p/c66fe0349345?v=1734349439280 
  • Rex老師推文 MySQL 8.4-LTS DDL會導致數據丟失。
  • 丁奇老師推文 丟數據風險 @ MySQL官方最新版。
  • Percona 推文 Who Ate My MySQL Table Rows?。

涉及到2個MySQL bug:

  • DDL 丟數風險:https://bugs.mysql.com/bug.php?id=115608
  • DDL 重復行報錯:https://bugs.mysql.com/bug.php?id=115511

該問題核心就存在于如果涉及到需要用INPLACE算法重建主鍵索引的DDL操作,就需要在 innodb_ddl_buffer_size 用滿后直接插入到 #sql-ibXXX 數據文件中,這個時候可能正在page的中間的某個位置,插入的時候會暫時放棄page上的mutex,并且保存游標到持久游標,然后插入數據,插入完成后再從持久游標恢復游標。這樣做的目的可能是為了提高page修改的并發,但是這里保存和恢復持久游標卻出了問題,主要是page中的數據可能出現修改,這種修改對應了前面的2個BUG:

  • Purge線程,清理del flag。
  • 其他線程INSERT了數據。

具體游標的保存和恢復出現的問題,可以參考Rex老師的文章 MySQL 8.4-LTS DDL會導致數據丟失。

問題影響

目前該問題已知影響的版本列表如下:

  • MySQL 8.0.x 系列版本中,所有 >= 8.0.27 的 MySQL 8.0.x 版本;
  • 所有 8.4.x 系列 LTS 版本;
  • Percona Server for MySQL 中從 8.0.27-18 至 8.0.37-29,以及 8.4.0-1 版本。
  • Percona XtraDB Cluster 中從 8.0.27-18.1 至 8.0.37-29,以及 8.4.0-1 版本。

未受影響或已修復的版本列表如下:

  • 所有早于 MySQL 8.0 的版本,及 MySQL 5.6、5.7 等版本,以及 Percona 5.6、5.7 版本;
  • Percona 8.0 系列中 8.0.39-30 及更高版本;
  • Percona 8.4 系列中 8.4.2-2 及更高版本;
  • Percona XtraDB Cluster 8.0 系列中 8.0.39-30 及更高版本。

目前所有活躍的 MySQL 版本均未修復,已安排在MySQL 8.0.41版本修復該問題。GreatSQL也會在下一個新版本中修復該問題。

問題復現/模擬

模擬測例1

經過測試,該問題觸發概率和 update/delete 并發負載有關,結合 MySQL bug #113812 提供的案例,我進行了簡化和改造,測試用例如下:

#/bin/sh
# bugtest.sh,測例1
# 需要先安裝 mysql_random_data_load 測試工具
# 通過socket方式連接MySQL時用root密碼并且是空密碼
MYSQL="mysql -N -s -uroot -S/data/MySQL/mysql.sock"
HOST=127.0.0.1
PORT=3306
USER="yejr"
PWD="yejr"

echo"1. Prepare work"

read -r -d '' bugSQL <<-EOSQL || true
CREATE DATABASE IF NOT EXISTS test;
USE test;
DROP TABLE IF EXISTS t1;
CREATE TABLE IF NOT EXISTS t1(
 id int not null,
 c1 varchar(20) not null,
 c2 varchar(30) not null,
 c3 datetime not null,
 c4 varchar(30) not null,
 PRIMARY KEY (id),
 KEY idx_c3 (c3)
) ENGINE=InnoDB;

CREATE USER IF NOT EXISTS '${USER}'@'%';
ALTER USER '${USER}'@'%' IDENTIFIED BY '${PWD}';
GRANT ALL PRIVILEGES ON test.t1 TO '${USER}'@'%';
EOSQL

${MYSQL} -f -e "${bugSQL}"

echo"2. Starting run test"

${MYSQL} -e "truncate table test.t1;"

for i in {1..1000}
do
 mysql_random_data_load -u${USER} -p${PWD} -h${HOST} -P${PORT} --max-threads=2 test t1 1000 > /dev/null 2>&1
 c_before_del=`${MYSQL} -e "select count(*) from test.t1;"`
 c_delete=`${MYSQL} -e "select count(*) from test.t1 where c3 < curdate() - interval 7 day;"`
${MYSQL} -e "delete from test.t1 where c3 < curdate() - interval 7 day;"
 c_before_alter=`${MYSQL} -e "select count(*) from test.t1;"`
${MYSQL} -e "alter table test.t1 engine=innodb;"
 c_after_alter=`${MYSQL} -e "select count(*) from test.t1;"`
if [ ${c_before_alter} -ne ${c_after_alter} ] ; then
echo"run ${i} times, delete: ${c_delete}, before alter: ${c_before_alter}, after alter: ${c_after_alter}"
exit
fi
if [ `expr ${i} % 10` -eq 0 ] ; then
echo"run ${i} times"
fi
done

執行該測試用例腳本,當發現有問題時,結果顯式如下:

$ sh ./bugtest.sh
1. Prepare work
2. Starting run test
run 10 times
run 20 times
run 30 times
...
run 175 times, delete: 979, before alter: 3436, after alter: 3435

這就表示執行到第175次后觸發問題,發現丟了一條記錄。在這個測例中,如果加大 innodb_ddl_buffer_size 參數值到10MB,則不再觸發問題。

模擬測例2

對上面的測試用例再進行調整后,改成下面這個測例,在執行完1000次后仍未觸發問題(可見并不總是會觸發問題,只有個別情況下會踩雷):

#!/bin/sh
# bugtest.sh,測例2
# 需要先安裝 mysql_random_data_load 測試工具
# 通過socket方式連接MySQL時用root密碼并且是空密碼
MYSQL="mysql -N -s -uroot -S/nvme/GreatSQL/mysql.sock"
HOST=127.0.0.1
PORT=3306
USER="yejr"
PWD="yejr"

echo"1. Prepare work"

read -r -d '' bugSQL <<-EOSQL || true
CREATE DATABASE IF NOT EXISTS test;
USE test;
DROP TABLE IF EXISTS t1;
CREATE TABLE IF NOT EXISTS t1(
 id int not null,
 c1 varchar(20) not null,
 c2 varchar(30) not null,
 c3 int not null,
 c4 varchar(30) not null,
 PRIMARY KEY (id),
 KEY idx_c3 (c3)
) ENGINE=InnoDB;

CREATE USER IF NOT EXISTS '${USER}'@'%';
ALTER USER '${USER}'@'%' IDENTIFIED BY '${PWD}';
GRANT ALL PRIVILEGES ON test.t1 TO '${USER}'@'%';
EOSQL

${MYSQL} -f -e "${bugSQL}"

echo"2. Starting run test"

${MYSQL} -e "truncate table test.t1;"

for i in {1..300}
do
 mysql_random_data_load -u${USER} -p${PWD} -h${HOST} -P${PORT} --max-threads=2 test t1 1000 > /dev/null 2>&1
 c_before_del=`${MYSQL} -e "select count(*) from test.t1;"`
${MYSQL} -e "delete from test.t1 LIMIT 980;"
 c_before_alter=`${MYSQL} -e "select count(*) from test.t1;"`
${MYSQL} -e "alter table test.t1 engine=innodb;"
 c_after_alter=`${MYSQL} -e "select count(*) from test.t1;"`
if [ ${c_before_alter} -ne ${c_after_alter} ] ; then
echo"run ${i} times, before alter: ${c_before_alter}, after alter: ${c_after_alter}"
exit
fi
if [ `expr ${i} % 10` -eq 0 ] ; then
echo"run ${i} times"
fi
done

從多次反復測試的結果來看,大致的規律是當執行 ALTER TABLE 操作特別頻繁時,就可能會在表重建時遇到被 Purge 的記錄還沒來得及被抹掉,這就比較容易觸發問題。試著把上面的測例1做些微調,把 ALTER TABLE 這部分的處理邏輯修改成下面這樣:

...
 47  if [ `expr ${i} % 20` -eq 0 ] ; then
 48   sleep 2
 49   ${MYSQL} -e "alter table test.t1 engine=innodb;"
 50  fi
...

即每完成20輪測試后再執行 ALTER TABLE 操作,并且在此之前還要先休眠等待2秒。改用新邏輯后,就沒再觸發問題。

模擬測例3

提示:該測例需要改成MySQL debug版本運行(平時使用的是release二進制包,是無法復現的)。

  • 準備測試數據
CREATE TABLE t1 (pk CHAR(5) PRIMARY KEY);
INSERT INTO t1 VALUES ('aaaaa'), ('bbbbb'), ('bbbcc'), ('ccccc'), ('ddddd'), ('eeeee');
  • 測試方法

S1

S2

這一步的目的是2行數據key buffer就滿


SET DEBUG='+d,ddl_buf_add_two';



set global innodb_purge_stop_now=ON;


DELETE FROM t1 WHERE pk = 'bbbcc';

進行DDL,并且來到ddl0par-scan.cc:238 行


ALTER TABLE t1 ENGINE=InnoDB, ALGORITHM=INPLACE



SET GLOBAL innodb_purge_run_now=ON;

DDL繼續進程(丟數據)


  • 測試結果

圖片圖片

寫在后面

在線上生產環境中,除了必要的增刪字段、增刪索引、修改字段定義外,直接執行 ALTER TABLE ... ENGINE=InnoDB 或 OPTIMIZE TABLE 重建整個表空間的行為還是比較少的,尤其是操作大表時,也基本上都習慣了用類似 gt-osc 之類的第三方輔助工具來完成。

此外,調大 innodb_ddl_buffer_size 參數值也可以應對大部分業務表的DDL操作需求,在我的測試中,調大到10MB就可以保證上述測試表有幾十萬行數據時不出問題,調大到100MB則可以保證上述測試表有千萬行數據時不出問題。如果是更大、更寬的表就需要進一步測試驗證了。

總的來看,這個問題在線上生產環境中并不是百分百會觸發,只是存在一定較低的幾率,在文章一開始也提到了幾個可以規避的方法,所以說其影響其實也是有限的,不必過于緊張。先采用緊急辦法規避問題,后面再擇機升級版本就好。

責任編輯:武曉燕 來源: MySQL學習
相關推薦

2022-09-20 10:44:06

MySQL 8.0數據庫DDL

2025-04-07 03:00:00

MySQLDDLonline

2021-01-22 09:56:50

微信微信8.0移動應用

2021-03-18 10:31:32

數據安全云廠商數據泄露

2009-06-23 09:13:38

喬布斯蘋果股價

2024-05-31 13:04:09

2023-06-12 08:18:19

MySQLDDL數據

2022-10-10 08:01:08

MySQL字典表

2009-02-22 17:52:53

simpana 8.0CommVault

2013-04-27 14:39:40

大數據全球技術峰會

2020-07-01 09:38:12

App安卓應用

2024-01-02 08:55:27

Linux緩存系統性能

2019-03-21 14:00:05

MySQLUpdate數據庫

2022-03-02 15:18:50

數據中心脫碳

2024-04-09 09:08:09

Kafka消息架構

2023-03-04 20:50:19

MySQL字典InnoDB

2019-07-01 16:20:28

Windows 功能系統

2023-09-12 07:26:46

2023-06-12 09:09:19

MySQLDDLNSTANT

2018-03-06 06:59:17

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲精品在线观 | 国产在线精品区 | 一区二区三区在线 | 亚洲黄色在线免费观看 | 久久久精品一区 | 在线看av网址 | 精品欧美一区二区三区精品久久 | 日本韩国电影免费观看 | 亚洲自拍偷拍免费视频 | 国产欧美久久一区二区三区 | 日本成人片在线观看 | 免费视频色 | 欧美不卡视频 | 女人牲交视频一级毛片 | 日韩欧美中文字幕在线观看 | 午夜精品久久久久久久久久久久 | 精品欧美乱码久久久久久1区2区 | 欧美日韩专区 | 97国产精品 | 久久久久久久久国产精品 | 91超碰在线| 狠狠干狠狠插 | 成人性视频免费网站 | 国产一区二区三区在线免费 | 欧美区日韩区 | 在线视频日韩 | 天天拍天天射 | 日韩一区二区在线播放 | 久久黄视频 | 国产精品一区二区三区四区 | 日韩在线免费播放 | 亚洲区一区二 | 日韩三区在线观看 | 男人天堂色 | 欧美精品一区二区三区视频 | 亚洲淫视频| 天天影视网天天综合色在线播放 | 午夜在线 | 久久久久久天堂 | 成人精品一区二区 | 国产黄色精品 |