圖解系統設計之Instagram
0 簡介
Instagram,分享帶有字幕的照片和視頻的免費社交應用。帖子可使用標簽和地理標簽進行組織,使其可搜索。若標記,帖子對粉絲和公眾可見。用戶可將配置文件設置為私人以限制對粉絲的訪問。
1 需求
1.1 功能性
- 發布照片和視頻:用戶可發布照片和視頻
- 關注/取關用戶:用戶可關注/取關其他用戶
- 點贊或點踩帖子:用戶可以對他們關注的帳戶的帖子進行點贊或不喜歡
- 搜索照片和視頻:用戶可根據字幕和位置搜索照片和視頻
- 生成新聞饋送:用戶可查看新聞饋送。包含他們關注的所有用戶的照片和視頻(按時間順序)。用戶還可以在其新聞饋送中查看建議的和推廣的照片
1.2 非功能性
- 可擴展性:該系統在計算資源和存儲方面應具有擴展性,以處理數百萬用戶
- 延遲:生成新聞饋送的延遲應該很低
- 可用性:系統應高度可用
- 持久性:任何上傳的內容(照片和視頻)都不能丟
- 一致性:可在一致性稍微妥協。若內容(照片或視頻)需一段時間才能在遠程區域的關注者信息流中顯示,也可接受
- 可靠性:系統須能容忍硬件、軟件故障
2 存儲模式
2.1 實體
- 用戶:存儲所有與用戶相關的數據,如ID、姓名、電子郵件、簡介、位置、帳戶創建日期、上次登錄時間等。
- 關注者:存儲用戶關系。Instagram有個單向關系,如若用戶 A 接受用戶 B 的關注請求,則用戶 B 可查看用戶 A 的帖子,但反之不成立
- 照片:存儲所有與照片相關的信息,如ID、位置、字幕、創建時間等。還需保留用戶 ID 以確定哪張照片屬于哪個用戶。用戶 ID 是來自用戶表的外鍵
- 視頻:存儲所有與視頻相關的信息,如ID、位置、字幕、創建時間等。還需保留用戶 ID 以確定哪個視頻屬于哪個用戶。用戶 ID 來自用戶表的外鍵
2.2 Instagram的數據模型
圖片
2.3 SQL or NoSQL?
我們的數據本質是關系型,并且我們需要數據的順序(帖子應按時間順序出現)和即使在故障的情況下也不會丟失數據(數據持久性)。此外,我們的例子中,我們將從關系查詢中受益,如根據用戶 ID 獲取關注者或圖像。因此,基于 SQL 的數據庫滿足這些要求。
因此,選擇關系數據庫,并在該數據庫存儲相關數據。
3 頂層設計
圖片
- 負載均衡器:平衡來自終端用戶的請求負載
- 應用服務器:向終端用戶托管我們的服務
- 關系數據庫:存儲我們的數據
- Blob 存儲:存儲用戶上傳的照片和視頻
4 詳細設計
4.1 上傳、查看和搜索照片
客戶端請求上傳照片,負載均衡器將請求傳遞給任何一個應用服務器,后者向數據庫添加一個條目。向用戶發送已成功存儲照片的更新。若遇到錯誤,也會通知用戶。
查看照片的過程與上述流程類似。客戶端請求查看一張照片,從數據庫中獲取與請求匹配的合適的照片,并顯示給用戶。客戶端還可以提供關鍵字來搜索特定圖像。
讀請求多于寫請求,并將內容上傳到系統中需要時間。若分離讀(上傳)寫服務,效率會更高。 由許多服務器操作的多個服務處理相關請求。讀服 務執行為用戶獲取所需內容的任務,而寫服務有助于將內容上傳到系統。
還需緩存數據來處理數百萬次讀取。它通過使獲取過程快速來改善用戶體驗。我們還將選擇延遲加載,這可以最大限度地減少客戶端的等待時間。它允許我們在用戶滾動時加載內容,從而節省帶寬,并專注于加載用戶當前正在查看的內容。這改善了在 Instagram 上查看或搜索特定照片或視頻的延遲。
照片上的讀/寫操作:
圖片
4.2 生成timeline
① 拉取方式
當用戶打開他們的 Instagram 時,我們發送timeline生成的請求:
- 先獲取用戶關注的人列表
- 獲取他們最近發布的照片
- 將其存儲在隊列中并顯示給用戶
但這種方法響應***較慢***,因為每次用戶打開 Instagram 時我們都會生成timeline
可通過離線生成timeline,大大減少用戶感知到的延遲。如在用戶打開 Instagram 前,我們定義一個服務,該服務會提前為用戶獲取相關數據,當該人打開 Instagram 時,它會顯示timeline。這減少了顯示timeline的延遲率。
② 推送方法
推送方法中,每個用戶都負責將他們發布的內容推送給關注他們的人的timeline。在之前的方法中,從每個關注者那里拉取帖子,但在當前方法中,我們將帖子推送給每個關注者。
現在只需獲取推送到該特定用戶的的數據來生成timeline。
基于推送的方法:
圖片
混合方法 — 讓我們將我們的用戶分為兩類:
- 基于推送的用戶:關注者數量為數百或數千的用戶。
- 基于拉取的用戶:關注者數量為數十萬或數百萬的名人用戶。
時間軸服務從基于拉取的關注者那里拉取數據并將其添加到用戶的時間軸中。基于推送的用戶將他們的帖子推送到他們關注者的時間軸服務,以便時間軸服務可以將其添加到用戶的時間軸中。
4.3 在哪存儲時間軸?
我們針對 userID 將用戶的時間表存儲在鍵值存儲中。在請求時,我們從鍵值存儲中獲取數據并顯示給用戶。鍵是 userID,而值是時間軸內容(指向照片和視頻的鏈接)。因為值的存儲大小通常限制在幾兆字節內,所以當我們接近大小限制時,我們可以將時間軸數據存儲在 blob 中,并將指向 blob 的鏈接放在鍵的值中。
4.4 Instagram 故事
可向我們的 Instagram 添加一個名為故事的新功能。在故事功能中,用戶可以添加一張照片,該照片僅可供他人在 24 小時內查看。我們可以通過在表中維護一個選項來實現這一點,我們可以在其中存儲故事的持續時間。我們可以將其設置為 24 小時,任務計劃程序刪除超過 24 小時限制的條目。
5 最終設計
Instagram 的最終設計:
圖片
6 評估
- 可擴展性:我們可以向應用服務層添加更多服務器以使可擴展性更好并處理來自客戶端的大量請求。我們還可以增加數據庫的數量以存儲不斷增長的用戶數據。
- 延遲:使用緩存和 CDN 已減少了獲取內容的時間。
- 可用性:通過使用跨全球復制的存儲和數據庫使系統可用于用戶。
- 持久性:擁有持久化存儲,可維護數據的備份,因此任何上傳的內容(照片和視頻)都不會丟失。
- 一致性:使用了 blob 存儲和數據庫等存儲來保持數據的全局一致性。
- 可靠性:數據庫處理復制和冗余,因此我們的系統保持可靠,數據不會丟失。負載平衡層會路由繞過失敗服務器的請求
參考:
- 編程嚴選網