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