100 億數據 1 萬屬性數據架構設計

DerNaquin 7年前發布 | 11K 次閱讀 軟件架構 數據庫

對于 version + ext 方案,還是有很多朋友質疑“線上不可能這么用”。 本篇將講述一下 58 同城最核心的數據“帖子”的架構實現技術細節,說明不僅不是“不可能這么用”,而是大數據,可變屬性,高吞吐場景下的“常用手段”。

一、背景描述及業務介紹

問:什么是數據庫擴展的 version + ext 方案?

使用 ext 來承載不同業務需求的個性化屬性,使用 version 來標識 ext 里各個字段的含義 。

例如上述 user 表:

verion=0 表示 ext 里是 passwd/nick

version=1 表示 ext 里是 passwd/nick/age/sex

優點?

( 1 )可以隨時動態擴展屬性,擴展性好

( 2 )新舊兩種數據可以同時存在,兼容性好

不足?

( 1 ) ext 里的字段無法建立索引

( 2 ) ext 里的 key 值有大量冗余,建議 key 短一些

問: 什么是 58 同城最核心的數據?

58 同城是一個信息平臺,有很多垂直品類:招聘、房產、二手物品、二手車、黃頁等等,每個品類又有很多子品類,不管哪個品類, 最核心的數據都是“帖子信息” (業務像一個大論壇?)。

問: 帖子信息有什么特點?

大家去 58 同城的首頁上看看就知道了:

( 1 ) 每個品類的屬性千差萬別 ,招聘帖子和二手帖子屬性完全不同,二手手機和二手家電的屬性又完全不同,目前恐怕有 近萬個屬性

( 2 ) 帖子量很大, 100 億級別

( 3 ) 每個屬性上都有查詢需求 (各組合屬性上都可能有組合查詢需求) ,招聘要查職位 / 經驗 / 薪酬范圍,二手手機要查顏色 / 價格 / 型號,二手要查冰箱 / 洗衣機 / 空調

( 4 ) 查詢量很大,每秒幾 10 萬級別

如何解決 100 億數據量, 1 萬屬性,多屬性組合查詢, 10 萬并發查詢 的技術難題,是今天要討論的內容。

二、最容易想到的方案

每個公司的發展都是一個從小到大的過程,撇開并發量和數據量不談,先看看

( 1 )如何實現屬性擴展性需求

( 2 )多屬性組合查詢需求

最開始,可能只有一個 招聘品類 ,那帖子表可能是這么設計的:

tiezi(tid,uid, c1, c2, c3)

那如何滿足各屬性之間的組合查詢需求呢?

最容易想到的是通過組合索引:

index_1(c1,c2) index_2(c2, c3) index_3(c1, c3)

隨著業務的發展,又新增了一個 房產類別 ,新增了若干屬性,新增了若干組合查詢,于是帖子表變成了:

tiezi(tid,uid, c1, c2, c3, c10, c11, c12, c13)

其中 c1,c2,c3 是招聘類別屬性, c10,c11,c12,c13 是房產類別屬性,這兩塊屬性一般沒有組合查詢需求

但為了滿足房產類別的查詢需求,又要建立了若干組合索引(不敢想有多少個索引能覆蓋所有兩屬性查詢,三屬性查詢)

是不是發現玩不下去了?

三、友商的玩法

新增屬性是一種擴展方式,新增表也是一種方式 ,有友商是這么玩的,按照業務進行垂直拆分:

tiezi_zhaopin(tid,uid, c1, c2, c3)

tiezi_fangchan(tid,uid, c10, c11, c12, c13)

這些表,這些服務維護在不同的部門,不同的研發同學手里,看上去各業務線靈活性強,這恰恰是悲劇的開始 :

( 1 ) tid 如何規范?

( 2 )屬性如何規范?

( 3 )按照 uid 來查詢怎么辦(查詢自己發布的所有帖子)?

( 4 )按照時間來查詢怎么辦(最新發布的帖子)?

( 5 )跨品類查詢怎么辦(例如首頁搜索框)?

( 6 )技術范圍的擴散,有的用 mongo 存儲,有的用 mysql 存儲,有的自研存儲

( 7 )重復開發了不少組件

( 8 )維護成本過高

( 9 ) …

想想看,電商的商品表,不可能一個類目一個表的。

四、 58 同城的玩法

【統一帖子中心服務】

平臺型創業型公司,可能有多個品類,例如 58 同城的招聘房產二手,很多異構數據的存儲需求,到底是分還是合,無需糾結: 基礎數據基礎服務的統一 ,無疑是 58 同城技術路線發展 roadmap 上最正確的決策之一 ,把這個方針堅持下來, @ 老崔 @ 曉飛 這些高瞻遠矚的先賢功不可沒,業務線會有“擴展性”“靈活性”上的微詞,后文看看先賢們如何通過一些巧妙的技術方案來解決的。

如何將不同品類,異構的數據統一存儲起來,采用的就是類似 version+ext 的方式:

tiezi(tid,uid, time, title, cate, subcate, xxid, ext)

( 1 ) 一些通用的字段抽取出來單獨存儲

( 2 ) 通過 cate, subcate, xxid 等來定義 ext 是何種含義 (和 version 有點像?)

( 3 )通過 ext 來存儲不同業務線的個性化需求

例如招聘的帖子:

ext : {“job”:”driver”,”salary”:8000,”location”:”bj”}

而二手的帖子:

ext : {”type”:”iphone”,”money”:3500}

58 同城最核心的帖子數據, 100 億的數據量,分 256 庫,異構數據 mysql 存儲,上層架了一個服務,使用 memcache 做緩存,就是這樣一個簡單的架構,一直堅持這這么多年。上層的這個服務,就是 58 同城最核心的統一服務 IMC ( Imformation Management Center ) ,注意這個最核心,是沒有之一。

解決了海量異構數據的存儲問題,遇到的 新問題 是:

( 1 )每條記錄 ext 內 key 都需要重復存儲,占據了大量的空間,能否壓縮存儲

( 2 ) cateid 已經不足以描述 ext 內的內容,品類有層級,深度不確定, ext 能否具備自描述性

( 3 )隨時可以增加屬性,保證擴展性

【統一類目屬性服務】

每個業務有多少屬性,這些屬性是什么含義,值的約束等揉不到帖子服務里,怎么辦呢?

58 同城的先賢們 抽象出一個統一的類目、屬性服務,單獨來管理這些信息 ,而帖子庫 ext 字段里 json 的 key ,統一由數字來表示,減少存儲空間 。

如上圖所示, json 里的 key 不再是 ”salary” ”location” ”money”  這樣的長字符串了,取而代之的是數字 1,2,3,4 ,這些 數字是什么含義,屬于哪個子分類,值的校驗約束,統一都存儲在類目、屬性服務里 。

這個表里對帖子中心服務里 ext 字段里的數字 key 進行了解釋:

1 代表 job ,屬于招聘品類下 100 子品類,其 value 必須是一個小于 32 的 [a-z] 字符

4 代表 type ,屬于二手品類下 200 子品類,其 value 必須是一個 short

這樣就對原來帖子表 ext 里的

ext : {“1”:”driver”,”2”:8000,”3”:”bj”}

ext : {”4”:”iphone”,”5”:3500}

key 和 value 都做了統一約束 。

除此之外, 如果 ext 里某個 key 的 value 不是正則校驗的值,而是枚舉值時,需要有一個對值進行限定的枚舉表來進行校驗 :

這個枚舉校驗,說明 key=4 的屬性(對應屬性表里二手,手機類型字段),其值不只是要進行“ short 類型”校驗,而是 value 必須是固定的枚舉值。

ext : {”4”:”iphone”,”5”:3500} 這個 ext 就是不合法的( key=4 的 value=iphone 不合法),合法的應該為

ext : {”4”:”5”,”5”:3500}

此外,類目屬性服務還能記錄類目之間的層級關系:

( 1 )一級類目是招聘、房產、二手 …

( 2 )二手下有二級類目二手家具、二手手機 …

( 3 )二手手機下有三級類目二手 iphone ,二手小米,二手三星 …

( 4 ) …

協助解釋 58 同城最核心的帖子數據,描述品類層級關系,保證各類目屬性擴展性,保證各屬性值合理性校驗,就是 58 同城另一個統一的核心服務 CMC ( Category Management Center ) 。

多提一句,類目、屬性服務像不像電商系統里的 SKU 擴展服務?

( 1 )品類層級關系,對應電商里的類別層級體系

( 2 )屬性擴展,對應電商里各類別商品 SKU 的屬性

( 3 )枚舉值校驗,對應屬性的枚舉值,例如顏色:紅,黃,藍

解決了 key 壓縮, key 描述, key 擴展, value 校驗,品類層級的問題, 還有這樣的一個問題 沒有解決:每個品類下帖子的屬性各不相同,查詢需求各不相同,如何解決 100 億數據量, 1 萬屬性的查詢需求,是 58 同城面臨的新問題。

【統一檢索服務】

數據量很大的時候,不同屬性上的查詢需求,不可能通過組合索引來滿足所有查詢需求,怎么辦呢?

58 同城的先賢們,從一早就確定了 “外置索引,統一檢索服務”的技術路線 :

( 1 )數據庫提供“帖子 id ”的正排查詢需求

( 2 )所有非“帖子 id ”的個性化檢索需求,統一走外置索引

元數據與索引數據的操作遵循:

(1)對帖子進行 tid 正排查詢,直接訪問帖子服務

(2)對帖子進行修改,帖子服務通知檢索服務,同時對索引進行修改

(3)對帖子進行復雜查詢,通過檢索服務滿足需求

這個扛起 58 同城 80% 終端請求(不管來自 PC 還是 APP ,不管是主頁、城市頁、分類頁、列表頁、詳情頁,很可能這個請求最終會是一個檢索請求)的服務,就是 58 同城另一個統一的核心服務 E-search ,這個搜索引擎的每一行代碼都來自 58 同城 @ 老崔 @ 老龔 等先賢們,目前系統維護者,就是“架構師之路”里屢次提到的 @ 龍神 。

對于這個服務的架構,簡單展開說明一下:

為應對 100 億級別數據量、幾十萬級別的吞吐量,業務線各種復雜的復雜檢索查詢, 擴展性是設計重點 :

( 1 ) 統一的 Java 代理層集群 ,其無狀態性能夠保證增加機器就能擴充系統性能

( 2 ) 統一的合并層 C 服務集群 ,其無狀態性也能夠保證增加機器就能擴充系統性能

( 3 ) 搜索內核檢索層 C 服務集群 , 服務和索引數據部署在同一臺機器上 ,服務啟動時可以加載索引數據到內存,請求訪問時從內存中 load 數據,訪問速度很快

( 3.1 )為了滿足數據容量的擴展性, 索引數據進行了水平切分 ,增加切分份數,就能夠無限擴展性能

( 3.2 )為了滿足一份數據的性能擴展性, 同一份數據進行了冗余 ,理論上做到增加機器就無限擴展性能

系統時延, 100 億級別帖子檢索,包含請求分合,拉鏈求交集,從 merger 層均可以做到 10ms 返回 。

58 同城的帖子業務, 一致性不是主要矛盾 , E-search 會定期全量重建索引,以保證即使數據不一致,也不會持續很長的時間。

五、總結

文章寫了很長,最后做一個簡單總結,面對 100 億數據量, 1 萬列屬性, 10 萬吞吐量的業務需求 , 58 同城的經驗,是采用了 元數據服務、屬性服務、搜索服務 來解決的。

 

來自:http://mp.weixin.qq.com/s/3O3kPSwV-tAeYdy2ZRACpg

 

 本文由用戶 DerNaquin 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!