線上資料遷移經驗:如何為正在飛行的飛機更換引擎

InfoQ - 唐福林發表於2015-02-15

線上資料遷移,是指將正在提供線上服務的資料,從一個地方遷移到另一個地方,整個遷移過程中要求不停機,服務不受影響。根據資料所處層次,可以分為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白名單用來驗證功能是否正常,百分比灰度用來驗證效能和資源壓力是否正常,所有驗證都通過後,最後才進行全量切換。一般這個過程會持續一週到兩週。

清理沉澱

切讀完成後,整個資料遷移過程可以認為已經完成了。但專案工作並沒有完結,舊的邏輯程式碼清理,舊的配套系統下線,舊資源回收,以及最重要的一個環節:經驗教訓總結、分享,流程完善,工具通用化改造。

線上資料遷移並不是一項需要高深技術的工作,它更多需要的是對業務邏輯的把控,對操作流程的理解,對新舊系統特性的掌握,以及對細節的敬畏之心。

相關文章