今天Github正式宣布以開(kāi)源的方式發(fā)布 gh-ost :GitHub的MySQL無(wú)觸發(fā)器在線更改表定義工具!
gh-ost是GitHub最近幾個(gè)月開(kāi)發(fā)出來(lái)的,目的是解決一個(gè)經(jīng)常碰到的問(wèn)題:不斷變化的產(chǎn)品需求會(huì)不斷要求更改MySQL表結(jié)構(gòu)。gh-ost通過(guò)一種影響小、可控制、可審計(jì)、操作簡(jiǎn)單的方案來(lái)改變線上表結(jié)構(gòu)。
MySQL表定義修改是個(gè)眾所周知的難題,從2009年開(kāi)始大家都通過(guò)在線表定義修改工具來(lái)解決??焖僭鲩L(zhǎng)和變化的業(yè)務(wù)需求經(jīng)常會(huì)要求更改數(shù)據(jù)庫(kù)表結(jié)構(gòu)。增加、改變、刪除字段和索引等操作在默認(rèn)情況下都會(huì)堵塞住數(shù)據(jù)操作。Github生產(chǎn)系統(tǒng)每天都會(huì)改好幾張表定義,非常希望能把對(duì)用戶的影響減少到最小。
在介紹gh-ost之前,請(qǐng)先了解一下各種現(xiàn)有方案,以及為什么要自己開(kāi)發(fā)一個(gè)新工具。
已有的在線修改表定義方案
目前,在線修改表定義的任務(wù)主要是通過(guò)這三種途徑完成的:
在從庫(kù)上修改表定義,修改之后再提升為新的主庫(kù)。
通過(guò)MySQL的InnoDB在線DDL功能。
使用修改表定義工具?,F(xiàn)在最流行的是 Percona公司的pt-online-schema-change 和 Facebook的OSC ,也有人使用 LHM 或最早的 oak-online-alter-table 。
還有其它的比如Galera Cluster的Rolling Schema Upgrade,或者非InnoDB引擎的表等。GitHub的MySQL數(shù)據(jù)庫(kù)用的都是主從復(fù)制架構(gòu),使用可靠的InnoDB引擎。
為什么Github決定去設(shè)計(jì)一個(gè)新解決方案,而不是直接從上面的幾種方案中選一個(gè)用?現(xiàn)有的解決方案都有著自身的局限性,下面就對(duì)它們的不足之處做個(gè)簡(jiǎn)單分析,主要深入地分析基于觸發(fā)器的在線修改表定義工具的不足之處。
在從庫(kù)上修改表定義的方案需要付出許多運(yùn)維代價(jià),這需要更多的服務(wù)器、更長(zhǎng)的完成時(shí)間和更復(fù)雜的管理工作。修改操作是直接應(yīng)用在具體的某個(gè)從庫(kù)或者整個(gè)拓?fù)浼軜?gòu)的一些子樹(shù)上。服務(wù)器宕機(jī)、從庫(kù)數(shù)據(jù)不夠新、新部署的服務(wù)器等各種問(wèn)題都需要有非常嚴(yán)密的跟蹤系統(tǒng)來(lái)跟進(jìn)單個(gè)數(shù)據(jù)庫(kù)上的操作。一個(gè)改變操作可能會(huì)需要多次反復(fù),也就需要更長(zhǎng)時(shí)間。而把一個(gè)從庫(kù)升為主庫(kù)也會(huì)導(dǎo)致短暫的停服。如果同時(shí)需要做多個(gè)更改就更難協(xié)調(diào)。由于每天都要改好幾張表,所以在考慮解決方案時(shí)不希望有這樣的管理開(kāi)銷。
MySQL的InnoDB在線DDL只能是在你敲命令的那個(gè)MySQL上才是“在線”修改的。二進(jìn)制文件中的日志把修改操作序列化了,從庫(kù)應(yīng)用日志時(shí)會(huì)導(dǎo)致復(fù)制延遲。但如果嘗試在每個(gè)從庫(kù)上挨個(gè)去改的話又會(huì)導(dǎo)致上面分析的管理代價(jià)。而且DDL還是不可中斷的,要是在修改時(shí)把操作殺掉的話還需要更長(zhǎng)的時(shí)間去回滾,甚至導(dǎo)致數(shù)據(jù)字典崩潰。這種方案也不“友好”,在系統(tǒng)負(fù)載高時(shí)也不能限速或者暫停。這樣的操作還有可能會(huì)耗盡你的系統(tǒng)資源。
Github用了pt-online-schema-change好幾年了??墒?,當(dāng)生產(chǎn)系統(tǒng)數(shù)據(jù)增多、業(yè)務(wù)壓力增大之后就碰到了越來(lái)越多的問(wèn)題,甚至到了許多修改操作都被認(rèn)為是“危險(xiǎn)操作”的地步。有一些操作只敢在非業(yè)務(wù)高峰期或者周末才敢執(zhí)行,其它的總是會(huì)導(dǎo)致MySQL停止服務(wù)。所有現(xiàn)有的在線修改表定義工具都是用MySQL觸發(fā)器來(lái)遷移數(shù)據(jù)的,因此本身就存在著一些問(wèn)題。
基于觸發(fā)器的解決方案有什么不好?
所有在線修改表定義的工具運(yùn)行原理都是相似的:創(chuàng)建一張與原始表定義相同的臨時(shí)表,趁上面沒(méi)有數(shù)據(jù)時(shí)先改好表定義,然后慢慢地、用增量方式把數(shù)據(jù)從原始表拷到臨時(shí)表,同時(shí)不斷的把進(jìn)行中的原始表上的數(shù)據(jù)操作(所有應(yīng)用在原始表上的插入、刪除、更新操作)也應(yīng)用過(guò)來(lái)。當(dāng)工具把所有數(shù)據(jù)都拷貝完畢,兩邊數(shù)據(jù)同步了之后,它就用這張臨時(shí)表來(lái)替代原始表。修改過(guò)程就結(jié)束了。
象pt-online-schema-change、LHM和oak-online-alter-table這些工具用的都是同步復(fù)制的方式,對(duì)表的每一條數(shù)據(jù)修改都會(huì)立刻在同一個(gè)事務(wù)里就應(yīng)用到臨時(shí)表上。Facebook的工具用的則是異步模式,先把修改操作都記在一張修改日志表里,然后再取出來(lái)執(zhí)行,把修改操作應(yīng)用到臨時(shí)表上。這些工具全都使用觸發(fā)器來(lái)提取那些應(yīng)用在目標(biāo)表上的操作。
觸發(fā)器都是存儲(chǔ)過(guò)程,在表上有插入、刪除、修改操作時(shí)就會(huì)被觸發(fā)。觸發(fā)器可能包括好多條語(yǔ)句,這些語(yǔ)句都是和引發(fā)觸發(fā)器的那條操作在相同的事務(wù)空間內(nèi)運(yùn)行的,因此保證了這些操作的原子性。