http://blogread.cn/it/article/5497html
Instagram 被 Facebook 以10億美金收購。團隊規模:13 人。而在被Facebook收購前的一個月,整個團隊才7名員工。python
制勝法寶:nginx
Instagram的兩個創始人git
下面一塊兒來看下這個奇蹟是怎樣搭建的?Instagram的技術實現是什麼?如下內容來自翻譯。github
當咱們與其餘工程師偶遇和交流的時候,有一個問題常常被問及,「大家的技術架構(technology stack)是怎麼樣的」?咱們以爲從較高的層次來描述Instagram的全部構成系統是一件有趣的事情;將來你可能期待更深刻的描述這些系統。這就是咱們的系統,僅僅1年時間,而且咱們活了下來,其中有一部分咱們一直在修改。一個小型團隊的初創公司,能夠在一年多一點時間發展到1400多萬用戶規模。redis
Instagram 開發團隊奉行的三個核心原則:sql
操做系統/主機數據庫
咱們在Amazon EC2上跑Ubuntu Linux 11.04 (「Natty Narwhal」),這個版本通過驗證在 EC2 上夠穩定。咱們發現以前的版本在EC2上高流量的時候都會出現各類不可預測的問題( freezing episodes)。由於只有3名工程師,咱們的需求依然在不斷的變化中,所以自託管主機不是咱們的選擇,也許將來當用戶量空前增加的時候,咱們會考慮。apache
負載均衡django
每個對Instagram 服務器的訪問都會經過負載均衡服務器;咱們使用2臺nginx機器作DNS輪詢。這種方案的缺點是當其中一臺退役時,須要花時間更新DNS。最近,咱們轉而使用Amazon的ELB(Elastic Load Balancer)負載均衡器,使用3個NGINX 實例能夠實現調入調出(and are automatically taken out of rotation if they fail a health check);咱們同時在 ELB 層停掉了 SSL , 以緩解nginx的 CPU 壓力。咱們使用Amazon的Route53服務做爲DNS服務,他們最近在AWS控制檯上增長了一套很好的GUI工具。
應用服務器
接下來是應用服務器用來處理咱們的請求。咱們在Amazon的High-CPU Extra-Large機器上運行了Django ,隨着用戶的增加,咱們已經在上面跑了25個Django實例了(幸運地,由於是無狀態的,因此很是便於水平擴展)。咱們發現咱們的個別工做負載是屬於計算密集型而非IO密集型,所以High-CPU Extra-Large類型的實例恰好提供了合適的比重(CPU和內存)。
使用 Gunicorn 做爲 WSGI 服務器。過去曾用過 Apache 下的 mod_wsgi 模塊,不過發現 Gunicorn 更容易配置而且節省 CPU 資源。使用 Fabric 加速部署。Fabric最近增長了並行模式,所以部署只須要花費幾秒鐘。
數據存儲
咱們大部分數據(用戶信息,照片的元數據、標籤等)存儲在PostgreSQL中;咱們 以前已經說了關於如何基於不一樣的Postgres 實例進行切分的。咱們的主要分片集羣包含12個四倍超大內存雲主機(且12個副本在不一樣的區域);
咱們發現亞馬遜的網絡磁盤系統(EBS)每秒的尋道能力不夠,所以,將咱們全部工做放到內存中就變得尤其重要。爲了得到合理的性能,建立了軟 RAID 以提高 IO 能力,使用的 Mdadm 工具進行 RAID 管理;
順便提一下,咱們發現vmtouch用來管理內存數據是個極好的工具,尤爲是在故障轉移時,從一臺機器到另外一臺機器,甚至沒有活動的內存概要文件的狀況。這裏是腳本,用來解析運行於一臺機器上的vmtouch 輸出並打印出相應vmtouch命令,在另外一臺機器上執行,用於匹配他當前的內存狀態;
咱們全部的PostgreSQL實例都是運行於主-備模式(Master-Replica),基於流複製,而且咱們使用EBS快照常常備份咱們的系統。爲了保證咱們的快照的一致性(原始靈感來源於ec2-consistent-snapshot)咱們使用XFS做爲咱們的文件系統,經過XFS,當進行快照時,咱們能夠凍結&解凍RAID陣列。爲了進行流複製,咱們最愛的工具是repmgr 。
對於從咱們的應用服務器鏈接到數據,咱們很早就使用了Pgbouncer作鏈接池,此舉對性能有巨大的影響。咱們發現Christophe Pettus的博客 有大量的關於Django、PostgreSQL 和Pgbouncer 祕訣的資源。
照片直接存儲在亞馬遜的S3,當前已經存儲了幾T的照片數據。咱們使用亞馬遜的CloudFront做爲咱們的CDN,這加快了全世界用戶的照片加載時間(像日本,咱們第二最受歡迎的國家)
咱們也普遍的使用了Redis ; 咱們的main feed、activity feed、sessions系統(這裏是咱們的Django session backend),和其餘 相關係統 都使用了Redis。由於全部的Redis數據都須要放在內存中,所以咱們最後使用了幾個四倍超大內存雲主機用於跑Redis。咱們的Redis也是運行於主-備模式(Master-Replica),而且常常將DB保存到磁盤,最後使用EBS快照備份這些數據(咱們發如今主機上進行導出太費勁了)。因爲Redis 容許寫入備份,使得在線故障轉移很是方便,轉移到一臺新的Redis 機器,而不須要停機。
爲了咱們的geo-search API,咱們一直使用PostgreSQL了不少個月,不事後來遷移到了Apache Solr.他有一套簡單的JSON接口,這樣咱們的應用程序相關的,只是另外一套API而已。
最後,和任何現代Web服務同樣,咱們使用了Memcached 作緩存,而且當前已經使用了6個Memcached 實例,咱們使用pylibmc & libmemcached進行鏈接。Amzon最近啓用了一個靈活的緩存服務(Elastic Cache service),可是它並不比運行咱們本身的實例便宜,所以咱們並無切換上去;
任務隊列&推送通知
當一個用戶決定分享一張Instagram 的照片到Twitter 或Facebook,或者是當咱們須要通知一個 實時訂閱者有一張新的照片貼出,咱們將這個任務推到 Gearman,一個任務隊列系統可以寫於Danga。這樣作的任務隊列異步經過意味着媒體上傳能夠儘快完成,而「重擔」能夠在後臺運行。咱們大概有200個工做實例(都用Python寫的)在給定的時間內對隊列中的任務進行消費,並分發給不一樣的服務。咱們的feed feed fan-out也使用了Gearman,這樣posting就會響應新用戶,由於他有不少followers。
對於消息推送,咱們找到的最划算的方案是https://github.com/samuraisam/pyapns,一個開源的Twisted 服務,已經爲咱們處理了超過10億條通知,而且絕對可靠。
監控
對於100多個實例,監控變得很是重要。咱們使用Munin進行圖形化度量。咱們基於 Python-Munin,也寫了不少Munin 插件。用於圖形化度量非系統級的東西(例如,每秒的簽入人數,每條照片發佈數等)咱們使用Pingdom做爲外部監控服務,PagerDuty 用於事件通知。
Python錯誤報告,咱們使用Sentry,一個Disqus的工程師寫的使人敬畏的開源的Django app。在任什麼時候間,咱們能夠開始工做,並實時的查看咱們的系統發生了什麼錯誤。
Instagram的技術變遷
創業初期:
技術更新
1、數據庫擴展
早期使用django ORM+postgresql,由於PostGIS,選擇了postgresql。(PostGIS在對象關係型數據庫PostgreSQL上增長了存儲管理空間數據的能力,至關於Oracle的spatial部分)而且數據庫部署在獨立服務器上。
由於EC2機器的最大內存爲68G,隨着照片存儲量的增長,進行垂直分區(vertical partitioning);使用django db routers,作垂直分區變得很容易;以下:照片則映射到photodb
def db_for_read(self, model): if app_label == 'photos': return 'photodb'
當照片存儲量大於60G的時候,採用水平分區(也就是所謂的「分片」sharding)
sharding帶來的問題:
一、數據的檢索,hard to know what your primary access patterns will be w/out any usage in most cases, user ID
二、當有分片變得太大的時候怎麼辦?
基於範圍的分片策略(就像MongoDB那樣)
三、性能有降低趨勢,尤爲在EC2上,緣由:disk IO,解決方法:預先切分(pre-split),即預先切分上千個邏輯切片,將它們映射到較少的物理分區節點中去。
關於相關內容,更詳細的能夠參看這裏。
2、選擇合適工具
進行緩存/反規範化數據設計
用戶上傳圖片時:
Redis適合什麼樣的場景?
不要將本身綁定在非得之內存數據庫爲主要存儲策略的方案上(don’t tie yourself to a solution where your in-memory DB is your main data store
參考連接:http://www.cnblogs.com/xiekeli/archive/2012/05/28/2520770.html