Instagram的技術架構

http://blogread.cn/it/article/5497html

 Instagram 被 Facebook 以10億美金收購。團隊規模:13 人。而在被Facebook收購前的一個月,整個團隊才7名員工。python

  • 2010年: 2位工程師
  • 2011年: 3 位工程師
  • 2012年: 5 位工程師

    制勝法寶:nginx

  • 普遍的單元測試和功能測試
  • 堅持DRY(Don’t Repeat Yourself)原則
  • 使用通知/信號機制實現解耦
  • 咱們大部分工做使用Python來完成,只有逼不得已的時候,纔會用C
  • 頻繁的代碼複查,儘可能保持「智慧共享」。(frequent code reviews, pull requests to keep things in the ‘shared brain’)
  • 普遍的系統監控

    Instagram的兩個創始人git

  • Mike Kriegerr:以前是一個頗爲低調的工程師和用戶體驗設計師,他在一家名叫Meebo的創業公司工做了1年半。analytics & python @ meebo(在Meebo作分析,使用python );
  • Kevin Systrom:畢業後在Google的收購部門工做了一年,今年28歲,隨後去到了一家從事旅行業務的創業公司Nextstop,沒有計算機學位,沒有接受過正式培訓, 但他下班後堅持自學編程,在這家創業公司被Facebook以人才收購的方式收購後,Systrom又去早期的Twitter實習了一段時間。

    下面一塊兒來看下這個奇蹟是怎樣搭建的?Instagram的技術實現是什麼?如下內容來自翻譯。github

    當咱們與其餘工程師偶遇和交流的時候,有一個問題常常被問及,「大家的技術架構(technology stack)是怎麼樣的」?咱們以爲從較高的層次來描述Instagram的全部構成系統是一件有趣的事情;將來你可能期待更深刻的描述這些系統。這就是咱們的系統,僅僅1年時間,而且咱們活了下來,其中有一部分咱們一直在修改。一個小型團隊的初創公司,能夠在一年多一點時間發展到1400多萬用戶規模。redis

    Instagram 開發團隊奉行的三個核心原則:sql

  • Keep it very simple (極簡主義)
  • Don’t re-invent the wheel (不重複發明輪子)
  • Go with proven and solid technologies when you can(能用就用靠譜的技術)

    操做系統/主機數據庫

    咱們在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。在任什麼時候間,咱們能夠開始工做,並實時的查看咱們的系統發生了什麼錯誤。

    以上內容翻譯自:http://instagram-engineering.tumblr.com/post/13649370142/what-powers-instagram-hundreds-of-instances-dozens-of

    Instagram的技術變遷

    創業初期:

  • 初存儲採用CouchDB(Apache CouchDB 是一個面向文檔的數據庫管理系統)
  • 最初只有一臺服務器(在洛杉磯),比一臺比MacBook Pro強不到哪裏去。

    技術更新

    

    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、選擇合適工具

    進行緩存/反規範化數據設計

    用戶上傳圖片時:

  • 用戶上傳帶有標題信息和地理位置信息(可選)的照片;
  • 同步寫到這個用戶對應的數據庫(分片)中;
  • 進行隊列化處理
  • a、若是帶有地理位置信息,經過異步的POST請求,將這個圖片的信息送到Solr(Instagram 用於geo-search API的全文檢索服務器)。
  • b、跟隨者的信息分發(follower delivery),即告訴個人follower ,我發佈了新的照片。如何來實現的呢?每一個用戶都有一個follower 列表,新照片上傳時會把照片ID發送給列表中的每個用戶,用Redis 來處理這一業務簡直太棒了,快速插入,快速子集化(rapid subsets,什麼意思?是指獲取部分數據嗎?
  • c、when time to render a feed,we take small # of IDs, go look up info in memcached(當須要生成feed的時候,咱們經過ID+#的格式,直接在memcached中查找信息)

    Redis適合什麼樣的場景?

  • 數據結構相對有限;
  • 對頻繁GET的地方,對複雜對象進行緩存;

    不要將本身綁定在非得之內存數據庫爲主要存儲策略的方案上(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

相關文章
相關標籤/搜索