大家知道,互聯網業務是典型的OLTP(online transaction process)應用,這種應用訪問數據庫的特點是大量的短事務高並發運行。因此任何限制高並發的動作都是不可接受的,甚至會給網站帶來災難。對於數據庫而言,高並發通常與事務ACID是一對矛盾體,為了保證事務的ACID特性,必需用一定的手段來控制並發,比如基於鎖的並發控制,亦或是基於MVCC的並發控制。基於MVCC的並發控制只是一定程度上解決了讀不阻塞的問題,但對於DML或DDL依然通過鎖機制來保證事務的隔離性。
所有數據庫操作中DDL的鎖粒度是最大的,通過包括元數據鎖和表對象鎖。常見的DDL包括alter,create,drop等,對於create,drop而言,通常執行過程很快,因此影響比較少,而對於alter操作,尤其是對大表的alter,這個過程可能持續時間很長,由於變更過程中,表對象的DML操作會阻塞,因此一個alter操作很有可能導致前台的網站應用出現大量的數據庫訪問超時情況。那麼怎麼解呢?第一種是alter操作不上鎖,從而不影響寫操作,若不行退而求其次,將alter操作的時間想辦法縮短,減少不可訪問表的時間。
對於mysql數據庫而言,解決alter的問題也有一個過程,直到5.6才推出了online ddl功能。5.5版本通過FIC(fast index creation),提高了alter操作中加索引和刪索引的速度,5.6的online ddl則優化更多,增加了更多的“在線”操作。在介紹FIC和online ddl的原理之前,我們先來看看有哪些常見的alter操作,參見表1
alter動作
說明
Add index,drop index
增加、刪除、修改二級索引
Add column,drop column
增加、刪除、修改列
Add primary key,drop primary key
增加、刪除、修改主鍵索引
Set character set utf8/gbk
修改字符集、修改存儲引擎
Optimize table
重組表
表1
那麼針對以上幾種常見的場景,我們看到FIC和online ddl到底做了什麼,它們實現的原理是怎樣的,下文的分析都是基於innodb表。
對於一般的alter操作而言,它的原理基本是這樣的,假設需要對A表做表結構變更,首先創建一個目的表結構的臨時表B;其次是鎖表,將數據從A表拷貝到B表;最後是將B表rename成A表,釋放鎖。
FIC針對加索引和刪索引做了優化,因為這種情景下,innodb的表存儲結構沒有變,只是多了或少了索引,因此沒有必要進行全表拷貝,直接增加或刪除索引即可,這樣就減少了拷貝表的時間,同時也減少了鎖表時間。對於需要該表存儲結構的alter操作,FIC則無能無力。由於mysql遲遲不出現Online ddl的版本,FIC的場景不通用,並且依然會阻塞寫,業務不可接受。沒有辦法,很多時候做表結構變更需要在業務低峰期(凌晨),通過主備庫切換的方式去做,真是苦了DBA的童鞋們。
還好,在mysql5.6出現之前,percona公司提供了“在線”表結構變更的工具pt-online-schema-change,這個工具給dba童鞋們帶來了福音。工具的核心原理是通過insert… select…語句進行一次全量拷貝,通過觸發器記錄表結構變更過程中產生的增量,從而達到表結構變更的目的。假設對A表進行變更,主要步驟如下:
通過這個方式後,執行alter操作時,不再阻塞讀和寫,而且支持的alter語句也更廣泛,比如表1列出來的幾種情況都可以支持,除了Optimize table以外。
Mysql online ddl的原理實質與pt-online-schema-change工具原理相同,只不過將這一過程封裝在mysql內部了。雖然如此,這種方式也有一定的弊端和限制,比如需要有主鍵,拷貝表速度不如源生鎖表拷貝表快等。
最後,舉一個例子說明alter操作在5.5和5.6對於DML的影響。從表2可以看到,5.5和5.6中,查詢和更新都會阻塞alter操作;若有alter操作,5.5版本中,alter不會阻塞讀,但會阻塞寫;5.6版本中,alter不會阻塞讀和寫。