小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!

架構師修行手冊發表於2023-04-26

小紅書是一個社群屬性為主的產品,它涵蓋了各個領域的生活社群,並儲存海量的社交網路關係。為解決社交場景下超大規模資料的更新與關聯讀取問題,並減少資料庫壓力和成本,我們自研了面向超大規模社交網路的圖儲存系統 REDtao,大大提高了系統穩定性。該系統借鑑了 Facebook 的圖儲存系統設計,將快取和底層資料庫封裝起來,並對外提供統一的圖查詢 API,實現了訪問收斂,同時在快取中實現了高效的邊聚合。

小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!

小紅書是以年輕人為主的生活記錄、分享平臺,使用者可以透過短影片、圖文等形式記錄生活點滴,分享生活方式。在小紅書的社交領域裡,我們有使用者、筆記、商品等實體,這些實體之間有各種各樣的關係。例如,使用者與筆記之間可能存在“擁有”(釋出)、“點贊”、“收藏”等三種關係,同時還存在對應的反向關係“被點贊”,“被收藏”等。


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


小紅書的社交圖譜資料已經達到了萬億條邊的規模,且增長速度非常快。當使用者登陸小紅書時,每個使用者都會看到關注的好友、粉絲、點贊、收藏以及其他為其量身定做的內容。


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


這些資訊高度個性化,需要實時從這些海量社交關係資料中讀取使用者相關資訊。這是一個讀為主的過程,讀取壓力非常大。


過去,我們將這些社交圖譜資料都儲存在運維成熟的 MySQL 資料庫中。然而,即使我們只有百萬請求每秒的規模,MySQL 的 CPU 使用率仍然到達了 55% 。隨著使用者和 DAU 爆發式的增長,需要不斷擴容 MySQL 資料庫,這帶來了巨大的成本和穩定性壓力。為了解決這些問題且考慮到沒有合適的開源方案,2021 年初我們開啟了從 0 到 1 自研 REDtao 的歷程。


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


我們充分調研了業內其他廠商的實現,發現有著強社交屬性的公司基本上都有一個自研的圖儲存系統:


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


Facebook 實現了一個叫做 “TAO” 專門的分散式社交圖譜資料庫,並將其作為最核心的儲存系統;Pinterest 和 Facebook 類似,也實現了類似的圖儲存系統;位元組跳動自研了 ByteGraph 並將其用於儲存核心的社交圖譜資料;Linkedln 在 KV 之上構建了社交圖譜服務。


考慮到當時我們的社交圖譜資料已經存放在 MySQL 資料庫上且規模巨大,而社交圖譜資料服務是非常重要的服務,對穩定性的要求非常高。回溯 Facebook 當年遇到的問題和我們類似,資料儲存在 Memcache 和 MySQL 中。因此,參考 Facebook 的 Tao 圖儲存系統更貼合我們的實際情況和已有的技術架構,風險更小。


社交圖譜的訪問主要是邊的關係查詢。我們的圖模型將關係表示為一個 <key, value> 對,其中 key 是 ( FromId,  AssocType,  ToId ) 的三元組,value 是屬性的  JSON 格式。比如“使用者 A ”關注“使用者 B ”,對映到 REDtao 的資料儲存結構為:



 <FromId:使用者A的ID, AssocType:關注, ToId:使用者B的ID>  ->  Value (屬性的json欄位)


我們對業務方的需求進行分析,封裝了 25 個圖語義的 API 給業務方使用,滿足了其增刪改查的需求,並收斂業務方的使用方式。相比於 Facebook 的 Tao,我們還補充了社交圖譜所需要的圖語義,為反作弊場景提供了額外的過濾引數。同時,在快取層面,我們支援對不同的欄位在快取中配置區域性二級索引。下面給一些典型的使用場景:


場景一:

獲取關注了 A 的所有正常使用者(並且剔除作弊使用者)


getAssocs(“被關注型別”, 使用者A的ID, 分頁偏移量, 最大返回值, 只返回正常使用者,是否按照時間從新到舊)


場景二:

獲取 A 的粉絲個數(並且剔除作弊使用者)


getAssocCount(“被關注型別”, 使用者A的ID, 只返回正常使用者)

小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!

REDtao 的架構設計考慮了下面這幾個關鍵的要素:

小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


3.1 整體架構

整體架構分為三層:接入層、快取層和持久層。業務方透過 REDtao SDK 接入服務。如下圖:


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


在這個架構中,和 Facebook Tao 不一樣的是,我們的快取層是一個獨立的分散式叢集,和下面的持久層是解耦的。快取層和下面的持久層可以獨立的擴容縮容,快取分片和 MySQL 分片不需要一一對應,這樣帶來了更好的靈活性,MySQL 叢集也變成了一個可以插拔替換的持久儲存。


讀流程:客戶端將讀請求傳送給 router,router 接收到 RPC 請求後,根據邊型別選擇對應的 REDtao 叢集,根據三元組 ( FromId,  AssocType,  ToId ) 透過一致性 Hash 計算出分片所在的 Follower 節點,將請求轉發到該節點上。Follower 節點接收到該請求,首先查詢本地的圖快取,如果命中則直接返回結果。如果沒有命中,則將請求轉發給 Leader 節點。同樣的,Leader 節點如果命中則返回,如果不命中則查詢底層 MySQL 資料庫。


寫流程:客戶端將寫請求傳送給 router,和讀流程一樣,會轉發到對應的 Follower 節點上。Follower 節點會轉發寫請求給 Leader 節點,Leader 節點轉發給 MySQL,當 MySQL 返回寫入成功後,Leader 會清除本地圖快取對應的 Key,並同步給其他所有 Follower 清除掉該 Key,保證資料的最終一致性。


3.2 高可用

REDtao 分為獨立的兩層:快取層和持久層。每一層都保證高可用性。


自研的分散式快取:

我們自研了實現圖語義的分散式 cache 叢集,支援故障自動檢測和恢復、水平擴縮容。


它是一個雙層 cache,每個分片都有一個 Leader 和若干個 Follower。所有的請求都先發給外層的 Follower,再由 Follower 轉發給 Leader。這樣的好處是讀壓力大的時候只需要水平擴充套件 Follower,單點 Leader 寫入的方式也降低了複雜度,更容易實現資料的一致性。


如果一個副本故障,系統會在秒級別內進行切換。當持久層發生故障時,分散式快取層仍然可以對外提供讀取服務。


高可用的MySQL叢集:

MySQL 叢集透過自研的中介軟體實現了分庫分表方案,並支援 MySQL 的水平擴容。每個 MySQL 資料庫有若干從庫,並且與公司內部其他的 MySQL 運維方案一致,保證高可用性。


限流保護功能:

為防止快取擊穿導致 MySQL 突發大量請求,從而導致 MySQL 當機,我們透過限制每個主節點最大 MySQL 併發請求數來實現限流保護 MySQL。達到最大併發請求限制之後的請求會被掛起等待,直到已有請求被處理返回,或者達到等待超時請求被拒絕不會被繼續請求到 MySQL 。限流閾值線上可調,根據 MySQL 叢集規模調整對應限制。


為防止爬蟲或者作弊使用者頻繁刷同一條資料,我們利用 REDtaoQueue 順序執行對寫入或者點查同一條邊的請求,佇列長度會被限制,控制同一時間大量相同的請求執行。相比於單個全域性的佇列控制所有請求的方式,基於每個請求的佇列可以很好地限制單個同一請求,而不影響其他正常請求。


3.3 極致效能

資料結構的設計是 REDtao 高效能的重要保證。我們採用了三層巢狀 HashTable 的設計, 透過根據某個起點 from_id 從第一級 HashTable 中查詢到 REDtaoGraph,記錄了所有 type 下對應的所有的出邊資訊。接著,在第二級 HashTable 中,根據某個 type_id 查詢到 AssocType 對應某個 type 下邊所有出邊的計數、索引以及其他後設資料。最終在最後一級 HashTable ,透過 AssocType 的某個 to_id 查詢到最終邊資訊。我們記錄了建立時間、更新時間、版本、資料以及 REDtaoQueue,time_index 則對應根據建立時間排序列表。最後一級 HashTable 以及索引限制儲存最新的 1000 個邊資訊,以限制超級點佔據過多記憶體,同時集中提高最新熱資料的查詢命中率以及效率。REDtaoQueue 用於排隊當前某個關係的讀寫,只記錄了當前最後一個請求的後設資料。每次查詢或寫入時,首先查詢 REDtaoAssoc,若快取不存在,則會首先建立只包含 REDtaoQueue 的物件;若快取已存在,則會更新佇列後設資料,將自己設定為佇列的最後一個請求,並掛起等待被執行。


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


透過這種多層 hash+ 跳錶的設計,我們能高效地組織點、邊、索引、時間序連結串列之間的關係。記憶體的申請、釋放在同一個執行緒上完成。


線上上環境中,我們的系統可以在一臺 16 核的雲廠商虛擬機器上跑到 150w 查詢請求/s,同時 CPU 利用率僅有 22.5% 。下方是線上叢集的一個監控圖,單機的 QPS 到達 3w ,每個 RPC 請求聚合了 50 個查詢。


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!
小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!
小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


3.4 易用性

豐富的圖語義 API :

我們在 REDtao 中封裝了 25 個圖語義的 API 給業務方使用,滿足了業務方的增刪改查的需求。業務方無需自行編寫 SQL 語句即可實現相應操作,使用方式更加簡單和收斂。


統一的訪問 URL :

由於社群後端資料太大,我們按照不同的服務和優先順序拆分成了幾個 REDtao 叢集。為了讓業務方不感知後端的叢集拆分邏輯,我們實現了統一的接入層。不同的業務方只需使用同一個服務 URL ,透過 SDK 將請求傳送到接入層。接入層會接收到不同業務方的圖語義的請求,並根據邊的型別路由到不同的 REDtao 叢集。它透過訂閱配置中心,能夠實時感知到邊的路由關係,從而實現統一的訪問 URL,方便業務方使用。


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


3.5 資料的一致性

作為社交圖譜資料,資料的一致性至關重要。我們需要嚴格保證資料的最終一致性以及一定場景下的強一致性。為此,我們採取了以下措施:


快取更新衝突的解決:

REDtao 為每個寫入請求生成一個全域性遞增的唯一版本號。在使用 MySQL 資料更新本地快取時,需要比較版本號,如果版本號比快取的資料版本低,則會拒絕此更新請求,以避免衝突。


寫後讀的一致性:

Proxy 會將同一個 fromId 的點或邊請求路由到同一個讀 cache 節點上,以保證讀取資料一致性。


主節點異常場景:

Leader 節點收到更新請求後,會將更新請求變為 invalidate cache 請求非同步的傳送給其他 follower,以保證 follower 上的資料最終一致。在異常情況下,如果 Leader 傳送的佇列已滿導致 invalidate cache 請求丟失,那麼會將其他的 follower cache 全部清除掉。如果 Leader 故障,新選舉的 Leader 也會通知其他 follower 將 cache 清除。此外,Leader 會對訪問 MySQL 的請求進行限流,從而保證即使個別分片的cache被清除掉也不會將 MySQL 打崩。


少量強一致的請求:

由於 MySQL 的從庫也提供讀服務,對於少量要求強一致的讀請求,客戶端可以將請求染上特殊標誌,REDtao 會透傳該標誌,資料庫 Proxy 層會根據該標誌將讀請求轉發到 MySQL 主庫上,從而保證資料的強一致。


3.6 跨雲多活

跨雲多活是公司的重要戰略,也是 REDtao 支援的一個重要特性。REDtao 的跨雲多活架構整體如下:


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


這裡不同於 Facebook Tao 的跨雲多活實現,Facebook Tao 的跨雲多活實現如下圖:


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


Facebook 的方案依賴於底層的 MySQL 的主從複製都透過 DTS Replication 來做。而 MySQL 原生的主從複製是自身功能,DTS 服務並不包含 MySQL 的主從複製。該方案需要對 MySQL 和 DTS 做一定的改造。前面說到,我們的快取和持久層是解藕的,在架構上不一樣。


因此,REDtao 的跨雲多活架構是我們結合自身場景下的設計,它在不改動現有 MySQL 功能的前提下實現了跨雲多活功能:


1)  持久層我們透過 MySQL 原生的主從 binlog 同步將資料複製到其他雲的從庫上。其他雲上的寫請求和少量要求強一致讀將被轉發到主庫上。正常的讀請求將讀取本區的 MySQL 資料庫,滿足讀請求對時延的要求。


2)  快取層的資料一致性是透過 MySQL DTS 訂閱服務實現的,將 binlog 轉換為 invalidate cache 請求,以清理掉本區 REDtao cache 層的 stale 資料。由於讀請求會隨機讀取本區的任何一個 MySQL 資料庫,因此 DTS 訂閱使用了一個延遲訂閱的功能,保證從 binlog 同步最慢的節點中讀取日誌,避免 DTS 的 invalidate cache 請求和本區 read cache miss 的請求發生衝突從而導致資料不一致。


3.7 雲原生

REDtao 的雲原生特性重點體現在彈性伸縮、支援多 AZ 和 Region 資料分佈、產品可以實現在不同的雲廠商間遷移等幾個方面。REDtao 在設計之初就考慮到支援彈性擴縮容、故障自動檢測及恢復。


隨著 Kubernetes 雲原生技術越來越成熟,我們也在思考如何利用 k8s 的能力將部署和虛擬機器解綁,進一步雲原生化,方便在不同的雲廠商之間部署和遷移。REDtao 實現了一個執行在 Kubernetes 叢集上的 Operator,以實現更快的部署、擴容和壞機替換。為了讓 k8s 能感知叢集分片的分配並且控制同一分片下的 Pods 排程在不同宿主機上,叢集分組分片分配由 k8s Operator 渲染並控制建立 DuplicateSet (小紅書自研 k8s 資源物件)。REDtao 則會建立主從並根據 Operator 渲染出來的分片資訊建立叢集,單個 Pod 故障重啟會重新加入叢集,無需重新建立整個叢集。叢集升級時,Operator 透過感知主從分配控制先從後主的順序,按照分片分配的順序滾動升級以減少升級期間線上影響。


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!

但凡變革,皆屬不易。實現全新的 REDtao 只是完成了相對容易的那部分工作。小紅書的社交圖譜資料服務已經在 MySQL 上執行多年,有很多不同的業務跑在上面,任何小的問題都會影響到小紅書的線上使用者。因此,如何保證不停服的情況下讓現有業務無感知地遷移到 REDtao 上成為一個非常大的挑戰。我們的遷移工作關鍵有兩點:


● 將老的大 MySQL 叢集按優先順序拆分成了四個 REDtao 叢集。這樣,我們可以先將優先順序最低的服務遷移到一個 REDtao 叢集,充分灰度後再遷移高優先順序的叢集。


● 專門開發了一個 Tao Proxy SDK,支援對原來的 MySQL 叢集和 REDtao 叢集進行雙寫雙讀,資料校驗比對。


遷移時,我們首先將低優先順序的資料從 MySQL 透過 DTS 服務遷移到了一個 REDtao 叢集,並升級好業務方的 SDK 。DTS 服務一直對增量資料進行同步。業務方 SDK 會訂閱配置中心的配置變更,我們修改配置讓 Tao Proxy SDK 同時讀寫 MySQL 叢集和 REDtao 叢集,並關閉 DTS 服務。此時會使用 MySQL 叢集的結果返回給使用者。


在停止 DTS 服務時,有可能會有新的 MySQL 資料透過 DTS 同步過來,造成了 REDtao 叢集新寫的資料被同步過來的老資料覆蓋。因此,在關閉 DTS 服務後,我們會透過工具讀取開雙寫之後到關閉 DTS 服務這個時間段的 binlog 對資料進行校驗和修復。


修復完成之後,Tao Proxy SDK 的雙讀會展示兩邊不一致的資料量,並過濾掉因為雙寫時延不一致導致資料不一致的請求。灰度一段時間後觀察到 diff 的數目基本為 0,將 Tao Proxy SDK 的配置改為只讀寫新的 REDtao 叢集。


最終,我們在 22 年初完成小紅書所有核心社交圖譜萬億邊級別資料的遷移和正確性校驗,並做到了整個遷移服務無感知,遷移過程沒有發生一起故障。


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!

我們的社交圖譜資料訪問中,90% 以上的請求都是讀請求,並且社交圖譜的資料有非常強的時間區域性性(即最近更新的資料最容易被訪問)。REDtao 上線後,獲得 90% 以上的 cache 命中率, 對MySQL 的 QPS 降低了 70%+ ,大大降低了 MySQL 的 CPU 使用率。在縮容 MySQL 的副本數目後,整體成本降低了21.3%。‍


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


業務的訪問方式都全部收斂到 REDtao 提供的 API 介面上,在遷移過程中,我們還治理了一些老的不合理訪問 MySQL 資料庫的方式,以及自定義某些欄位賦予特殊含義的不合理做法,透過 REDtao 規範了資料訪問。


對比 2022 年初和 2023 年初,隨著 DAU 的增長,社交圖譜的請求增長了 250% 以上,如果是之前 MySQL 的老架構,擴容資源基本上和請求增長速度成正比,至少需要擴容 1 倍的資源成本(數萬核)。而得益於 REDtao 系統的存在,因其 90% 的快取命中率,實際上整體成本只增加了 14.7%(數千核)就能扛下 2.5 倍的請求增長。在成本和穩定性上有了較大的提升。


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!

在較短的時間,我們自研了圖儲存系統 REDtao ,解決了社交圖譜關係資料快速增長的問題。


REDtao 借鑑了 FaceBook Tao 的論文,並對整體架構、跨雲多活做了較多的改進,全新實現了一個高效能的分散式圖快取,更加貼合我們自身的業務特點和提供了更好的彈性。同時,利用 k8s 能力進一步實現了雲原生化。


隨著 DAU 的持續增長,萬億的資料規模也在繼續增長,我們也面臨著更多的技術挑戰。目前公司內部的 OLTP 圖場景主要分為三塊:


●社交圖譜資料服務:透過自研圖儲存系統 REDtao 滿足了社交場景超大規模資料的更新與關聯讀取問題。目前已經儲存了萬億規模的關係。


●風控場景:透過自研圖資料庫 REDgraph,滿足多跳的實時線上查詢。目前儲存了千億點和邊的關係,滿足 2 跳以及 2 跳以上的查詢。(關於 REDgraph 的介紹我們將放在下一篇文章中分享)


●社交推薦:這塊主要是兩跳的查詢。每天透過 Hive 批次地匯入全量的資料,透過 DTS 服務近實時的寫入更新資料。因為是線上場景,對時延的要求非常高,當前的 REDgraph 還無法滿足這麼高的要求,因此業務方主要是用 REDkv 來儲存。


針對以上場景,為了快速滿足業務需求,我們使用了三套不同的自研儲存系統:REDtao 、REDgraph 和 REDkv 。顯然相對於 3 套儲存系統,用一個統一的架構和系統去解決這幾個圖相關的場景是更加合適的。未來,我們會將 REDgraph 和 REDtao 融合成一個統一的資料庫產品,打造業內頂尖的圖技術,對公司內部更多的場景進行賦能。最後,歡迎對技術有著極致追求,志同道合的同學一起加入我們。


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!

空洞:小紅書基礎架構儲存組,負責圖儲存系統 REDtao 和分散式快取的研發


劉備:小紅書基礎架構儲存組負責人,負責REDkv / REDtao / REDtable / REDgraph 的整體架構和技術演進


小紅書如何應對萬億級社交網路關係挑戰?圖儲存系統 REDtao 來了!

基礎架構-儲存組是給小紅書的業務部門提供穩定可靠的儲存和資料庫服務,滿足業務對儲存產品的功能、效能、成本和穩定性要求。


目前負責自研分散式 KV、分散式快取、圖儲存系統、圖資料庫和表格儲存。已上線的儲存產品包括:


● REDkv : 分散式高效能 KV

● REDtao :滿足一跳查詢的高效能圖儲存資料庫

● REDtable :提供 Schema 語義和二級索引的表格儲存

● REDgraph :提供兩跳及以上的圖語義查詢資料庫


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027824/viewspace-2948828/,如需轉載,請註明出處,否則將追究法律責任。

相關文章