Instagram,是 Meta于 2010 年推出的一款免費提供在線圖片及視頻分享的社群應用軟件。在推出短短一年的時間里,Instagram 迅速“躥紅”,它的用戶數量從 0 增長到了 1400 萬。而在這背后,只有三名工程師在支撐。
Instagram 的成功,成為很多軟件產品學習的楷模,那么它究竟是怎么做到的?背后運用了哪些技術棧?近日,一篇文章初探了其中的秘密。
來源:https://engineercodex.substack.com/p/how-instagram-scaled-to-14-million
翻譯工具 | ChatGPT 責編 | 蘇宓
出品 | CSDN(ID:CSDNnews)
以下為譯文:
從 2010 年 10 月到 2011 年 12 月,Instagram 在短短一年多的時間里,用戶數量從 0 增長到了 1400 萬。他們僅僅依靠 3 名工程師實現了這一壯舉。
他們之所以能夠做到這一點,是因為遵循了 3 個關鍵原則并采用了可靠的技術堆棧。
Instagram 的指導原則:
1. 保持極度簡單。
2. 不要重新發明輪子。
3. 在可能的情況下使用經過驗證的、穩定的技術。
Instagram 背后的技術堆棧
早期的 Instagram 基礎設施在 AWS 上運行,使用了帶有 Ubuntu linux 的 EC2。EC2 是亞馬遜的一項服務,允許開發人員租用虛擬計算機。
為了簡化說明,這里從工程師的角度來看用戶會話的生命周期(下文標注為“Session:”),從而捋清楚 Instagram 所用到的一些技術。
前端
Session:用戶打開 Instagram 應用。
Instagram 最初于 2010 年作為 IOS 應用推出。由于 Swift 于 2014 年發布,我們可以猜測 Instagram 是使用 Objective-C 以及其他如 UIKit 的組合技術來編寫的。
負載均衡
Session:打開應用后,向后端發送請求以獲取主要的動態照片,該請求將被發送到 Instagram 的負載均衡器。
Instagram 使用了亞馬遜的彈性負載均衡器。工程師租用了3 個 Nginx 實例,并根據它們的健康狀態進行交替切換。
每個請求首先會被發送到負載均衡器,然后再路由到實際的應用服務器。
后端
Session:負載均衡器將請求發送到應用服務器,應用服務器負責保存處理請求的邏輯。
Instagram 的應用服務器使用 Django 框架以及它是用 Python/ target=_blank class=infotextkey>Python 編程語言編寫的,并選擇 Gunicorn 作為他們的 WSGI 服務器。
值得一提的是,WSGI(Web 服務器網關接口)將請求從 Web 服務器轉發到 Web 應用程序。
Instagram 使用 Fabric 在多個實例上并行運行命令。這允許他們在幾秒內部署代碼。
這些應用服務器運行在超過 25 臺亞馬遜高性能 CPU 大型服務器上。由于服務器本身是無狀態的,當需要處理更多請求時,他們可以添加更多服務器。
通用數據存儲
Session:應用服務器意識到請求需要主要動態數據。為此,讓我們假設它需要:
- 最新相關的照片 ID
- 與這些照片 ID 匹配的實際照片
- 這些照片的用戶數據。
數據庫:Postgres
Session:應用服務器從 Postgres 中獲取最新相關的照片 ID。
應用服務器會從存儲了大部分 Instagram 數據的 PostgreSQL 中提取數據,包括用戶和照片元數據。
Postgres 和 Django 之間的連接使用 Pgbouncer 進行連接池化管理。
由于 Instagram 收到的數據量很大(每秒超過 25 張照片和 90 個點贊),工程師對數據進行了分片。他們使用代碼將數千個“邏輯”分片映射到少數物理分片上。
Instagram 面臨并解決的一個有趣挑戰是生成可以按時間排序的 ID。他們生成的可按時間排序的 ID 如下:
- 用 41 位表示毫秒級時間(使用自定義時期,可提供 41 年的 ID)
- 用 13 位表示邏輯分片 ID
- 用 10 位表示自動遞增序列,模數為 1024。這意味著我們可以在每個分片中每毫秒生成 1024 個 ID
由于在 Postgres 中使用可按時間排序的 ID,應用服務器已成功接收到最新相關的照片 ID。
照片存儲:S3 和 Cloudfront
Session:應用服務器獲取與這些照片 ID 匹配的實際照片,并使用快速 CDN 鏈接,以便為用戶快速加載這些照片。
數千字節的照片存儲在 Amazon S3 中。這些照片通過 Amazon CloudFront 迅速提供給用戶。
緩存:redis 和 Memcached
Session:為了從 Postgres 中獲取用戶數據,應用服務器(Django)使用 Redis 將照片 ID 與用戶 ID 匹配。
Instagram 使用 Redis 存儲了大約 3 億張照片與創建它們的用戶 ID 的映射,以便在獲取主要動態數據、活動動態數據等時知道要查詢哪個分片。所有的 Redis 都存儲在內存中,以降低延遲,并分布在多臺機器上。
通過一些巧妙的哈希處理,Instagram 成功地將 3 億個鍵映射存儲在不到 5GB 的空間中。
為了知道要查詢哪個 Postgres 分片,需要這種 photoID 到 user ID 的鍵-值映射。
Session:由于最近已經緩存響應,通過高效的 Memcached 緩存獲取用戶數據,從 Postgres 獲取數據的速度很快。
對于一般的緩存,Instagram 使用了 Memcached。那時他們有 6 個 Memcached 實例。在 Django 上使用 Memcached 相對簡單。
有趣的事實:2 年后,即在 2013 年,Facebook 發布了一篇關于如何擴展 Memcached 以幫助他們處理每秒數十億請求的重要論文。
Session:用戶現在可以看到主頁動態,其中包含他正在關注的人的最新照片。
主從設置
Postgres 和 Redis 都在主從設置下運行,并使用 Amazon EBS(彈性塊存儲)的快照功能來頻繁備份系統。
推送通知和異步任務
Session:現在,假設用戶關閉了應用,但后來收到了一個朋友發布了一張照片的推送通知。
這個推送通知是使用 pyapns 發送的,以及 Instagram 發送出的十億多條其他推送通知。Pyapns 是一個開源的通用蘋果推送通知服務(APNS)提供商。
Session:用戶非常喜歡這張照片!所以他決定在 Twitter 上分享它。
在后端,這個任務被推送到 Gearman,這是一個任務隊列,用于分配適合的機器來處理工作。Instagram 擁有大約 200 個 Python 工作程序來消耗 Gearman 任務隊列。
Gearman 被用于多個異步任務,比如向所有用戶的粉絲(稱為粉絲傳播)推送活動信息(比如發布新照片)。
監控
Session:糟糕!Instagram 應用程序崩潰了,因為服務器上出現了錯誤,并發送了錯誤的響應。三名 Instagram 工程師立即收到警報。
Instagram 使用 Sentry,一個開源的 Django 應用程序,實時監控 Python 錯誤。
Munin 用于繪制系統范圍的指標和警告異常。Instagram 有很多自定義的 Munin 插件來跟蹤應用級別的指標,比如每秒發布的照片數量。
Pingdom 用于外部服務監控,PagerDuty 用于處理事故和通知。
最終架構概述