日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从vivo 大规模特征存储实践中学点经验

發布時間:2024/2/28 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从vivo 大规模特征存储实践中学点经验 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原創?黃偉鋒?

本文旨在介紹 vivo 內部的特征存儲實踐、演進以及未來展望,拋磚引玉,吸引更多優秀的想法。

?

一、需求分析

?

AI 技術在 vivo 內部應用越來越廣泛,其中特征數據扮演著至關重要的角色,用于離線訓練、在線預估等場景,我們需要設計一個系統解決各種特征數據可靠高效存儲的問題。

?

1. 特征數據特點

?

(1)Value 大

特征數據一般包含非常多的字段,導致最終存到 KV 上的 Value 特別大,哪怕是壓縮過的。

?

(2)存儲數據量大、并發高、吞吐大

特征場景要存的數據量很大,內存型的 KV(比如 Redis Cluster)是很難滿足需求的,而且非常昂貴。不管離線場景還是在線場景,并發請求量大,Value 又不小,吞吐自然就大了。?

?

(3)讀寫性能要求高,延時低

大部分特征場景要求讀寫延時非常低,而且持續平穩,少抖動。

?

(4)不需要范圍查詢

大部分場景都是單點隨機讀寫。

?

(5)定時灌海量數據

很多特征數據剛被算出來的時候,是存在一些面向 OLAP 的存儲產品上,而且定期算一次,希望有一個工具能把這些特征數據及時同步到在線 KV 上。

?

(6)易用

業務在接入這個存儲系統時,最好沒有太大的理解成本。

?

?

2. 潛在需求

?

  • 擴展為通用磁盤 KV,支撐各個場景的大容量存儲需求

    我們的目標是星辰大海,絕不僅限于滿足特征場景。

    ?

  • 支撐其他 Nosql/Newsql 數據庫,資源復用

    從業務需求出發,后續我們會有各種各樣 Nosql 數據庫的需求,如圖數據庫、時序數據庫、對象存儲等等,如果每個產品之間都是完全隔離,沒有任何資源(代碼、平臺能力等等)復用,維護成本是巨大的。

    ?

  • 可維護性強

    首先實現語言不能太小眾,否則人才招聘上會比較困難,而且最好能跟我們的技術棧發展方向匹配。

    架構設計上不能依賴太多第三方服務組件,降低運維的復雜性。

?

?

3. 存儲系統的冰山

?

綜合以上需求,最終我們決定兼容 Redis 協議,用戶看到的只是一個類似單機版的 Redis 服務,但背后我們做了大量的可靠性保障工作。

?

?

?

二、方案選型

?

在方案選型上,我們遵循一些基本原則:

  • 源自開源,按需定制。

  • 內部開源,集思廣益。

  • 語言主流,架構主流。

  • 可靠至上,高可維護。

?

先簡單介紹一下我們早期方案調研的一些優缺點分析:

?

?

說實話,調研的都是優秀的開源項目,但光靠官方代碼和設計文檔,沒有深入的實踐經驗,我們是很難斷定一個開源產品是真正適合我們的,適當的賽馬可以更好校準方案選型,同時也一定程度反映出我們較強的執行力。

?

總的來說我們是要在現有需求、潛在需求、易用性、架構先進性、性能、可維護性等各個方面中找到一個最優平衡,經過一段時間的理論調研和實踐以后,最終我們選擇了 Nebula。

?

?

三、Nebula 簡介

?

Nebula Graph 是一個高性能、高可用、高可靠、數據強一致的、開源的分布式圖數據庫。

?

1. 存儲計算分離

Nebula 采用存儲計算分離的設計,有狀態的存儲服務 和 無狀態的計算服務 是分層的,使得存儲層可以集中精力提升數據可靠性,只暴露簡單的 KV 接口,計算層可以聚焦在用戶直接需要的計算邏輯上,而且大大提升運維部署的靈活性。

?

不過作為圖數據庫,為了提升性能,Nebula 把一部分圖計算邏輯下沉到存儲層,這也是靈活性與性能之間的一個比較現實的權衡。

?

2. 強一致,架構主流

Nebula 的強一致使用 Raft,是目前實現多副本一致性的主流方法,而且這個 Raft 實現已經初步通過了 Jepsen 線性一致性測試,作為一個剛起步不久的開源項目,對增加用戶的信心很有幫助。

?

3. 可伸縮

Nebula 的橫向擴展能力得益于其 Hash-based 的 Multi-raft 實現,同時自帶一個用于負載均衡的調度器(Balancer),架構和實現都比較簡潔(至少目前還是),上手成本低。

?

4.易維護

Nebula 內核使用 C++ 實現,跟我們基礎架構的技術棧發展方向比較匹配。經過評估,Nebula 一些基本的平臺能力(如監控接口、部署模式)比較簡單易用,跟我們自身平臺能很好對接。

?

代碼實現做了較好抽象,可以靈活支持多種存儲引擎,為我們后來針對特征場景的性能優化奠定了很好的基礎。

?

?

四、Nebula Raft 簡介

?

上文提到 Nebula 是依賴 Raft 保證強一致的,這里簡單介紹一下 Nebula Raft 的特點:

?

1. 選主 與 任期

一個 Raft Group 的生命周期是由一個又一個連續的任期組成的,每個任期開始會選出一個 Leader,其他成員為 Follower,一個任期內只有一個 Leader,如果任期內 Leader 不可用,會馬上進入下一個任期,選新的 Leader。這種 Strong Leader 機制使得 Raft 的工程實現難度遠低于它的祖師爺 - Paxos。

?

2. 日志復制、壓縮

標準的 Raft 實現中,每個從客戶端來的寫請求都會轉換成 “操作日志” 寫到 wal 文件中,Leader 在把操作日式更新到自己狀態機后,會主動向所有 Follower 異步復制日志,直到超過半數的 Follower 應答后,才返回客戶端寫入成功。

?

實際運行中,wal 的文件會越來越大,如果沒有一個合理的 wal 日志回收機制,wal 文件將很快占滿整個磁盤,這個回收機制就是日志壓縮(Log Compaction)。Nebula 的 Log Compaction 實現比較簡潔,用戶只需要配置一個 wal_ttl 參數,即可在不破壞集群正確性的前提下,把 wal 文件的空間占用控制在一個穩定的范圍。

?

Nebula 實現了 Raft batch 和 pipeline 機制,支持 Leader 到 Follower 的批量和亂序日志提交,在高并發場景下,能有效提升集群整體吞吐能力。

?

3. 成員變更

跟典型的 Raft 實現類似,這里著重提一下 Nebula Raft 的 Snapshot 機制。

?

當一個 Raft Group 增加成員時,新成員節點需要從當前的 Leader 中獲取所有的日志并重放到自身的狀態機中,這是一個不容小覷的資源開銷,對 Leader 造成較大的壓力。為此一般的 Raft 會提供一個 Snapshot 機制,以此解決節點擴容的性能問題,以及節點故障恢復的時效問題。

?

Snapshot,即 Leader 把自身狀態機打成一個“鏡像”單獨保存,在 Nebula Raft 實現中,“鏡像”就是 Rocksdb 實例(即狀態機本身),新成員加入時,Leader 會調用 Rocksdb 的 Iterator 掃描整個實例,過程中把讀到的值分批發送給新成員,最終完成整個 Snapshot 的拷貝過程。

?

4. Multi-raft 實現

如果一個集群只有一個 Raft Group,很難通過加機器實現橫向擴展,適用場景非常有限,自然想到的方法就是把集群的數據拆分出多個不同的 Raft Group,這里就引入了 2 個新問題:(1)數據如何分片(2)分片如何均勻分布到集群中。

?

實現 Multi-raft 是一個有挑戰且很有意思的事情,業界有 2 種主流的實現方式,一種是 Hash-based 的,一種是 Region-based,各有利弊,大部分情況下,前者比較簡單有效,Nebula 目前采用 Hash-based 的方式,也是我們需要的,但面向圖場景,后續有沒有進一步的規劃,需要持續關注社區動態。

?

?

五、特征存儲平臺介紹

?

1. 系統架構

?

?

在 Nebula 原有架構基礎上,增加了一些組件,包括 Redis Proxy、Rediscluster Proxy 以及平臺化相關的組件。

?

Meta 實例是存整個集群的元信息,包括數據分片路由規則,space 信息等等,其本身也是一個 Raft Group。

?

Storage 實例是實際存數據的節點,假設一個集群多個分片對應 m 個 Raft Group,每個 Raft Group 對應 n 個副本,Nebula 就是把 m * n 個副本均勻分布到這多個 Storage 實例中,并力求每個實例中的 Leader 數也相近。

?

Graph 實例是圖 API 的服務提供者以及整個集群的 Console,無狀態。

?

Redis 實例兼容了 Redis 協議,實現了部分 Redis 原生的數據結構,無狀態。

?

Rediscluster 實例兼容了 Redis Cluster 協議,無狀態。

?

?

2. 性能優化

?

(1)集群調優

實際接入生產業務時,往往需要針對不同場景調整參數,這個工作在在早期占用了大量的時間,但確實也為我們積累寶貴的經驗。

?

(2)WiscKey

前文提到的大部分特征場景的 Value 都比較大,單純依賴 Rocksdb 會導致嚴重的寫放大,原因在于頻繁觸發 Compaction 邏輯,而且每次 Compaction 的時候都會把 Key 和 Value 從磁盤掃出來,在 Value 大的場景下,這個開銷非常可怕。為此學術界提出過一些解決方案,其中 WiscKey 以實用性而廣受認可,工業界也落地了其開源實現(Titandb)。

?

Titandb 詳細原理可參考其?官方文檔,簡單來說,就是改造 Rocksdb,兼容對外接口,保留 LSM-tree,新增 BlobFile 存儲,Key Value 分離存儲,Key 存 ?LSM-tree,Value 存 BlobFile,依賴 SSD 磁盤隨機讀寫性能,犧牲范圍查詢性能,減少大 Value 場景下的寫放大。

?

得益于 Nebula 支持多存儲引擎的設計,Titandb 很輕松就集成到 Nebula Storage,在實際生產中,的確在性能上給我們帶來不錯的收益。

?

?

3. TTL 機制

?

不管是 Rocksdb, 還是 Titandb,都兼容了 Compaction Filter 接口,即在 Compaction 的時候會調用這個 Filter 來判斷是否需要過濾掉具體的數據。我們在實際寫入 Storage 的 Value 中種入了 TTL,在 Compaction Filter 的時候,掃描每個 Value,提取出 TTL 判斷 Value 是否過期了,如果是,則刪除掉對應 Key-Value 對。

?

然而,實踐中我們發現,Titandb 在 Compaction 的時候,如果 Value 很大被分離到 BlobFile 后,Filter 是讀不到具體 Value 的(只有留在 LSM-tree 里的小 Value 才能被讀到)。這就對我們 TTL 機制造成很大的不利,導致過期的數據沒有辦法回收。為此,我們做了一點特殊處理,當大 Value 被分離到 BlobFile 后,LSM-tree 里會存 Key-Index 對,Index 就是 Value 在 BlobFile 中的位置,我們嘗試把 TTL 種到 Index 中,使得 Filter 時能解析出 TTL,從而實現所有過期數據的物理刪除。

?

?

4. 易用

?

易用性是一個數據庫走向成熟的標志,是一個很大的課題。

?

從不同用戶的視角出發,會引申出不同的需求集合,用戶角色可以包括 運維 dba、業務研發工程師、運維工程師等等,最終我們希望在各個視角都能超出預期,實現真正高易用的存儲產品。這里簡單介紹我們在易用性上的一些實踐:

?

(1)兼容 redis 協議

我們改造了美圖開源的 KVrocks(一個基于 Rocksdb 的兼容 redis 協議的單機磁盤 KV 產品),依賴 Nebula C++ 版本的 Storage Client,把底層依賴 Rocksdb 的邏輯替換成 Nebula Storage KV 接口的讀寫邏輯,從而實現一個無狀態的 redis 協議兼容層(Proxy),同時我們根據實際需要額外實現了一些命令。當然,我們只是針對特征場景實現了一些 redis 命令,要在分布式 KV 基礎上兼容所有 redis 的指令,需要考慮分布式事務,這里我先賣個關子,敬請期待。

?

(2)支持從 Hive 批量導入數據到 KV

對特征場景來說,這個功能也是易用性的一種體現,Nebula 目前針對圖結構的數據已經實現了從 Hive 導數據,稍加改造就能兼容 KV 格式。

?

(3)平臺化運維

前期我們在公共配置中心上維護了所有線上集群的元信息,并落地了一些簡單的作業,如一鍵部署集群、一鍵卸載集群、定時監控上報、定時命令正確性檢查、定時實例健康檢測、定時集群負載監控等等,能滿足日常運維的基本需求。同時,vivo 內部在建設一個功能完善的 DBaaS 平臺,已經實際支撐了不少 DB 產品的平臺化運維,包括 redis、mysql、elasticsearch、mongodb 等等,大大提升業務的數據管理效率,所以,最終特征存儲是要跟平臺全面結合、共同演進,不斷實現產品易用性和健壯性的突破。

?

?

5. 災備

?

(1)定期冷備

Nebula 本身提供了冷備機制,我們只需要設計好個性化的定時備份策略,即可較好滿足業務需求,這里不詳細描述,感興趣可以看看 Nebula 的?集群快照機制。

?

(2)實時熱備

?

熱備落地一共分兩期:

?

第一期:比較簡單,只考慮增量備份,且容忍有損。

目前 KV 主要服務特征場景(或緩存場景),對數據可靠性要求不是特別高,而且數據在存儲中駐留的時間不會很長,很快就會被 TTL 清理掉。為此熱備方案中暫不支持存量數據的備份。

?

至于增量備份,就是在 Proxy 層把 “寫請求” 再異步寫一次到備集群,主集群還是繼續執行同步寫,只要 Proxy cpu 資源足夠,不會影響主集群本身的讀寫性能。這里會存在數據丟失的風險,比如 Proxy 異步沒寫完,進程突然掛了,這時備集群是會丟一點數據的,但正如之前提到,大部分特征場景(或緩存場景)對這種程度的數據丟失是可容忍。

?

第二期:?既保證增量備份,也要保證存量備份。

Nebula Raft 引入了 Learner,它也是 Raft Group 中的一個副本,但既不參與選主,也不影響多數派提交,它只是默默的接收來自 Leader 的日志復制請求。跟其他 Follower 一樣,Learner 一旦掛了,Leader 會不斷重試復制日志給 Learner,直到 Learner 重啟恢復。

?

有了這個機制,要實現存量備份就變的簡單了,我們可以實現一個災備組件,偽裝成 Learner,掛到 Raft Group 中,這時 Raft 的成員變更機制會保證 Leader 中的存量數據和增量數據都能以日志的形式同步給災備組件,同時組件另一側依賴 Nebula Storage Client 把源日志數據轉換成寫請求應用到災備集群。

?

?

6. 跨機房雙活

?

雙活也是分兩期落地:

?

第一期:不考慮沖突處理,不保證集群間的最終一致。

這個版本的實現同樣簡單,可以理解是 2 個集群互為災備,對有同城雙活、故障轉移需求,對最終一致性要求不高的業務還是很有幫助的。

?

第二期:引入 CRDT 處理沖突,實現最終一致。

這個版本對可靠性的要求比較高,復用災備二期的能力,在 Learner 中獲取集群的寫請求日志。

?

一般雙活情況下,兩個 KV 集群會分布在不同機房,單元化的業務服務會各自讀寫本機房 KV 的數據,兩個不同機房的 KV 相互同步變更。假如兩個 KV 更新了同一個 Key,并同步給對方,這時應該怎么處理沖突呢?

?

最簡單直接的方案就是最 “晚” 寫的數據更新到兩個 KV,保證最終一致,這里的 “晚” 不是指絕對意義上的先來后到,而是根據寫操作發生的時間戳,同一個 Key 兩個機房的寫操作都能取到各自的時間戳,但機房之間時鐘不一定同步,這就可能導致實際先發生的操作 時間戳可能更大,但我們的目標是實現最終一致,不是跟時鐘同步機制較勁,所以問題不大。針對這個思路,知名最終一致性方案 CRDT 已經給出了相應的標準實現。

?

KV 實際存的數據只有 String 類型,對應于 CRDT 里的 Register 數據結構,其中一種實現就是 Op-based LWW(Last-Write-Wins) Register,顧名思義,就是最 “晚” 寫的 Value 成為最終一致的狀態,算法原型如下:

?

?

對 CRDT 感興趣的可以看看網上的其他資料,這里不詳細描述。

?

慶幸的是,vivo 內部已經在 Redis Cluster 上實現了 CRDT Register ,并提供了保障數據跨機房可靠傳輸的組件,使得新 KV 存儲可以站在巨人的肩膀上。需要注意的是,KV 線上大量 mset 的寫請求,而 CRDT Register 只支持單個 Set 的請求沖突處理,所以在雙活組件 Learner 中,從 Leader 收到的 Batch Write 請求需要拆解成一個一個的 Set 命令,然后再同步給 Peer 集群。

?

?

六、未來展望

?

1. 擴展成通用 KV 存儲

?

我們立項特征存儲的時候,就目標要做成通用 KV 存儲,成為更多數據庫的強力底座。但要做成一個通用 KV 存儲,還需要很多工作要落實,包括可靠性、平臺能力、低成本方面的提升。慶幸業界已經有很多優秀的實踐,給我們提供很大的參考價值。

?

2. 持續完善平臺能力

?

最簡單的,參考 vivo 內部以及各大互聯網公司 redis 平臺化管理實踐,新 KV 的平臺能力建設還有非常多的事情要做,而且后續還會跟智能化 DB 運維結合在一起,想象空間更大。

?

3. 持續完善正確性校驗機制

?

數據可靠性和正確性是一個數據庫產品的安身立命之本,需要持續完善相應的校驗機制。

?

現階段我們還沒法承諾金融級的數據可靠性,我們會持續往這個方向努力,目前滿足一些特征場景和緩存場景還是可行的。

?

我們已經在逐漸引入一些開源的 chaos 工具,希望能持續深入挖掘出系統的潛在問題,為用戶提供更可靠的數據存儲服務。

?

4. 強化調度能力

?

分布式數據庫核心是圍繞存儲、計算、調度 3 個話題展開的,可見調度的重要性,負載均衡就是其中一個環節,目前 Hash-based 的分片規則,后續能否改成 Region-based 的分片規則?能否跟 k8s 結合構建云原生的 KV 存儲產品?能否讓數據分布調整變得更智能、更自動化 …… 我們拭目以待。

?

5. 冷熱數據分離

?

本質還是成本和性能的權衡,對一些規模特別大的集群,可能 90% 的數據是很少被訪問的,這些數據哪怕存到閃存,也是一種資源的浪費。一方面我們希望被頻繁訪問的數據能得到更好的讀寫性能,另一方面我們希望能最大限度的節省成本。

?

一個比較直接的方法,就是把熱數據存到內存和閃存上,一些冰封的冷數據則存到一些更便宜的介質(比如機械磁盤),這就需要系統自身具備判斷能力,能持續動態區分出哪些屬于熱數據,哪些屬于冷數據。

?

6. 支持更多類型的存儲引擎

?

目前已經支持了 Rocksdb 和 Titandb,后續會考慮引入更多類型的存儲引擎,比如純內存的,或者基于 AEP 等新閃存硬件產品的存儲引擎。

?

7.支持遠端 HDFS 冷備

?

對于在線場景,數據備份還是很重要的,當前 Nebula 已經支持本地集群級的快照備份,但機器掛了,還是會存在大量數據丟失的風險,我們會考慮把數據冷備到遠端,比如 HDFS。是不是只要把 HDFS 掛載成本地目錄,集群把快照 dump 到指定目錄就可以了呢?我們會做進一步的思考和設計。

?

8. SPDK 磁盤讀寫

?

實際測試告訴我們,同樣是依賴 nvme 磁盤,單機上使用 SPDK 比不使用 SPDK 吞吐提升接近 1 倍。SPDK 這種 Bypass Kernel 的方案已經是大勢所趨,對磁盤 io 容易成為瓶頸的場景,使用 SPDK 能有效提升資源利用率。

?

9. KV SSD

?

鑒于 SPDK Bypass Kernel 的優勢,業界提出了一種新的解決方案(KV SSD)。

?

Rocksdb 基于 LSM-tree 實現,Compaction 機制會帶來嚴重的寫放大,而 KV SSD 提供了原生的 KV接口,兼容 Rocksdb API,可以將新的數據記錄直接寫入到 SSD 中,不需要再進行反復的 Compaction 操作,從而將 Rocksdb 的寫放大減小到 1,是一個非常值得嘗試的新技術。

?

10. 支撐圖數據庫

?

我們的 KV 產品之所以訂制 Nebula,其中一個重要原因是為圖數據庫做準備的,目前已經在嘗試接入一些有圖需求的業務,以后希望能跟開源社區合作,共建領先的圖數據庫能力。

?

11. 支撐時序數據庫

?

在 5G 和 物聯網時代,時序數據庫起著非常重要的作用。

?

這個領域 Influxdb 目前比較領先,但開源版本不支持分布式,只依賴一種為時序數據設計的單機存儲引擎(TSM),實用價值非常有限。

?

我們的 KV 產品提供了現成的分布式復制能力、標準化的平臺能力、高可用保障措施,我們希望能盡可能復用起來。

?

結合起來,是不是可以考慮把 TSM 跟分布式復制能力做一個整合,外加對時序場景友好的 Sharding 策略,構建一個高可用的分布式時序存儲引擎,替換掉開源 InfluxDB 的單機存儲層。

?

12.? 支撐對象存儲的元數據存儲

?

元數據存儲對“對象存儲”來說至關重要,既然我們已經提供了一個強大的 KV 存儲產品,是不是可以復用起來,減輕運維和研發維護的負擔呢?

?

七、最后

?

實踐過程中我們需要不斷協調資源、收集需求、迭代產品,力求接入更多場景,收集更多需求,更好打磨我們的產品,盡早進入良性循環,一句話總結下心得體會:

?

總結

以上是生活随笔為你收集整理的从vivo 大规模特征存储实践中学点经验的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。