1. 程式人生 > >關於 Feed 流的幾個熱門問題

關於 Feed 流的幾個熱門問題

0x00 前言

本篇聊一下 Feed 流技術,由於這個話題在業界有豐富的實踐經驗,所以我特意選了個小的切入點,從相對微觀的角度說幾個具體的問題,避免一些無意義的重複。希望提煉實踐中的具體問題來做討論,使事情變得更有實際意義。

0x01 先行資料

0x02 關於模型

當要做一個 Feed 流,擺在我們眼前的第一個問題就是到底選推模型還是選拉模型,因為這個選擇將影響接下來一系列的架構方式。

  • 推模型 or 拉模型

推模型和拉模型各自的優缺點已經被羅列了很多了,比如推模型的儲存量大,或者拉模型的效率可能低,但如果你從無到有做這個事情,這些優缺點的羅列還是無法幫助你做出最初的決定,所謂的“知道了許多道理,還是過不好這一生”,當然除非你有實際的構造大流量 Feed 流的經驗。

然而根據我們的經驗:基於正確規範的架構和基礎設施,對於一個千萬日活量級的應用 Feed 流, 拉模型完全可以扛得住。

我想,上面這個結論是很有意義的,尤其是對中小創業公司,因為拉模型本身節省儲存資源,開發成本低,上線速度快,在業務爆發之前做這樣一個 Feed 流,有這樣一個明確經驗可以幫助你快速做出決定。

另外,上面說的千萬日活,並不是說就是拉模型的上限,而是說,如果你做到千萬日活,你將會有豐富的實踐經驗幫助你走下一步,那時也會有更多的資源讓你使用,是繼續深挖拉模型潛能,還是上推拉結合消滅效能問題,將是另外一個夠挑戰的問題了。

  • 推模型的原罪

上一節我的描述有些極端,本意上我是想給出更明確的實踐結論,因為對於推拉模型的積累對比已經夠多了,現在難的似乎是做決定時的信心。那這一節,我就來聊推模型的幾個問題。

耗儲存。推模型可以理解為給每個粉絲維護一個單獨的儲存,舉例來說,如果某個大 V 有一千萬粉絲,他發的一條內容,將被儲存一千萬份,這個儲存放大是非常可觀的。於是這裡就會常見的問題:一、有多少儲存資源能用,這些資源貴不貴?二、如果省掉這些資源儲存,響應時間效能到底能打多少折扣,這些折扣值不值?這是個時間和空間的衝突,程式設計師每天都在做這種問題的衡量,每個系統的要求基準也不一樣,我就不妄下結論了。

寫峰值。推模型有一個寫峰值的問題,通常,我們做推模型,給粉絲寫資料的時候一般是離線的,也就是大 V 釋出完內容,觸發離線寫任務推給各個粉絲。可大 V 是少數,大部分時候,都是普通使用者在釋出,寫任務沒有那麼多,這時,離線寫任務的 worker 數可能用不了幾個,可一旦大 V 釋出了內容,這個寫任務會驟增,突然來一個大峰值,如何處理這個峰值是個問題。有些方案:一、把資源排程系統做的超級棒,worker 數量自動化跟著調整,峰值來了的時候,worker 自動迅速擴容,消費離線任務,並在離線任務處理完畢之後縮容,避免資源浪費,這個排程確實需要很棒,因為大多時候,Feed 流對這些任務的要求是很嚴苛的,比如,產品上希望粉絲至少也是在分鐘級看到大 V 發的內容,甚至秒級,這對排程系統的挑戰是巨大的。二、推拉結合,大 V 走拉模型邏輯,這個方案的問題就是,你其實做了兩套系統,開發成本大。

避不開的業務邏輯。這一點是從業務邏輯開發上來說的,這個也是在具體業務開發過程中推模型讓人覺得很難受的點,就是:當我解決很多問題之後,從業務邏輯開發層面,我還是避不開很多業務邏輯。為什麼這麼說呢,就是在推模型裡,每個粉絲都存有一個屬於他的資料,但這部分資料在介面設計和資料返回上,也僅僅就是元資料,這份元資料,還是要經過很多處理才能返回給使用者,比如過濾、Format,我們希望推模型維護的那個儲存是一份儘可能乾淨的資料,但事情卻沒那麼簡單。

不過,以上是我個人的一些總結,由於在推模型上我沒有走的更遠,這些問題到底是不是真正的問題,歡迎來噴。

0x03 關於資料

模型的事情就不過多說了,再來聊幾個關於資料的具體問題。

  • 有狀態與無狀態

這是 Feed 流的 API 介面設計相關的問題。

舉個例子,在拉取 Feed 流資料時候, API 層面基於數量 offset/limit 的分頁方案是完全不行的,因為使用者 Feed 流的新資料會 insert 到流最開始位置,僅僅給出 offset 會導致分頁資料錯亂,所以會給出一種 after/limit 的分頁方案,就是有一個標誌資料,意義是“從 after 這個資料向後取 limit 條資料”;但是,這僅僅是一個乾淨的 Feed 流的情況下,在實際的業務需求中,Feed 流中的資料會更復雜,複雜到打亂這個看起來可行的分頁方式。

以分頁這個例子來說,它為什麼會這麼脆弱呢? 我總結是因為 API 的資料請求是無狀態的,使用者在取第二頁資料的時候,並不知道取第一頁資料時到底發生了什麼,僅僅知道在介面層面傳遞的幾個值(offset/after/limt),而許多時候尤其是對於 Feed 流的一些時候這些值不夠用,導致資料拉取變得棘手。

所以,如果 Feed 流的資料獲取是有狀態就好了,就像瀏覽器與伺服器之間的 Session,保持使用者一個訪問週期的上下文資料,這樣想做什麼就都好做了。

  • 資料 Format

通常,Feed 流中的資料會來自多個不同的源,最後返回給使用者之前需要做資料的 Format,這個過程是個效能黑洞,經常包含了很多 IO,你可能要讀大量儲存,讀大量 RPC來獲取到資料才能成功組裝。所以針對資料 Format 有很多效能優化的點,包括不限於:消滅慢查詢、減少呼叫放大、並行獲取資料、做好快取、操作批量。

要做好效能優化,好的結構是必需的,比如要減少呼叫放大,那就要儘量保證資料複用和批量獲取,只有你的程式碼結構好,才會有更合適的地方去獲取資料和複用資料;也同樣,只有你把可以並行部分都很清晰的摘離出來了,才能更合適地去做統一併行。

而諸如消滅慢查詢、做好快取,此類其他細節也都是重要的,這裡就不展開。

  • 過濾

幾乎所有的 Feed 流都有過濾需求,比如對已經讀過的內容進行過濾,或者對已經被作者刪除的內容進行過濾。

過濾是個具體的事情,有的時候你僅僅需要元資料就能過濾,有的時候你需要對拿到完整資料才能過濾。總結一句話就是過濾的繁瑣與否取決於產品需求,但好的結構可以讓過濾變得更符合邏輯,效能表現更好。

0x04 結語

Feed 流是個不小的系統,三言兩語只是管中窺豹,長時間沒寫分享文章了行文也變得不太流暢,希望看完這篇你會有所收穫吧。