GitHub 開源的 MySQL 在線更改 Schema 工具【轉】

本文來自:http://www.javashuo.com/article/p-bkposbdu-mh.htmlhtml

原文:gh-ost: GitHub's online schema migration tool for MySQLmysql

 

MySQL在線更改schema的工具不少,如Percona的pt-online-schema-change、 Facebook的 OSCLHM 等,但這些都是基於觸發器(Trigger)的,今天我們介紹的 gh-ost 號稱是不須要觸發器(Triggerless)支持的在線更改表結構的工具。git

圖片描述

本文先介紹一下當前業界已經存在的這些工具的使用場景和原理,而後再詳細介紹 gh-ost 的工做原理和特性。github

今天咱們開源了GitHub內部使用的一款 不須要觸發器支持的 MySQL 在線更改表結構的工具 gh-ostsql

開發 gh-ost 是爲了應付GitHub在生產環境中面臨的持續的、不斷變化的在線修改表結構的需求。gh-ost 經過提供低影響、可控、可審計和操做友好的解決方案改變了現有的在線遷移表工具的工做模式。數據庫

MySQL表遷移及結構更改操做是業界衆所周知的問題,2009年以來已經能夠經過在線(不停服務)變動的工具來解決。迅速增加,快速迭代的產品每每須要頻繁的需改數據庫的結構。增長/更改/刪除/ 字段和索引等等,這些操做在MySQL中默認都會鎖表,影響線上的服務。 向這種數據庫結構層面的變動咱們天天都會面臨屢次,固然這種操做不該該影響用戶的正常服務。segmentfault

在開始介紹 gh-ost 工具以前,我們先來看一下當前現有的這些工具的解決方案。服務器

在線修改表結構,已存在的場景

現在,在線修改表結構能夠經過下面的三種方式來完成:網絡

  • 在從庫上修改表結構,操做會在其餘的從庫上生效,將結構變動了的從庫設置爲主庫架構

  • 使用 MySQL InnoDB 存儲引擎提供的在線DDL特性

  • 使用在線修改表結構的工具。如今最流行的是 pt-online-schema-change 和 Facebook 的 OSC;固然還有 LHM 和比較原始的 oak-online-alter-table 工具。

其餘的還包括 Galera 集羣的Schema滾動更新,以及一些其餘的非InnoDB的存儲引擎等待,在 GitHub 咱們使用通用的 主-從 架構 和 InnoDB 存儲引擎。

爲何咱們決定開始一個新的解決方案,而不是使用上面的提到的這些呢?現有的每種解決方案都有其侷限性,下文會對這些方式的廣泛問題簡單的說明一下,但會對基於觸發器的在線變動工具的問題進行詳細說明。

  • 基於主從複製的遷移方式須要不少的前置工做,如:大量的主機,較長的傳輸時間,複雜的管理等等。變動操做須要在一個指定的從庫上或者基於sub-tree的主從結構中執行。須要的狀況也比較多,如:主機宕機、主機從早先的備份中恢復數據、新主機加入到集羣等等,全部這些狀況都有可能對咱們的操做形成影響。最要命的是可能這些操做一天要進行不少次,若是使用這種方法咱們操做人員天天的效率是很是高的(譯者注:現現在不多有人用這種方式了吧)

  • MySQL針對Innodb存儲引擎的在線DDL操做在開始以前都須要一個短期排它鎖(exclusive)來準備環境,因此alter命令發出後,會首先等待該表上的其它操做完成,在alter命令以後的請求會出現等待waiting meta data lock。一樣在ddl結束以前,也要等待alter期間全部的事務完成,也會堵塞一小段時間,這對於繁忙的數據庫服務來講危險係數是很是高的。另外DDL操做不能中斷,若是中途kill掉,會形成長時間的事務回滾,還有可能形成元數據的損壞。它操做起來並不那麼的Nice,不能限流和暫停,在大負載的環境中甚至會影響正常的業務。

  • 咱們用了不少年的 pt-online-schema-change 工具。然而隨着咱們不斷增加的業務和流量,咱們遇到了不少的問題,咱們必須考慮在操做中的哪些 危險操做 (譯者注:pt工具集的文檔中常常會有一些危險提示)。某些操做必須避開高峯時段來進行,不然MySQL可能就掛了。全部現存的在線表結構修改的工具都是利用了MySQL的觸發器來執行的,這種方式有一些潛藏的問題。

基於觸發器的在線修改有哪些問題呢?

全部在線表結構修改工具的操做方式都相似:建立與原表結構一致的臨時表,該臨時表已是按要求修改後的表結構了,緩慢增量的從原表中複製數據,同時記錄原表的更改(全部的 INSERT, DELETE, UPDATE 操做) 並應用到臨時表。當工具確認表數據已經同步完成,它會進行替換工做,將臨時表改名爲原表。

pt-online-schema-change, LHMoak-online-alter-table 這些工具都使用同步的方式,當原表有變動操做時利用一些事務的間隙時間將這些變化同步到臨時表。Facebook 的工具使用異步的方式將變動寫入到changelog表中,而後重複的將changelog表的變動應用到臨時表。全部的這些工具都使用觸發器來識別原表的變動操做。

當表中的每一行數據有 INSERT, DELETE, UPDATE 操做時都會調用存儲的觸發器。一個觸發器可能在一個事務空間中包含一系列查詢操做。這樣就會形成一個原子操做不單會在原表執行,還會調用相應的觸發器執行多個操做。

在基於觸發器遷移實踐中,遇到了以下的問題:

  • 觸發器是以解釋型代碼的方式保存的。MySQL 不會預編譯這些代碼。 會在每次的事務空間中被調用,它們被添加到被操做的表的每一個查詢行爲以前的分析和解釋器中。

  • 鎖表:觸發器在原始表查詢中共享相同的事務空間,而這些查詢在這張表中會有競爭鎖,觸發器在另一張表會獨佔競爭鎖。在這種極端狀況下,同步方式的鎖爭奪直接關係到主庫的併發寫性能。以咱們的經驗來講,在生產環境中當競爭鎖接近或者結束時,數據庫可能會因爲競爭鎖而被阻塞住。觸發鎖的另外一個方面是建立或銷燬時所須要的元數據鎖。咱們曾經遇到過在繁忙的表中當表結構修改完成後,刪除觸發器可能須要數秒到分鐘的時間。

  • 不可信:當主庫的負載上升時,咱們但願降速或者暫停操做,但基於觸發器的操做並不能這麼作。雖然它能夠暫停行復制操做,但卻不能暫停出觸發器,若是刪除觸發器可能會形成數據丟失,所以觸發器須要在整個操做過程當中都要存在。在咱們比較繁忙的服務器中就遇到過因爲觸發器佔用CPU資源而將主庫拖死的例子。

  • 併發遷移:咱們或者其餘的人可能比較關注多個同時修改表結構(不一樣的表)的場景。鑑於上述觸發器的開銷,咱們沒有興趣同時對多個表進行在線修改操做,咱們也不肯定是否有人在生產環境中這樣作過。

  • 測試:咱們修改表結構可能只是爲了測試,或者評估其負載開銷。基於觸發器的表結構修改操做只能經過基於語句複製的方式來進行模擬實驗,離真實的主庫操做還有必定的距離,不能真實的反映實際狀況。

gh-ost

gh-ost GitHub 的在線 Schema 修改工具,下面工做原理圖:

圖片描述

gh-ost 具備以下特性:

  • 無觸發器

  • 輕量級

  • 可暫停

  • 可動態控制

  • 可審計

  • 可測試

  • 值得信賴 

無觸發器

gh-ost 沒有使用觸發器。它經過分析binlog日誌的形式來監聽表中的數據變動。所以它的工做模式是異步的,只有當原始表的更改被提交後纔會將變動同步到臨時表(ghost table)

gh-ost 要求binlog是RBR格式 ( 基於行的複製);然而也不是說你就不能在基於SBR(基於語句的複製)日誌格式的主庫上執行在線變動操做。其實是能夠的。gh-ost 能夠將從庫的 SBR日誌轉換爲RBR日誌,只須要從新配置就能夠了。

輕量級

因爲沒有使用觸發器,所以在操做的過程當中對主庫的影響是最小的。固然在操做的過程當中也不用擔憂併發和鎖的問題。 變動操做都是以流的形式順序的寫到binlog文件中,gh-ost只是讀取他們並應用到gh-ost表中。實際上,gh-ost 經過讀取binlog的寫事件來進行順序的行復制操做。所以,主庫只會有一個單獨鏈接順序的將數據寫入到臨時表(ghost table)。這和ETL操做有很大的不一樣。

可暫停

全部的寫操做都是由gh-ost控制的,而且以異步的方式讀取binlog,當限速的時候,gh-ost能夠暫停向主庫寫入數據,限速意味着不會在主庫進行復制,也不會有行更新。當限速時gh-ost會建立一個內部的跟蹤(tracking)表,以最小的系統開銷向這個表中寫入心跳事件

gh-ost 支持多種方式的限速:

  • 負載: 爲熟悉 pt-online-schema-change 工具的用戶提供了相似的功能,能夠設置MySQL中的狀態閾值,如 Threads_running=30

  • 複製延遲: gh-ost 內置了心跳機制,能夠指定不一樣的從庫,從而對主從的複製延遲時間進行監控,若是達到了設定的延遲閾值程序會自動進入限速模式。

  • 查詢: 用戶能夠能夠設置一個限流SQL,好比 SELECT HOUR(NOW()) BETWEEN 8 and 17 這樣就能夠動態的設置限流時間。

  • 標示文件: 能夠經過建立一個標示文件來讓程序限速,當刪除文件後能夠恢復正常操做。

  • 用戶命令: 能夠動態的鏈接到 gh-ost (下文會提到) 經過網絡鏈接的方式實現限速。

可動態控制

如今的工具,當執行操做的過程當中發現負載上升了,DBA不得不終止操做,從新配置參數,如 chunk-size,而後從新執行操做命令,咱們發現這種方式效率很是低。

gh-ost 能夠經過 unix socket 文件或者TCP端口(可配置)的方式來監聽請求,操做者能夠在命令運行後更改相應的參數,參考下面的例子:

  • echo throttle | socat - /tmp/gh-ost.sock 打開限速,一樣的,可使用 no-throttle 來關閉限流。

  • 改變執行參數: chunk-size=1500, max-lag-millis=2000, max-load=Thread_running=30 這些參數均可以在運行時變動。

可審計

一樣的,使用上文提到的程序接口能夠獲取 gh-ost 的狀態。gh-ost 能夠報告當前的進度,主要參數的配置以及當前服務器的標示等等。這些信息均可以經過網絡接口取到,相對於傳統的tail日誌的方式要靈活不少。

可測試

由於日誌文件和主庫負載關係不大,所以在從庫上執行修改表結構的操做能夠更真實的體現出這些操做鎖產生的實際影響。(雖然不是十分理想,後續咱們會作優化工做)。

gh-ost 內建支持測試功能,經過使用 --test-on-replica 的參數來指定: 它能夠在從庫上進行變動操做,在操做結束時gh-ost 將會中止複製,交換表,反向交換表,保留2個表並保持同步,中止複製。能夠在空閒時候測試和比較兩個表的數據狀況。

這是咱們在GitHub的生產環境中的測試:咱們生產環境中有多個從庫;部分從庫並非爲用戶提供服務的,而是用來對全部表運行的連續覆蓋遷移測試。咱們生產環境中的表,小的可能沒有數據,大的會達到數百GB,咱們只是作個標記,並不會正在的修改表結構(engine=innodb)。當每個遷移結束後會中止複製,咱們會對原表和臨時表的數據進行完整的checksum確保他們的數據一致性。而後咱們會恢復複製,再去操做下一張表。咱們的生產環境的從庫中已經經過 gh-ost 成功的操做了不少表。

值得信賴

上文提到說了這麼多,都是爲了提升你們對 gh-ost 的信任程度。畢竟在業界它仍是一個新手,相似的工具已經存在了不少年了。

  • 在第一次試手以前咱們建議用戶先在從庫上測試,校驗數據的一致性。咱們已經在從庫上成功的進行了數以千計的遷移操做。

  • 若是在主庫上使用 gh-ost 用戶能夠實時觀察主庫的負載狀況,若是發現負載變化很大,能夠經過上文提到的多種形式進行限速,直到負載恢復正常,而後再經過命令微調參數,這樣能夠動態的控制操做風險。

  • 若是遷移操做開始後預完成計時間(ETA)顯示要到夜裏2點才能完成,結束時候須要切換表,你是否是要留下來盯着?你能夠經過標記文件讓gh-ost推遲切換操做。gh-ost 會完成行復制,但並不會切換表,它會持續的將原表的數據更新操做同步到臨時表中。你次日來到辦公室,刪除標記文件或者經過接口 echo unpostpone 告訴gh-ost開始切換表。咱們不想讓咱們的軟件把使用者綁住,它應該是爲咱們拜託束縛。

  • 說到 ETA, --exact-rowcount 參數你可能會喜歡。相對於一條漫長的 SELECT COUNT(*) 語句,gh-ost 會預估出遷移操做所須要花費的時間,還會根據當前遷移的工做情況更新預估時間。雖然ETA的時間隨時更改,但進度百分比的顯示是準確的。

gh-ost 操做模式

gh-ost 能夠同時鏈接多個服務器,爲了獲取二進制的數據流,它會做爲一個從庫,將數據從一個庫複製到另一個。它有各類不一樣的操做模式,這取決於你的設置,配置,和要運行遷移環境。

圖片描述

a. 鏈接到從庫,在主庫作遷移

這是 gh-ost 默認的工做方式。gh-ost 將會檢查從庫狀態,找到集羣結構中的主庫並鏈接,接下來進行遷移操做:

  • 行數據在主庫上讀寫

  • 讀取從庫的二進制日誌,將變動應用到主庫

  • 在從庫收集表格式,字段&索引,行數等信息

  • 在從庫上讀取內部的變動事件(如心跳事件)

  • 在主庫切換表

若是你的主庫的日誌格式是 SBR,工具也能夠正常工做。但從庫必須啓用二級制日誌(log_bin, log_slave_updates) 而且設置 binlog_format=ROW ( gh-ost 是讀取從庫的二級制文件)。

若是直接在主庫上操做,固然也須要二進制日誌格式是RBR。

b. 鏈接到主庫

若是你沒有從庫,或者不想使用從庫,你能夠直接在主庫上操做。gh-ost 將會直接在主庫上進行全部操做。你須要持續關注複製延遲問題。

  • 你的主庫的二進制日誌必須是 RBR 格式。

  • 在這個模式中你必須指定 --allow-on-master 參數

c. 在從庫遷移/測試

該模式會在從庫執行遷移操做。gh-ost 會簡單的鏈接到主庫,此後全部的操做都在從庫執行,不會對主庫進行任何的改動。整個操做過程當中,gh-ost 將控制速度保證從庫能夠及時的進行數據同步

  • --migrate-on-replica 表示 gh-ost 會直接在從庫上進行遷移操做。即便在複製運行階段也能夠進行表的切換操做。

  • --test-on-replica 表示 遷移操做只是爲了測試在切換以前複製會中止,而後會進行切換操做,而後在切換回來,你的原始表最終仍是原始表。兩個表都會保存下來,複製操做是中止的。你能夠對這兩個表進行一致性檢查等測試操做。

gh-ost at GitHub

咱們已經在全部線上全部的數據庫在線操做中使用了gh-ost ,咱們天天都須要使用它,根據數據庫修改需求,可能天天要運行屢次。憑藉其審計和控制功能咱們已經將它集成到了ChatOps流程中。咱們的工程師能夠清醒的瞭解到遷移操做的進度,並且能夠靈活的控制其行爲。

開源

gh-ost 在MIT的許可下發布到了開源社區

雖然gh-ost在使用中很穩定,咱們還在不斷的完善和改進。咱們將其開源也歡迎社會各界的朋友可以參與和貢獻。隨後咱們會發布 貢獻和建議的頁面。

咱們會積極的維護 gh-ost 項目,同時但願廣大的用戶能夠嘗試和測試這個工具,咱們作了很大努力使之更值得信賴。

相關文章
相關標籤/搜索