在線數據遷移經驗:如何為正在飛行的飛機更換引擎
原文 http://www.infoq.com/cn/articles/online-data-migration-experience
在線數據遷移,是指將正在提供線上服務的數據,從一個地方遷移到另一個地方,整個遷移過程中要求不停機,服務不受影響。根據數據所處層次,可以分為cache遷移和存儲遷移;根據數據遷移前后的變化,又可以分為平移和轉移。
平移是指遷移前后數據組織形式不變,比如Mysql從1個實例擴展為4個實例,Redis從4個端口擴展到16個端口,HBase從20臺機器擴 展到 30臺機器等等。如果在最初的設計里就為以后的擴容縮容提供了方便,那么數據遷移工作就會簡單很多,比如Mysql已經做了分庫分表,擴展實例的時候,只 需要多做幾個從庫,切換訪問,最后將多余的庫表刪除即可。更進一步,在實現上已經做到全自動數據遷移,如 HBase,就更簡單了:添加機器,手工修改配置或者系統自動發現,然后,沏一杯咖啡,等待系統完成遷移。
轉移是指數據遷移前后,數據組織形式發生了變化。多年前,某社交平臺曾經為ID升級做過一次數據遷移,將ID由最初的自增算法修改為巧妙設計的UUID算 法,這次遷移最大的挑戰是要修改數據的主鍵,主鍵本來是數據的唯一標識,它發生變化,也就意味著原來的數據不復存在,新的數據憑空產生,對于整個系統中所 有業務流程、周邊配套、上下游部門都會產生巨大的兼容性挑戰。不過大部分數據遷移項目都不會修改主鍵,甚至不會修改數據本身,改變的只是數據的組織形式。 比如某社交平臺計數器原本為了節約存儲空間,使用redis hash進行存儲,后來為了提升批量查詢的性能,遷移成 KV 形式;又比如某社交平臺的轉發列表和粉絲列表,最初都使用Mysql存儲,后來為了更好的擴展性和成本,都遷移到HBase存儲。
在線數據遷移最大的挑戰是如何保證遷移過程服務不受影響。很多人將其比喻成“飛行過程中換發動機”“給行駛的汽車換輪胎”,但實際上并沒有那么困難,一個入行一兩年的技術人員,遵從一些經驗指導,完全可以完成。下面就跟大家分享一下個人在這方面的一些經驗,作為拋磚引玉。
在線數據遷移一般分為四個步驟:一,上線雙寫,即同時寫入新舊兩種數據;二,歷史數據離線搬遷,即離線將歷史存量數據從舊系統搬到新系統;三,切 讀,即將讀請求路由到新系統;四,清理沉淀,包括清理舊的數據,回收資源,及清理舊的代碼邏輯,舊的配套系統等等,將遷移過程中的經驗教訓進行總結沉淀, 將過程中開發或使用的工具進行通用化改造,以備下次使用。注意,某些情況下,步驟一和步驟二也可能倒過來,先做歷史數據搬遷,然后再寫入新數據,這時候就 需要謹慎的處理搬遷這段時間里產生的新數據,一般使用 queue 緩存寫入的方式,稱為“追數據”。
圖1:在線數據遷移步驟示意圖
下面以某社交平臺粉絲列表從Mysql遷移到HBase為例子,展開來講講每個步驟具體實施、可能的問題及對策。
在遷移之前,根據以往的經驗制定了更詳細的流程,如圖:
圖2:粉絲列表遷移到HBase工作流程圖
上線雙寫
編寫雙寫的代碼邏輯之前,首先要根據業務規則和性能指標確定HBase的表結構和主鍵設計。對于列表類的需求,HBase有兩種典型的用法,一種 是高表模式,與傳統的Mysql模式非常類似,列表中的每一項存一行,每一行有固定的屬性列;另一種是寬表模式,一個列表存一行,列表中的每一項存成一個 單獨的列,各種屬性都打包到列內部的value中。如圖:
圖3:粉絲列表業務分別使用HBase高表模式和寬表模式存儲示意圖
高表模式的好處在于與Mysql類似,各種業務邏輯的實現也比較像,認知和改造成本較低,劣勢在于因為HBase的實現機制導致單個列表可能被分 別存儲在多個不同的Region里,查詢的性能較差。而寬表的優劣勢正好與高表相反。在高并發大流量系統中,技術方案很多特性都可以妥協,但唯獨性能永遠 是不能妥協的,所以我們選擇寬表模式。
很多高并發系統都采用上行異步化,通過將操作轉化為消息,寫入消息隊列,后臺異步處理的方式來削峰填谷,并獲得更好的可用性。大部分消息隊列都支 持單個消息被多個業務模塊重復處理,并支持串聯和并聯。所以在這里我們將寫入HBase的代碼邏輯單獨封裝到一個模塊中,將它配置為與寫入舊Mysql代 碼串聯或并聯即可。
為了支持消息異步處理的重試機制,建議將業務模塊設計成具有冪等特性,即同一條消息可以重試多次,而不會破壞最終的結果。有一些模塊,如計數器, 提醒等,業務本身不支持重試,可以通過“重復消息檢測模塊”為它們提供短時間內的重試支持。大部分Mysql存儲都通過主鍵或者單獨的Unique key索引來達到冪等要求,相應的,HBase高表模式通過主鍵保證,寬表模式通過column qualifier保證。在粉絲列表遷移過程中,因為column qualifier不能保證冪等,導致數據一致性無法達到要求,最后也是通過引入額外的重復消息檢測模塊解決。
另外,HBase當前不提供二級索引、覆蓋索引、join、order by等Mysql高級查詢功能,需要在遷移之前做好評估,確定新方案能夠支持所有的業務特性。比如粉絲列表一般都是查詢最新的5000個粉絲,但如果還要 支持查詢最初100個粉絲列表的功能,就會比較費勁。
上線雙寫完成后,需要對雙寫的數據進行一致性校驗。數據一致性校驗需要從兩個維度進行:存儲維度和業務維度。存儲維度是指直接取Mysql和 HBase里的數據進行對比;業務維度是指從最終用戶看到的數據維度進行校驗,即訪問粉絲列表頁面,看結果是否與原來一致。大型系統的數據一致性校驗建議 及格線是6個9,即99.9999%,也就是說每一百萬條數據中,差別不能超過1條。
歷史數據搬遷
上線雙寫并校驗確認通過后,就可以開始搬遷歷史數據了。
搬遷歷史數據的步驟中,最大的困難是保證搬遷過程與線上業務寫入互不干擾。對于列表類功能,最大的干擾是來自于這樣一種業務場景:搬遷程序從 Mysql中select出來一個列表,在插入到HBase之前,這個列表發生了變化。如果是增加一個元素,由于HBase的冪等保證,最終結果并不會產 生偏差,但如果是刪除一個或多個元素,那么最終會表現為HBase中刪除操作未生效,因為線上業務執行完刪除操作后,搬遷程序又執行了插入操作。本質上, 這是因為我們在這樣的數據量規模下不能使用事務引起的,如果引入事務,能夠解決這個問題,但同時也會將搬遷耗時從幾天延長到幾周甚至幾個月。為了解決這個 問題,可以通過引入輕量級的Memcache鎖來模擬Serializable級別的事務隔離。
歷史數據搬遷完成后也需要進行一致性校驗。實際上,建議在搬遷全量數據之前,先搬遷部分數據,并進行一致性校驗。部分數據一致性校驗通過后,再對全量數據進行搬遷。這種方式可以極大的節約搬遷時間,降低因為搬遷流程或代碼不完善導致的延期風險。
切讀
全量數據搬遷并校驗完成后,即可以進行讀請求切換了。通用的切換方式是在代碼中埋入開關,通過 Config Service 或類似機制進行切換操作。切換的流程為:Tcpcopy環境 --> 線上環境 uid 白名單(內部工程師)--> 線上環境百分比灰度 0.01%,1%,10% --> 線上環境全量。tcpcopy 環境用來驗證代碼在線上環境是否正常,uid白名單用來驗證功能是否正常,百分比灰度用來驗證性能和資源壓力是否正常,所有驗證都通過后,最后才進行全量 切換。一般這個過程會持續一周到兩周。
清理沉淀
切讀完成后,整個數據遷移過程可以認為已經完成了。但項目工作并沒有完結,舊的邏輯代碼清理,舊的配套系統下線,舊資源回收,以及最重要的一個環節:經驗教訓總結、分享,流程完善,工具通用化改造。
在線數據遷移并不是一項需要高深技術的工作,它更多需要的是對業務邏輯的把控,對操作流程的理解,對新舊系統特性的掌握,以及對細節的敬畏之心。