QQ 相冊後台存儲架構重構與跨 IDC 容災實踐
歡迎大家前往雲加社區,獲取更多騰訊海量技術實踐乾貨哦~
作者簡介:xianmau,2015 年加入騰訊 TEG 架構平台部,一直負責 QQ 相冊平台的維護和建設,主導相冊上傳架構重構和容災優化等工作。主要研究方向為口語對話系統、分散式系統架構設計和優化,發表對話系統相關學術論文 3 篇,系統架構相關專利 2 篇。
本文由騰訊技術工程官方號發布在雲加社區。
寫在前面
QQ 相冊作為重量級資深業務,穩定運營、有效容災,一直是相冊團隊追求的目標。QQ 相冊架構一直在演變進化,本文重點介紹相冊最新的一次重構細節。重構進行了大規模的存儲搬遷、功能模塊合併,抽象了圖片上傳「兩階段」,並在此之上設計了輕量級的容災方案。新架構精簡了大量模塊,優化了圖片上傳流程,減輕了運維工作,從實際運營效果看,系統穩定達到 4 個 9 的服務質量,並具備跨 IDC 容災的能力。
項目背景
QQ 相冊在之前已經上線了索引異地容災,當時容災的設計和實施,受限於人力和設備資源以及保守的升級策略,我們在原有的相冊架構和業務流程上進行非常輕量的設計,從過去一年的實際運營情況看,雖然在各種波動和故障中起到了一定的作用,但是由於容災場景有限,相冊體量龐大,存儲和索引分布在很多機房,稍有網路波動,業務仍然有較高的感知度。QQ 相冊接入架平這十年來,業務對相冊上傳成功率和整體服務質量的要求越來越高,但由於相冊邏輯的複雜性,原有架構在容災、運維和維護(尤其是對新人來說)等方面,並不友好。今年,我們對系統進行了重構!本文總結此次重構的設計和實施,並展示新架構下相冊的容災細節和演習效果,最後總結項目實施過程中的一些思考。
重構目標
從業務角度來說,本項目的實施旨在提高 QQ 相冊上傳的成功率,在各種小型網路波動和故障中低感知甚至不感知(上傳成功率分鐘粒度穩定達到 3 個 9,全天成功率達到 4 個 9),在機房故障甚至大型災難時,具備快速異地容災和恢復的能力。對於相冊平台來說,主要有以下幾個目標:
- 模塊合併
- 簡化架構
- 優化上傳流程
- 優化容災邏輯
解決方案
整體架構調整
一、原相冊架構
QQ 相冊對外提供了豐富的介面,目前存儲量超過 300PB,用戶索引存儲按歸屬地分布,也達到數百 TB 的量級。當前相冊平台雖然較穩定地支撐了如此大量級的業務,但是,系統架構中,模塊眾多,數據流程複雜,這給開發、運維和維護帶來不少麻煩。原相冊架構如圖 1 所示。
用戶使用 app 或 pc 客戶端進行 QQ 相冊操作,比如上傳,修改,刪除,拉列表等,這些請求由 preupload 模塊完成,而 zz 模塊負責圖片的旋轉和轉載,recycle 模塊負責相冊回收站的操作。這裡以最重要的上傳操作為例來說明各核心模塊的功能以及數據流向,如圖 2 所示。相冊數據龐大,索引分布在多個園區,單個用戶的全部索引信息都落在同一個園區內。通過路由模塊可以查詢用戶索引的歸屬地。
二、重構架構
以往的架構調整,大都是用「拆」,但是,隨著業務數據量的增長,以及業務需求變化的緩和,我們更加關注系統的穩定性和高可用性,於是此次重構,我們採用了「合」的思路,把 zz 和 rececyle 整合進 preupoad。看上去功能耦合了,preupload 變得更加臃腫,但是從 zz 和 recycle 的功能邏輯來看,和 preupload 是一樣的或者很相似的,底層也是共用一套存儲,將他們獨立部署,時間久了,三個模塊的代碼邏輯差異越來越大,直接導致開發維護和運維的困難。新架構還把一些已經沒用的模塊去掉,比如 ckv 系統,原圖系統等,然後將原圖功能完全接入秒傳率更高的微雲系統,容災模塊也從原來三地部署、兩兩互備,變成單獨園區部署。重構如圖 3 所示。
由於相冊用戶有歸屬地的問題,導致就近上傳請求有超過一半的概率需要進行異地同步索引,在原架構中,上傳流程需要判斷這一邏輯並分別處理,這使得原本就複雜的上傳邏輯變得更加難以理解,而且還給容災造成極大的困擾。在重構的時候,重點考慮了這一情況,並將上傳流程抽象為兩個階段:數據落地和索引落地。這樣,上傳流程簡化為:就近 preupload 接收到上傳請求,先將圖片數據進行壓縮落地,然後將索引信息發送到索引 preupload 去落地索引,如圖 4 所示。
容災流程調整
一、原相冊上傳容災
大致的容災流程如圖 5 所示。
二、優化容災流程
在新的架構上,把數據落地和索引落地獨立看待,容災流程可以進一步簡化。首先,我們利用上傳請求協議中的一個預留標誌位,巧妙地把普通請求改造成容災請求,並通過容災配置項,預設模塊的容災級別。系統根據請求類型(是否容災請求)、配置項和動態統計信息,實施相應的容災策略。容災的數據流如圖 6 所示。
三、容災策略
新的容災流程,容災策略比較簡單,總結起來就是:
- 根據索引 preupload 的可用性和超時率,決定要不要將上傳請求改造成容災上傳請求(容災請求或容災重試)
- 根據上傳 preupload 的可用性和超時率,決定要請求就近的上傳 preupload 還是異地的上傳 preupload(異地請求或異地重試)
下面通過不同的視角說明具體的策略實施。
業務視角
業務根據請求情況進行容災:
- proxy 不可用,由業務切請求到可用 proxy
- proxy 超時,超時率在 10% 以內可重試一次,超時率在 10% 以上,視容量切請求到異地 proxy(超時率閥值會根據實際運營進行調整)
- proxy 過載,不可重試,視容量切請求到異地 proxy
- proxy 返回錯誤,不建議重試
proxy 視角
1、大型故障導致模塊整體不可用,需要直接進行異地請求或索引容災,請求失敗不進行重試。
2、普通故障和小波動,直接請求就近 preupload,請求失敗則根據超時率和錯誤碼採取相應的重試措施。
上傳 preupload 視角
上傳 preupload 收到 proxy 的請求,先落地圖片數據,如果是容災上傳,需要生成容災索引發送到 synsrv,普通上傳則生成常規索引發送到索引 preupload,然後寫 synsrv 備份索引,不進行任何重試。
索引 preupload 視角
索引 preupload 收到上傳 preupload 的請求,寫主索引和次要索引,不進行任何重試。
synsrv 視角
- 收到備份請求,直接回復成功,並且寫備份索引;
- 收到容災請求,先寫備份索引,再存儲容災索引,並標記 bitmap,所有都成功才返回成功;
- 定期檢測是否有容災索引,有的話,同步回索引點 preupload。
四、關於超時時間的設置
重試是容災的重要手段甚至是必要手段,但是看似簡單,實則用好不易,特別地,重試會放大流量,在失敗率很高的情況下,過多的重試可能導致機器過載,甚至擊垮後端服務,另外,對於多步驟流程的任務來說,在哪些步驟上做重試,以及每一步的超時時間設置,都是挑戰。
我們考慮了所有模塊的過載保護功能,並極簡重試機制:在設定的超時率範圍內,僅在 proxy 層面做一次本地重試或異地重試!圖 7 以一條最長的鏈路說明每個流程的超時時間設定。根據經驗,業務對於上傳的超時時間為 120 秒,proxy 本地請求一次超時為 60 秒,本地重試一次超時為 60 秒,異地請求一次超時為 60 秒。超時時間可能會在實際運營後進行調整優化。
重要成果
項目上線已有一段時間,從實際運營效果看,較好的達到設定的目標。
1、模塊精簡。相冊重構後,直接下架了三地原圖中轉 rawupload、兩地原圖落地 rawupload、四個園區的轉載 preupload 和回收站 preupload 等模塊,並將原來多園區部署的容災系統模塊統一到深圳園區,業務模塊數量從原來的 37 個減少到 18 個,極大地簡化了維護和運維工作。
2、成功率提升。優化了上傳流程以及重試策略,重點排查了出現頻次 top 10 的錯誤碼,目前上傳的成功率從全天平均接近 3 個 9 提升到穩定的分鐘平均 3 個 9、全天平均 4 個 9 的水平。圖 8 為重構優化前的上傳成功率統計,圖 9 為重構優化後的上傳成功率。
3、容災能力提升。新的容災策略基於精心整理的錯誤碼分類,能做到精準的異地容災,容災功能上線以來,可以看到一些小波動的故障也能及時觸發異地容災,成功率得到更完備的保障。不過,上線以來還未出現過大型故障,因此我們也進行了現網故障演習,演習結果表明,新的容災邏輯在應對大型故障也有不錯的表現。表 3 和表 4 分別為容災級別為 2 級和 3 級配置下的演習數據。
寫在最後
相冊上傳重構項目落地已有一段時間了,從實際運營效果來看,在系統維護、運維、實際上傳成功率、業務投訴量等方面,都有不錯的優化效果。架構設計中的「分分合合」,是一門學問,相冊把數據和索引分開存儲,索引又分為主索引和次要索引,輕重分離,提高了存儲效率;新架構抽象了上傳流程,把數據落地和索引落進行邏輯分離和模塊分離,更易於理解和容錯設計;而合併了邏輯重合度高的模塊,則有利於系統的維護和運維。架構設計上沒有永遠的相聚也沒有永遠的分離,只有變化的線上需求,變化的流程,當架構不再適應新的場景時,需要進行重構調整。
相關閱讀
微信朋友圈:應對春節千億訪問量背後的故事高性能伺服器架構思路( 五 ) : 分散式緩存淺析海量用戶的分散式系統設計(2)
此文已由作者授權雲加社區發布,轉載請註明原文出處
推薦閱讀: