標籤:bool odk 問題 amp 2dx idc jar xfce asm
本文簡析Online DDL的實現原理與使用過程注意事項。
任何DDL操作,執行者都需要預先測試或者清晰瞭解這個操作會給資料庫帶來的影響是否是在業務期間資料庫的可承受範圍內,尤其是對大表的DDL操作中,需要密切留意伺服器的IO,記憶體及CPU使用方式(每個DBA總有那麼一段被大表的DDL語句坑到的血淚史)。 如果轉載,請註明博文來源: www.cnblogs.com/xinysu/ ,著作權歸 部落格園 蘇家小蘿蔔 所有。望各位支援!
1 早期DDL實現原理(
5.6.7之前
) Innodb早期支援通過copy table跟inplace的方式來執行DDL語句,其原理如下:
- copy table方式
- 建立跟原表格一致的暫存資料表,並在該暫存資料表上執行DDL語句
- 鎖原表,不允許DML,允許查詢
- 逐行資料從原表拷貝到暫存資料表中(這個過程是沒有排序的)
- 拷貝結束後,原表禁止讀操作,也就是原表此時不提供讀寫服務
- 進行rename操作,完成DDL過程
- inplace方式(fast index creation,僅針對索引的建立跟刪除)
- 建立frm臨時檔案
- 鎖原表,不允許DML,允許查詢
- 按照叢集索引的順序,查詢資料,找到需要的索引列資料,排序後插入到新的索引頁中
- 原表禁止讀操作,也就是原表此時不提供讀寫服務
- 進行rename操作,替換frm檔案,完成DDL過程
inplace在copy table的基礎上做了一個較大的改進,則是不需要copy整個表格,只需要在原來的ibd檔案上,建立所需要的索引頁,這個過程比copy table節約極大的IO資源佔用 且 DDL SQL執行速度大大提高,減少了該表格不提供寫服務的時間長度。但是inplace僅支援索引的建立於刪除,不支援其他的DDL操作,其他的DDL操作,仍然是copy table方式執行。
對於一個線上業務資料庫,無論是copy table方式還是inplace方式,這裡仍然有一個明顯的弊端:操作期間涉及表格不提供寫服務!無法對涉及到表格至下INSERT,UPDATE,DELETE操作,僅支援SELECT。
2 Online DDL實現原理 當表格發生DDL操作,可能會出現該表格數分鐘甚至數小時不可訪問,效能及響應異常,為了有效改善這個情況,MySQL 在5.6.7版本推出了Online DDL。(本文參考官網5.7版本的文檔整理及測試)。 在online DDL中,也包含了copy跟inplace兩種方式,對於不支援Online DDL的DDL SQL,則採用COPY方式;對於支援Online DDL的DDL SQL,則採用Inplace方式,這裡的Inplace又區分為2類:是否需要rebuild表格,判斷標準為:是否修改行記錄格式。如果修改了行記錄格式,則需要rebuild表格,比如修改列類型、增減列等;如果沒有修改行記錄格式,僅修改表的中繼資料,則不需要rebuild表格,僅修改中繼資料 metadata,比如刪除索引、設定預設值及重新命名列名等。詳細可見,具體文法情況見`第4部分`。 那麼,新增的Online DDL內部是怎樣一個實現原理呢?(此處參考:http://blog.itpub.net/22664653/viewspace-2056953/) 有3個階段:prepare、execute、commit。
- PREPARE
- 建立新的臨時frm檔案
- 持有EXCLUSIVE_MDL鎖,禁止讀寫
- 根據alter類型,確定執行方式(copy,rebuild,no-rebuild)
- 更新資料字典的記憶體對象
- 若是需要rebuild,分配row_log對象記錄的增量
- 若是需要rebuild, 產生新的臨時ibd檔案
- EXECUTE
- 如果是僅修改中繼資料:
- 其他,則是:
- 降低EXCLUSIVE-MDL鎖,允許讀寫(copy 不允許寫)
- 記錄ddl執行過程中產生的增量row-log(僅rebuild類型需要)
- 掃描old_table的叢集索引每一條記錄record
- 遍曆新表的叢集索引和二級索引,逐一處理
- 根據record構造對應的索引項目
- 將構造索引項目插入sort_buffer塊
- 將sort_buffer塊插入新的索引
- 把row-log中的操作應用到新暫存資料表中,應用到最後一個Block
- COMMIT
- 升級到EXECLUSIVE-MDL鎖,禁止讀寫
- 重做最後一部分的row_log增量
- 更新innodb的資料字典表
- 提交事務,寫redo日誌
- 修改統計資訊
- rename 臨時的ibd檔案、frm檔案
- DDL完成
這裡注意下row-log,它是記錄 DDL在執行過程中表格發生資料變更的操作,這樣就可以保證執行DDL表格的並發性,在EXCUTE階段可以正常提供寫服務,不發生堵塞,最後把row-log應用到新的表格上即可。 在5.7.17版本上測試的時候,發現,支援inplace且需要rebuild的DDL,在DDL期間,如果資料發生修改,都是直接重新整理到原來的idb檔案上,在測試環境中,給大表testddl刪除一個欄位,這個過程中INSERT 100w行記錄,可以看到原有ibd檔案增長了1G左右。
這裡有個疑問,未確定:row-log應該不是記錄行記錄的修改格式,因為這樣效率過慢,初步推測應該是僅記錄主鍵,然後根據主鍵尋找應用到新表上。
Online DDL可以有效改善DDL期間對資料庫的影響:
- Online DDL期間,查詢和DML操作在多數情況下可以正常執行,對錶格的鎖時間也會大大減少,儘可能的保證資料庫的可擴充性;
- 允許 in-place 操作的 DDL,避免重建表格佔用過多磁碟IO及CPU資源,減少對資料庫的整體負荷,使得在DDL期間,能夠鑑效組資料庫的高效能及高輸送量;
- 允許 in-place 操作的 DDL,比需要COPY到臨時檔案的操作要更少佔用buffer pool,避免以往DDL過程中效能的臨時下降,因為以前需要拷貝資料到暫存資料表,這個過程會佔用到buffer pool ,導致記憶體中的部分頻繁訪問的資料會被清理出去。
3 Online DDL涉及參數及選項
3.1 innodb_online_alter_log_max_size online ddl過程中發生DML時,會把資料修改情況記錄到row-log中,而row-log的大小,則由 innodb_online_alter_log_max_size設定,預設為128M,當表格較大且操作頻繁時,做DDL過程,可調大該參數,避免出現1799錯誤:
3.2 Online DDL文法
- Alter table …. , ALGORITHM [=] {DEFAULT|INPLACE|COPY}, LOCK [=] { DEFAULT| NONE| SHARED| EXCLUSIVE }
3.3 lock 選項 該選項用於調整DDL加鎖的方式,一共有4個選項。
LOCK=EXCLUSIVE
- 對整個表格添加獨佔鎖(x鎖),不允許查詢跟修改操作
LOCK=SHARED
- 對整個表格添加(s鎖),允許查詢操作,但是不支援資料變更操作
LOCK=NONE
- 不添加鎖,既允許查詢操作,也支援資料庫變更操作,該模式下並發最好
LOCK=DEFAULT
- 沒有指定LOCK的時候,則是預設為這個選項
- 根據DDL的操作類型,最小程度的加鎖,儘可能支援查詢及0DML操作
- 首先判斷當前操作是否可以使用NONE模式,如果不能,判斷是否可以使用SHARED模式,如果不能,判斷是否可以使用
EXCLUSIVE模式
3.4 ALGORITHM選項 DDL對資料庫效能的影響,很大程度受操作方式影響,比如是否是允許in-place,是否請求COPY操作,是否重建整個表格。比如
某個表格,修改或者添加預設值,並不會影響到表格內部的資料,所以1s內就可以完成;添加1個索引,需要幾十秒,應為需要新增索引資料頁跟修改frm檔案,但是不用rebuild表格式資料;而修改列的資料類型是,可能需要幾分鐘甚至更多時間,因為其需要重新Rebuild整個表格,執行期間對CPU,IO及buffer pool大量申請資源。 由DDL引起的INPLACE,COPY,REBUILD,可以通過指定ALGORITHM來選擇(注意並非所有DDL都支援in-place,詳見第4部分)
ALGORITHM=INPLACE
ALGORITHM=COPY
這兩個選項中,INPLACE要比COPY效能好,因為INPLACE既不會記錄UNDO LOG,也不寫REDO LOG,同時執行期間提供DML操作。
4 Online DDL支援文法情況 Online DDL對不同的DDL語句具有不同的執行規則,下面的表格將詳細描述各個文法對Online DDL的支援情況。列說明:
- In-Place?
- 說明: 是否支援
ALGORITHM=INPLACE
- Rebuilds Table?
- 說明:是否會重建表格
- 重建表格分為兩種方式:INPLACE跟COPY (原地修改或者複製到臨時檔案修改)
- 如果支援
ALGORITHM=INPLACE,那麼則是原地修改 INPLACE(淡黃色標記)
- 如果不支援
ALGORITHM=INPLACE,那麼則是COPY,拷貝到臨時檔案修改,並且不支援UPDATE DELETE INSERT操作(深褐色標記)
- Permits Concurrent DM
- 說明: 是否支援在DDL期間並發對該表格操作DML SQL
- 新增空間索引及全文索引時,不支援DML操作
- 當允許時,可以通過LOCK選項來控制是否要提供查詢或者修改操作
- LOCK=NONE,支援查詢跟UPDATE INSERT DELETE操作
- LOCK=SHARED,僅支援查詢
- Only Modifies Metadata?
- 是否只修改中繼資料
5 測試記錄
5.1 4個典型DDL操作分析 針對是否支援INPLACE、是否需要REBUILD及是否僅修改metadata來分類,選取每類一個DDL SQL來測試,見: 考慮到varchar變化長度的問題,這裡加測多這一項。
5.1.1 DDL測試內容
- 測試DB環境:表格名 tbddl,表格大小:1G ,500W行記錄
- 測試流程:開啟事務查詢,不提交 => 執行DDL => 提交查詢事務 => 執行DML =>開啟事務,執行DML不提交 =>提交DML
- 測試DDL SQL
- ALTER TABLE tbddl MODIFY COLUMN ItemId VARCHAR(20);
- ALTER TABLE tbddl ADD xinysu int;
- CREATE INDEX IX_PROID ON tbddl (providerid);
- ALTER TABLE tbddl ALTER COLUMN xinysu SET DEFAULT 123456;
- ALTER TABLE tbddl ALTER COLUMN ItemId VARCHAR(50); #UTF8字元集,3個位元組一個字元,50個字元則是150個位元組,小於256bytes
- ALTER TABLE tbddl ALTER COLUMN ItemId VARCHAR(100); #UTF8字元集,3個位元組一個字元,100個字元則是300個位元組,大於256bytes
- 測試關注點
- 啟動與關閉 old_alter_table
- prepare,commit階段的鎖是怎麼樣的
- excute階段的鎖是怎麼樣的
- 執行期間伺服器的效能情況(zabbix監控)
- 執行期間資料庫的並發情況(sysbench壓測)
5.1.2 DDL測試結論 測試過程中的,不在此描述,直接粘貼測試結果,感興趣的筒子們,可以自行測試。 VARCHAR按字元儲存,每個字元按照字元集來計算位元組,UTF8是3個位元組一個字元,當VARCHAR的位元組數<256byte時,只需要1個byte來儲存實際長度,當VARCHAR位元組數>=256時,則需要2個byte來儲存實際長度。舉例,UTF8字元集下的VARCHAR(10),假設儲存 N (0<=N<=10),則其佔用的位元組數為:N*3+1;UTF8字元集下的VARCHAR(100),假設儲存 N (0<=N<=100),則其佔用的位元組數為:N*3+2。 理解了這一點後,就可以理解 增長或縮短列的長度這列DDL的處理方式,假設列 VARCHAR(M)需要增大或縮小到VARCHAR(N),字元集是UTF8:
- 當 3M<256,3N<256,儲存長度的位元組不需要變化,都為1,則不需要變動行記錄,僅需要修改中繼資料;
- 當 3M>256,3N>256,儲存長度的位元組不需要變化,都為2, 則不需要變動行記錄,僅需要修改中繼資料;
- 當 3M<256,3N>256,儲存長度的位元組需要變化,由1變2, 則需要變動行記錄,Online DDL使用COPY TABLE方式;
- 當 3M>256,3N>256,儲存長度的位元組需要變化,由2變1,則需要變動行記錄,Online DDL使用COPY TABLE方式
5.2 同表格多個DDL處理 在Online DDL之前,都會習慣性的把同個表格的所有DDL語句合并為一個SQL語句,避免重複Rebuild、多次加鎖導致不提供DML時間長度增加等弊端。 但是,引入Online DDL後,需要有2點改觀:
- 除了個別不支援inplace的DDL語句,其他DDL語句在執行期間是不會加X鎖的,也就是表格仍然提供DML操作
- 鎖的粒度,同個DDL語句中,按照最進階別的鎖處理
- 維護的方便性
這裡建議按照3類來處理(
測試後的個人建議,僅供參考),見。
- 為啥copy table單獨出來呢?
- 因為這一類操作過程中是不允許DML操作的,建議把這一類的合成單獨一條DDL SQL執行,不與IPLACE的DDL SQL合并;
- 為啥iplace的要分為2類呢?
- 方便維護
- 僅中繼資料修改的DDL較快執行結束,為了方便管理維護,不至於所有SQL貼一堆,僅中繼資料修改的DDL語句歸一類
- 需要REBUILD的歸一類,避免重複rebuild,浪費磁碟IO跟CPU資源。
舉個例子,現在上線項目,需要對錶格tbddl,1個欄位由INT修改為VARCHAR,新增3個欄位,2個索引,2個預設值,2個列增長長度,單獨的SQL 為: alter table tbddl alter column ItemId varchar(20); ALTER TABLE tbddl ADD su int;ALTER TABLE tbddl ADD xin varchar(40);ALTER TABLE tbddl ADD yu int; CREATE INDEX IX_SU ON tbddl(SU);CREATE INDEX IX_yu ON tbddl(yu); ALTER TABLE tbddl ALTER COLUMN CreatedById SET DEFAULT 123456;ALTER TABLE tbddl ALTER COLUMN ItemID SET DEFAULT 654321; ALTER TABLE tbddl ALTER COLUMN CreatedByName VARCHAR(70);ALTER TABLE tbddl ALTER COLUMN ModifiedByName VARCHAR(100); 測試建議以下執行方式: alter table tbddl alter column ItemId varchar(20);ALTER TABLE tbddl ADD su int ,ADD xin varchar(40) ,ADD yu int,ALTER COLUMN ModifiedByName VARCHAR(100),add index ix_su(SU), add index ix_yu(yu);ALTER TABLE tbddl ALTER COLUMN CreatedById SET DEFAULT 123456,ALTER COLUMN ItemID SET DEFAULT 654321,ALTER COLUMN CreatedByName VARCHAR(70);
5.3 DDL執行期間資料庫效能異常處理 執行DDL期間,需要密切留意資料庫伺服器的CPU及IO情況,查看資料庫的串連池、慢查詢情況,如果期間發生了異常,應該如何處理呢? 假設現在給大表tbddl新增一列,新增的過程中,發現影響到線上業務,需要緊急停止,可以通過以下步驟操作:
- show processlist;
- kill 進程id;
具體見。
5.4 DDL執行期間資料庫宕機 DDL期間,如果發生宕機情況,會對資料庫的恢複啟動造成什麼影響呢?臨時檔案還存在嗎? 恢複過程中會自動執行未完成的DDL操作嗎?如果會,是怎麼處理?如果不會,再次手動建立會有影響嗎? 在5.7.17版本上,測試了4類DDL SQL,當DDL執行過程中,資料庫發生宕機,該DDL不會影響到資料庫的恢複啟動,同時,這個未完成的DDL語句不回自動執行,由於宕機過程中來不及清理臨時檔案,所以資料庫恢複後,臨時檔案依舊存在。DDL沒有commit,也就以為這資料庫的資料字典和表格的中繼資料沒有發生修改,再次手動執行DDL語句,並不會報衝突。(這點跟部分博文的分析有些出入,本次測試版本是5.7.17版本) 測試過程,這裡不做過多描述,直接貼上結論,感興趣的筒子們可以自行測試,歡迎討論。
5.5 DDL對主從的影響 DDL期間,假設該SQL執行的時間需要10h,除去waitting metadata lock的時間,rebuild或者inplace的時間需要5小時,那麼在從庫是單線程SQL THREAD應用relay log的情況,需要考慮從庫滯後的影響。 DDL在主庫執行情況,由於DDL語句沒有提交,所以不會同步到從庫上,從庫可以正常同步其他資料修改操作,這個環節沒有問題,但是當DDL在主庫提交後,該binlog日誌通過IO_THREAD傳送到從庫的RELAY LOG上,從庫的SQL_Thread是單線程工作,應用RELAY log的時候,至少需要5個小時,也就是這5個小時都用來執行RELAY LOG,無法同步主庫幾個小時內產生的BIN LOG,那麼,從庫就會發生嚴重的滯後情況,這個問題是否在可接受範圍內,需要納入到DDL執行造成的影響範圍內。 如果不能接受從庫這麼大的滯後,有什麼法子可以處理呢? 可以通過這個思路來,從庫啟動並行複製。啟動並行複製,需要注意這幾個問題:
- 使用注意
- 在從庫嚴重落後主庫的情況下,可以開啟該參數實現多線程並存執行
- 在業務量低的資料庫,不建議開啟,從庫同步效能反而會比拖累
- 配置注意
- 注意 master_info_repository relay_log_info_repository 設定為 table,預設是寫入mater_info.log 及 relay_info.log ,刷下這兩個檔案的頻率帶來的效能影響比較大,據 薑承驍薑老師 壓測,效能相差 20-50%間
- slave_parallel_workers 建議設定為從庫 核心 數
- slave_parallel_type
- database,不同庫的事務,觸發從庫並行回放
- logical_clock,組提交事務,按照組提交設定,從庫並行回放,如果是為了改善DDL的滯後情況,應使用這個配置。
6 Online DDL注意事項
- 磁碟空間
- rebuild 的時候,datadir空間是否足夠
- rebuild 的時候,innodb_online_alter_log_max_size是否足夠
- rebuild過程中,產生的DML涉及到行記錄變更日誌,是否足夠儲存
- inplace的時候,考慮tmpdir空間是否足夠
- ddl對從庫延遲的影響是否可以接受
- 主庫online DDL的過程中,由於沒有commit,所以其他並行作業可以正常同步到從庫
- 主庫commit後,DDL同步到從庫
- 由於從庫是單線程執行SQL_THREAD,假設DDL執行過程需要1個小時,那麼從庫將會滯後1小時+
- 是否允許從庫的滯後,如果不允許,可以通過並行複製來最佳化處理
- row-log會檢查重複值或者修改衝突嗎?
- copy table ,inplace下如何暫停DDL操作
- show full processlist;
- kill id; #( DDL SQL的id號)
- 這裡kill完後,仍然可以再次正常執行DDL,不會存在衝突,其建立的臨時idb及frm檔案會自動刪除
- copy table ,inplace下宕機
- 這兩種情況下宕機後,沒有完成的DDL語句不會繼續執行
- 但是,其產生的frm跟idb臨時檔案不會被刪除,可以手動刪除,也可以不手動刪除,即使不刪除,也不會影響再次執行DDL
- 但建議mysql服務後,刪除無用的臨時檔案
- 同個表格多個DDL語句,不要一個個執行
- 請按照是否支援inplace及是否需要rebuild分類合并執行
- 如何查看ddl進度(未解決)
- 如果有rebuild,則是通過ibd檔案的增長來評估;但是如果是inplace,如何查看呢?有沒有什麼比較好的方式查看?performance_schema是否有提供相應的查詢方式?
MySQL Online DDL的改進與應用