10億級存儲挑戰!看一看、微信廣告、微信支付、小程序都在用的存儲系統到底是怎麼扛住的?!

| 導語 10億級,是微信用戶的數量級。這個龐大數字的背後,是「看一看」、「微信廣告」、「微信支付」、「小程序」等業務對數據庫10億級的讀寫需求。那麼,在此場景下誕生的 FeatureKV,到底是怎樣強悍的一個存儲系統呢?前端

背景:兩個十億級的挑戰linux

PaxosStore 是微信內普遍應用的強一致性的分佈式存儲系統,它普遍支撐了微信的在線應用,峯值過億TPS,運行在數千臺服務器上,在線服務場景下性能強悍。但在軟件開發中沒有銀彈,在面對離線產出、在線只讀的數據場景,PaxosStore 面臨了兩個新的十億挑戰:算法

10億 / 秒 的挑戰:數據庫

「看一看」團隊須要一個存儲系統來存放CTR過程須要用到的模型,實現存儲和計算分離,使得推薦模型的大小不會受限於單機內存。小程序

每次對文章的排序打分,ctrsvr 會從這個存儲系統中拉取成千上萬個特徵,這些特徵須要是相同版本的,PaxosStore 的 BatchGet 不保證相同版本。數組

業務方預估,這個存儲系統須要支持10億/秒的QPS,PaxosStore 的副本數是固定的,沒法增長只讀副本。緩存

這個存儲系統須要有版本管理和模型管理的功能,支持歷史版本回退。安全

10億 / 小時 的挑戰:性能優化

微信內部很多團隊反饋,他們須要把10億級(也就是微信用戶的數量級)信息,天天按期寫到 PaxosStore 中,但 PaxosStore 的寫入速度沒法知足要求,有時候甚至一天都寫不完,寫太快還會影響現網的其餘業務。服務器

PaxosStore 是一個保證強一致性的存儲系統,爲在線業務設計,其性能也能知足在線業務的需求。但面對這種離線灌庫、在線只讀、不要求強一致性保證的場景,就須要很高的成本才能知足業務的需求了。

基於數據的應用愈來愈多,這類的數據存儲需求也愈來愈多,咱們須要解決這個問題,把10億級key量的數據寫入時間控制在1個小時左右。

上述場景具備定時批量寫、在線只讀的特色,爲了解決這些場景的痛點問題,咱們基於性能強大的WFS(微信自研分佈式文件系統)和穩如磐石的Chubby(微信自研元數據存儲),設計並實現了 FeatureKV,它是一個高性能 Key-Value 存儲系統,具備如下特色:

高性能且易於擴展

優秀的讀性能: 在B70機型上,全內存的表能夠有千萬級的QPS;在TS80A機型上,數據存放於SSD的表能夠有百萬級的QPS。

優秀的寫性能: 在遠程文件系統性能足夠的狀況下,能夠在1小時內完成十億個key、平均ValueSize是400Byte的數據的寫入。

易於擴展: 水平擴容(讀性能)和縱向擴容(容量)能夠在數小時內完成,寫性能擴容只是擴容一個無狀態的模塊(DataSvr),能夠在分鐘級完成。

對批量寫支持友好

任務式的寫接口: 支持以 WFS/HDFS 上的文件做爲輸入,業務方無需編寫、執行灌數據工具,支持失敗重試、告警。

支持增量更新/全量更新: 增量更新是在上一個版本的基礎上,對一批新輸入的 Key-Value 進行覆蓋寫,輸入中沒有的 key 則保持不變。而全量更新則是丟棄上一個版本的數據,灌入一批新的 Key-Value 。

支持TTL: 支持過時自動刪除功能。

具備版本管理功能

事務的 BatchGet 接口: 保證一次 BatchGet 獲得的數據都是同一個版本的。

支持歷史版本回退: 一次更新會產生一個遞增的版本,支持歷史版本回退,包括增量更新生成的版本。

固然,在軟件開發中沒有銀彈,FeatureKV 在設計上它作了取捨:

不支持在線寫入數據,當數據量較小時(GB級),FeatureKV 能夠作到十分鐘級的更新頻率。

不保證強一致性,保證最終一致性,而且在大部分時間裏能夠保證順序一致性。

FeatureKV 如今在微信內部已經普遍應用,包括看一看、微信廣告、微信支付、小程序等業務,接下來會闡述 FeatureKV 的設計,並具體說明如何解決上述兩個十億挑戰。

整體設計

  1. 系統架構

FeatureKV 涉及的外部依賴有三個:

Chubby:用來保存系統中的元數據。FeatureKV 內不少地方是經過對 Chubby 內的元數據輪詢來實現分佈式協同、通訊。

USER_FS:業務側的分佈式文件系統,能夠是 WFS/HDFS ,由於 FeatureKV 的寫接口是任務式的,輸入是一個分佈式文件系統上的路徑。

FKV_WFS:FeatureKV 使用的分佈式文件系統,用來存放 DataSvr 產出的、能夠被 KVSvr 使用的數據文件。能夠保存多個歷史版本,用於支持歷史版本回退。

這三個外部依賴均可以和其餘業務共用。FKV_WFS 和 USER_FS 能夠是同一個模塊。FKV_WFS 可使用 HDFS 替代。Chubby 可使用 etcd 替代。

DataSvr:

主要負責寫數據,把 USER_FS 的輸入,通過數據格式重整、路由分片、建索引等流程,生成 KVSvr 可用的數據文件,寫到 FKV_WFS 中。

它是一個無狀態的服務,寫任務的狀態信息保存在 Chubby 中,擴容 DataSvr,能夠增長系統的寫性能。

通常部署2臺就好,部分場景寫任務較多能夠適當擴容。

KVSvr:

對外提供讀服務,經過輪詢 Chubby 來感知數據更新,再從 WFS 拉取數據到本地,加載數據並提供只讀服務。

它是一個有狀態服務,一個 KVSvr 模塊會由 K 個 Sect 和 N 個 Role 組成,共 K * N 臺機器。

每一個 Sect 都有全量的數據,每次 BatchGet 只須要發往某一個 Sect,增長 Sect 能夠擴容讀性能,而並不會增長 BatchGet 的 rpc 次數。

相同的 Role 負責的數據切片都是同樣的,單機故障時 Batch 請求直接換機重試就好。

K 最少是2,用以保證系統的容災能力,包括在變動時候的可用性。

N 不能是任意一個數字,能夠看下面第二部分。

寫入流程:

FeatureKV 只支持批量寫入數據,每次寫任務能夠是增量更新/全量更新的,每次寫入的數據量大小無限制。離線的批量寫接口設計,咱們踩過一些坑:

一開始咱們打算封一些類/工具,打算讓業務端直接用咱們的類/工具,打包Key-Value數據,直接寫到 FKV_WFS 的目錄上。該方案最省帶寬,可是這樣作讓咱們後續的數據格式升級變得很麻煩,須要讓全部業務方配合,因此這個方案就廢棄了。

而後,咱們起了一個新模塊 DataSvr,在 DataSvr 上面開了一個 tcp svr,業務側輸出 Key-Value,寫入工具會把 Key-Value 數據發過來這個 tcp svr 完成打包,可是仍是有下面這些問題:

寫入的速度與業務方的代碼質量、機器資源有關,曾經碰到過的狀況是,業務方的代碼裏面用 std::stringstreams 解析浮點數輸入,這個函數佔用了 90%+ 的 CPU(用 std::strtof 會快不少),或者業務方跑寫入工具的機器,被別的進程用了 90%+ 的 CPU ,最後反饋 FeatureKV 寫得很慢。

DataSvr 的平常變動或機器故障,會致使任務失敗。前端工具發包的方法沒法對任務進行重試,由於 Key-Value 的輸入流沒法重放。

最終,咱們設計了一個任務式的接口,以 USER_FS 上的路徑做爲輸入:

業務側把數據按照約定好的格式,放在 USER_FS 中,向 DataSvr 提交一個寫任務。

DataSvr 流式讀取 USER_FS 中的數據,對數據進行格式重整、路由分片、建索引,而後把數據寫入 FKV_WFS 中,並更新 Chubby 中的元數據。其中寫任務的分佈式執行、失敗重試等,也須要經過 Chubby 來同步任務狀態。

KVSvr 經過輪詢 Chubby 感知數據更新,把數據拉取到本地,完成加載並提供服務。

  1. 數據路由

考慮擴縮容,FeatureKV 會把一個版本的數據切分爲 N 份, N 如今是 2400,經過哈希 HashFun(key) % N 來決定 key 屬於那份文件。

KVSvr 加載哪些文件是由一致性哈希決定的,角色相同的 KVSvr 會加載相同一批在擴縮容的時候,數據騰挪的單位是文件。

因爲這個一致性哈希只有 2400 個節點,當 2400 不能被 sect 內機器數量整除時,會出現比較明顯的負載不均衡的狀況。因此 FeatureKV 的 sect 內機器數得可以整除2400。還好 2400 是一個幸運數,它 30 之內的因數包括 1,2,3,4,5,6,8,10,12,15,16,20,24,25,30 ,已經能夠知足大部分場景了。

上圖是 N=6 時候的例子,Part_00[0-5] 表示 6 份數據文件。從 RoleNum=2 擴容成 RoleNum=3 的時候,只須要對 Part_003 和 Part_005 這兩份文件進行騰挪,Part_005 從 Role_0遷出至 Role_2,Part_003 從 Role_1 遷出至 Role_2。

因爲現網所用的 N=2400 ,節點數較少,爲了減小每次路由的耗時,咱們枚舉了 RoleNum<100 && 2400%RoleNum==0 的全部狀況,打了一個一致性哈希表。

  1. 系統擴展性

FeatureKV 的 FKV_WFS 上存有當前可用版本的全部數據,因此擴容致使的文件騰挪,只須要新角色的機器從 FKV_WFS 拉取相應編號的文件,舊角色機器的丟棄相應編號的文件便可。

當 BatchSize 足夠大的時候,一次 BatchGet 的 rpc 數量等價於 Role 數量,這些 rpc 都是並行的。當 Role 數量較大時,這些 rpc 出現最少一個長尾請求的機率就越高,而 BatchGet 的耗時是取決於最慢一個 rpc 的。上圖展現了單次 rpc 是長尾請求的機率是 0.01% 的狀況下,不一樣 Role 數量狀況下的 BatchGet 長尾機率,經過公式 1 - (0.999^N) 計算。

增長 Sect(讀性能擴容):

每一個 Sect 都有全量的數據,增長一個 Sect 意味着增長一個只讀副本,能夠達到讀性能擴容的效果。

因爲一個 BatchGet 只須要發往一個 Sect ,RPC 數量是收斂的,不會由於底下的 KVSvr 有 200 臺而發起 200 次 RPC。這種設計能夠下降 BatchGet 操做的平均耗時,減小長尾請求出現的機率。

增長 Role(存儲容量+讀性能擴容):

假設每臺機的存儲能力是相等的,增長 Role 的數量即可以增長存儲容量。

因爲整個模塊的機器都多了,因此讀性能也會增長,整個模塊在讀吞吐量上的擴容效果等價於增長 Sect。

但當 Role 數量較大時,一次 BatchGet 涉及的機器會變多,出現長尾請求機率會增大,因此通常建議 Role 的數量不要超過30。

增長 DataSvr(寫性能擴容):

DataSvr 是一個無狀態服務,能夠作到分鐘級的擴容速度。

底下的寫任務是分佈式的跑,一次寫會切分爲多個並行的 job,增長 DataSvr 的實例數,能夠增長整個模塊的寫性能。

數據遷移都是以文件爲級別,沒有複雜的遷移邏輯,不考慮灰度流程的話,能夠在小時級完成,考慮灰度流程通常是一天內。

  1. 系統容災

KVSvr 側:

每一個 Sect 的機器是部署在同一個園區的,只須要部署 2 個 Sect 就能夠容忍一個園區的機器故障。

具體案例:2019年3月23號,上海南匯園區光纜被挖斷,某個 featurekv 有 1/3 的機器在上面,故障期間服務穩定。

故障期間部分 RPC 超時,致使長尾請求增長。可是換機重試以後大部分請求都成功了,最終失敗出現次數很低。後續全局屏蔽了南匯園區的機器以後,長尾請求和最終失敗徹底消失。

DataSvr/WFS 側:

即使這兩部分整個掛掉, FeatureKV 的 KVSvr 仍是能夠提供只讀服務,對於大部分 定時批量寫、在線只讀 的場景,這樣已經足夠了。

具體案例:2019年6月3號,某個分佈式文件系統集羣故障,不可用9小時。某個 featurekv 的 USER_FS 和 FKV_WFS 都是這個集羣。故障期間業務方的輸出產出流程也中止了,沒有產生寫任務。整個故障期間,featurekv 的讀服務穩定。

十億每秒的挑戰-在線讀服務的具體設計

  1. KVSvr 讀性能優化

爲了提升 KVSvr 的性能,咱們採起了下面一些優化手段:

高性能哈希表:針對部分數據量較少、讀請求很高的數據,FeatureKV 能夠用 MemTable 這一個全內存的表結構來提供服務。Memtable 底層實現是一個咱們本身實現的只讀哈希表,在 16 線程併發訪問的時候能夠達到 2800w 的 QPS,已經超過了 rpc 框架的性能,不會成爲整個系統瓶頸。

libco aio:針對部分數據量較大、讀請求要求較低的數據,FeatureKV 能夠用 BlkTable 或 IdxTable 這兩種表結構來提供服務,這兩表結構會把數據存放在 SSD 中。而 SSD 的讀性能須要經過多路併發訪問才能徹底發揮。在線服務不可能開太多的線程,操做系統的調度是有開銷的。這裏咱們利用了 libco 中對 linux aio 的封裝,實現了協程級的多路併發讀盤,通過壓測在 value_size 是 100Byte 的狀況下,TS80A 上 4 塊 SSD 盤能夠達到 150w+/s 的QPS。

數據包序列化:在 perf 調優的過程當中,咱們發現 batch_size 較大的狀況下(ctrfeaturekv 的平均 batch_size 是 4k+),rpc 數據包的序列化時耗時會較大,因此這裏咱們本身作了一層序列化/反序列化,rpc 層的參數是一段二進制 buffer。

數據壓縮:不一樣業務對數據壓縮的需求是不同的,在存儲模型的場景,value 會是一段浮點數/浮點數數組,表示一些非 0. 特徵。這時候若是用 snappy 這類明文壓縮算法,效果就不太好了,壓縮比不高並且浪費 cpu。針對這類場景,咱們引入了半精度浮點數(由 kimmyzhang 的 sage 庫提供)來作傳輸階段的數據壓縮,下降帶寬成本。

  1. 分佈式事務 BatchGet 的實現

需求背景:更新分爲全量更新和增量更新兩種,一次更新包括多條數據,每次更新都會讓版本號遞增,BatchGet 也會返回 多條數據。業務方但願這些更新都是事務的,BatchGet 的時候若是一個更新沒有所有執行完,那就返回上一個版本的數據,不能返回半新半舊的數據。

RoleNum=1 的狀況:

數據沒有分片,都落在同一臺機器上,咱們調研後發現有這麼兩種作法:

MVCC: 多版本併發控制,具體實現就是 LevelDB 這樣的存儲引擎,保存多版本的數據,能夠經過 snapshot 控制數據的生命週期,以及訪問指定版本的數據。這種方案的數據結構須要同時支持讀寫操做,後臺也得有線程經過清理過時的數據,要支持全量更新也是比較複雜。

COW: 寫時複製,具體的實現就是雙 Buffer 切換,具體到FeatureKV的場景,增量更新還須要把上一個版本的數據拷貝一份,再加上增量的數據。這種方案的好處是能夠設計一個生成後只讀的數據結構,只讀的數據結構能夠有更高的性能,缺點是須要雙倍的空間開銷。

爲了保證在線服務的性能,咱們採用了 COW 的方式,設計了 第一部分 中提到了只讀哈希表,來作到單機的事務 BatchGet。

RoleNum>1 的狀況:

數據分佈在不一樣機器,而不一樣機器完成數據加載的時間點不同,從分佈式的角度去看,可能沒有一個統一的版本。

一個直觀的想法,就是保存最近N份版本,而後選出每一個 Role 都有的、最新的一份版本。

N 的取值會影響存儲資源(內存、磁盤)的開銷,最少是2。爲了達到這個目的,咱們在 DataSvr 側加入了這麼兩個限制:

單個表的更新是串行的。

寫任務開始結束以前,加多一步版本對齊的邏輯,即等待全部的 kvsvr 都加載完最新的版本。

這樣咱們就能夠在只保留最近 2 個版本的狀況下,保證分佈式上擁有一個統一的版本。在 COW 的場景下,只要把另一個 Buffer 的數據延期刪除(直到下次更新才刪),就能夠了保留最近 2 個版本了,內存開銷也不會變大。

擁有全局統一的版本以後,事務 BatchGet 應該怎麼實現呢?

先發一輪 rpc 詢問各 role 的版本狀況?這樣作會讓QPS翻倍,而且下一時刻那臺機可能就發生數據更新了。

數據更新、版本變更實際上是很低頻的,大部分時刻都是返回最新一個版本就好了,而且能夠在回包的時候帶上 B-Version (即另一個 Buffer 的版本),讓 client 端在出現版本不一致的時候,能夠選出一個全局統一的版本 SyncVersion,再對不是 SyncVersion 的數據進行重試。

在數據更新的時候,數據不一致的持續時間多是分鐘級的,這種作法會帶來一波波的重試請求,影響系統的穩定性。因此咱們還作了一個優化就是緩存下這個 SyncVersion ,每次 BatchGet 的時候,若是有 SyncVersion 緩存,則直接拉取 SyncVersion 這個版本的數據。

  1. 版本回退

每一個表的元數據中有一個回退版本字段,默認是0表示不處於回退狀態,當這個字段非0,則表示回退至某個版本。

先考慮如何實現版本回退:

考慮簡單的狀況,一個表每次都是全量更新。那麼每次讓都是讓 KVSvr 從 FKV_WFS 拉取指定版本的數據到本地,走正常的全量更新流程就行了。

而後,須要考慮增量的狀況。若是一個表每次更新都是增量更新,那麼回退某個版本 Vi,就須要把 V1 到 Vi 這一段都拉到 KVSvr 本地,進行更新重放,相似於數據庫的 binlog,當累計了成千上萬的增量版本以後,這是不可能完成的事。

咱們須要有一個異步的 worker,來把一段連續的增量,以及其前面的全量版本,合併爲一個新的全量版本,相似 checkpoint 的概念,這樣就能夠保證一次回退不會涉及太多的增量版本。這個異步的 worker 的實如今 DataSvr 中。

更進一步,這裏有一個優化就是若是回退的版本在本地雙 Buffer 中,那麼只是簡單的切換一下雙 Buffer 的指針就好,能夠作到秒級回退效果。實際上不少回退操做都是回退到最後一個正常版本,極可能是上一個版本,在本地的雙 Buffer 中。

處於回退狀態的表禁止寫入數據,防止再次寫入錯誤的數據。

再考慮如何解除回退:

解除回退就是讓某個表,以回退版本的數據繼續提供服務,而且以回退版本的數據爲基礎執行後續的增量更新。

直接解除回退狀態,現網會先更新爲回退前的版本,若是還有流量的話則會讀到回退前的異常數據,這裏存在一個時間窗口。

數據的版本號要保證連續遞增,這一點在數據更新的流程中會依賴,因此不能簡單粗暴的刪除最後一段數據。

爲了不這個問題,咱們借用了COW的思想,先複製一遍。具體的實現就是把當前回退的版本,寫出一個全量的版本,做爲最新的數據版本。

這一步須要點時間,但在回退的場景下,咱們對解除回退的耗時要求並不高。只要回退夠快,解除回退是安全的,就能夠了。

十億每小時的挑戰-離線寫流程的具體設計

  1. 背景

DataSvr 主要的工做是把數據從 USER_FS 寫入 FKV_WFS,在寫入過程須要作路由切分、數據格式重建等工做,是一個流式處理的過程。

FeatureKV 中目前有三種表結構,不一樣的表結構在寫流程中有不同的處理邏輯:

MemTable: 數據全內存,索引是無序的哈希結構,容量受限於內存,離線寫邏輯簡單。

IdxTable: 索引全內存,索引是有序的數組,Key量受限於內存,離線寫邏輯較爲簡單,須要寫多一份索引。

BlkTable: 塊索引全內存,索引是有序的數據,記錄着磁盤中一個 4KB 數據塊的 begin_key 和 end_key,容量沒限制,離線寫流程複雜,須要對數據文件進行排序。

  1. 單機的 DataSvr

一開始,咱們只有 MemTable,數據都是全內存的。MemTable 的數據最大也就 200+GB,這個數據量並不大,單機處理能夠節省分佈式協同、結果合併等步驟的開銷,因此咱們有了上面的架構:

一次寫任務只由一個 DataSvr 執行。

Parser 每次處理一個輸入文件,解析出 Key-Value 數據,計算路由並把數據投遞到對應的 Que。

一個 Sender 負責處理一個 Que 的數據,底下會對應多份 FKV_FS 的文件。FKV_FS 上的一個文件只能由一個 Sender 寫入。

總的設計思想是,讓能夠並行跑的流程都並行起來,榨乾硬件資源。

具體的實現,加入了不少批量化的優化,好比對FS的IO都是帶 buffer 的,隊列數據的入隊/出隊都是 batch 的等,儘可能提升整個系統的吞吐能力。

最終,在臺 24 核機器上的寫入速度能夠達到 100MB/s,寫入 100GB 的數據只須要 20 分鐘左右。

  1. 分佈式的 DataSvr

再日後,FeatureKV 須要處理十億級Key量、TB級的數據寫入,所以咱們加入了 IdxTable 和 BlkTable 這兩種表結構,這對於寫流程的挑戰有如下兩點:

生成的數據須要有序,只有有序的數據才能作到範圍索引的效果,讓單機的key量不受內存限制。

TB 級的寫速度,100MB/s 是不夠用的,寫入 1TB 須要接近 3 小時的時間,而且這裏是不可擴展的,即使有不少不少機器,也是 3 小時,這裏須要變得能夠擴展。

先考慮數據排序的問題:

咱們得先把數據切片跑完,才能把一個 Part 的數據都拿出來,對數據進行排序,前面的數據切片相似於 MapReduce 的 Map,後續的排序就是 Reduce,Reduce 中存在着較大的計算資源開銷,須要作成分佈式的。

Map 階段複用上述的單機 DataSvr 邏輯,數據切分後會獲得一份臨時的全量結果,而後實現一個分佈式的 Reduce 邏輯,每一個 Reduce 的輸入是一份無序的數據,輸出一份有序的數據及其索引。

這種作法有一次全量寫和一次全量讀的額外開銷。

具體的流程以下圖所示,DATASVR SORTING 階段由多臺 DataSvr 參與,每一個淺藍色的方框表示一個 DataSvr 實例。

再考慮大數據量狀況下的擴展性:

參考上圖,如今 DataSvr 的排序階段其實已是分佈式的了,惟一一個單點的、沒法擴容的是數據切片階段。

實現分佈式的數據切片,有兩種作法:

一是每一個 DataSvr 處理部分輸入的 User_Part 文件,每一個 DataSvr 都會輸出 2400 個切片後的文件,那麼當一次分佈式切片有 K 個 DataSvr 實例參與,就會生成 2400 * K 個切片後的文件,後續須要把相同編號的文件合併,或者直接做爲排序階段的輸入。

二是每一個 DataSvr 負責生成部分編號的 FKV 文件,每次都讀入全量的用戶輸入,批處理生成一批編號的 FKV 文件。

第一種作法若是是處理 MemTable 或者 IdxTable,就須要後接一個 Merging 過程,來把 TMP_i_0, TMP_i_1, TMP_i_2 ... 合併爲一個 FKV_i。而處理 BlkTable 的時候,因爲其後續是有一個 Sorting 的邏輯的,只須要把 Sorting 的邏輯改成接受多個文件的輸入便可。故這種作法的壞處是在數據量較少的時候,MemTable 或者 IdxTable 採用分佈式數據切片可能會更慢,Merging 階段的耗時會比分佈式切片減小的耗時更多;

第二種作法生成的直接就是 2400 個文件,沒有後續 Merging 流程。但它會帶來讀放大的問題,假設數據被切分紅爲 T 批,就會有 T-1 次額外的全量讀開銷。在數據量大的狀況下,批數會越多,由於排序的數據須要所有都進內存,只能切得更小;

在小數據場景,單機的數據分片已經足夠了,因此咱們選用了第一種方案。

是否分佈式切分,是一個可選項,在數據量較小的狀況下,能夠不走這條路徑,回到單機 DataSvr 的處理流程。

最終,咱們獲得了一個能夠線性擴展的離線處理流程,面對10億、1TB數據的數據:

在實現 BlkTable 以前,這是一個不可能完成的任務。

在實現分佈式數據切片以前,這份數據須要 120min 才能完成寫入。

如今,咱們只須要 71min 即可以完成這份數據的寫入。

上面這一套流程,其實很像 MapReduce,是多個 Map, Reduce 過程拼接在一塊兒的結果。咱們本身實現了一遍,主要是基於性能上的考慮,能夠把系統優化到極致。

現網運營情況

FeatureKV 在如今已經部署了 10+ 個模塊,共 270+ 臺機,業務涉及看一看,搜一搜,微信廣告,小程序,微信支付,數據中心用戶畫像,附近的生活,好物圈等各種數業務,解決了離線生成的數據應用於在線服務的痛點問題,支撐着各種數據驅動業務的發展。

最大的一個模型存儲模塊有210臺機:

11億特徵/s: 日均峯值 BatchGet 次數是29w/s,平均 BatchSize 是 3900,模塊壓測時達到過 30億特徵/s。

15ms: 96.3% 的 BatchGet 請求在 15ms 內完成,99.6% 的 BatchGet 請求在 30ms 內完成。

99.999999%:99.999999% 的事務 BatchGet 執行成功。

微信廣告基於 FeatureKV 實現個性化拉取+個性化廣告位置,推薦策略可以及時更新。相比於舊的方案,拉取量和收入都取得了較大的增加,拉取+21.8%,收入+14.3%。

微信支付在面對面發券以及支付風控中都有用 FeatureKV,存儲了多份十億級的特徵,以前一天沒法更新完的數據能夠在數小時內完成更新。

總結

一開始,這類定時批量寫、在線只讀的需求不太廣泛,通常業務會用 PaxosStore 或者文件分發來解決。

但隨着愈來愈多的應用/需求都與數據有關,這些數據須要按期大規模輸入到在線服務當中,並須要很強的版本管理能力,好比用戶畫像、機器學習的模型(DNN、LR、FM)、規則字典,甚至正排/倒排索引等,所以咱們開發了 FeatureKV 來解決這類痛點問題,並取得了良好的效果。

本文首發於雲加社區公衆號:QcloudCommunity

相關文章
相關標籤/搜索