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