前一篇翻譯了Instagram blog上的一篇文章《What Powers Instagram: Hundreds of Instances, Dozens of Technologies》,讓我們對Instagram 的大致技術路線有了一個大體的了解。我覺得Instagram 的工程師能夠在Instagram blog上將自己使用的技術和工具進行分享,真是難能可貴。同時,在網上看到了一份Mike Krieger在“AirBnB Tech Talk 2012”上演講的PPT,感覺受益匪淺,有必要整理學習。
- 相關統計
用戶規模:30+ million users in less than 2 years(不到2年時間,3000多萬用戶,注:在他們發布android版本后的10天已經突破4000萬了)
在發布android版本的12個小時里,他們就新增了100萬用戶
- 創建初期
兩個聯合創始人沒有任何后端的實戰經驗(這也太…)
:)就是這兩小子
注:
Mike Kriegerr:之前是一個頗為低調的工程師和用戶體驗設計師,他在一家名叫Meebo的創業公司工作了1年半。analytics & python @ meebo(在Meebo做分析,使用python );
Kevin Systrom: 畢業后在Google的收購部門工作了一年,今年28歲,隨后去到了一家從事旅行業務的創業公司Nextstop,沒有計算機學位,沒有接受過正式培訓, 但他下班后堅持自學編程,在這家創業公司被Facebook以人才收購的方式收購后,Systrom又去早期的Twitter實習了一段時間。
最初存儲采用CouchDB(Apache CouchDB 是一個面向文檔的數據庫管理系統)
最初只有一台服務器(在洛杉磯),比一台比MacBook Pro強不到哪里去。
上線第一天有25000注冊用戶。
上線初期的問題(總是些微不足道的問題):
1、favicon.ico :因為忘記favicon.ico圖標文件,在Django上引起大量404錯誤;
2、
ulimit -n
,設置Linux內核可以同時打開的文件描述符的最大值,例如size為4092。3、
memcached -t 4
,設置用於處理請求的線程數.4、prefork/postfork 線程的預加載還是后加載問題,類似於線程池吧?
- 技術遷徙
let’s move to EC2,系統擴展就像對100碼速度行駛的汽車更換所有部件;
- Instagram 的哲學
保持簡單
為了最小的運營負擔而優化程序
利用一切能用到的工具
- 一、數據庫擴展
早期使用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帶來的問題:
1、數據的檢索,hard to know what your primary access patterns will be w/out any usage in most cases, user ID
2、當有分片變得太大的時候怎么辦?
基於范圍的分片策略(就像MongoDB那樣)
3、性能有下降趨勢,尤其在EC2上,原因:disk IO,解決方法:預先切分(pre-split),即預先切分上千個邏輯切片,將它們映射到較少的物理分區節點中去。
關於相關內容,更詳細的可以參看這里;
- 二、選擇合適工具
進行緩存/反規范化數據設計
用戶上傳圖片時:
1、用戶上傳帶有標題信息和地理位置信息(可選)的照片;
2、同步寫到這個用戶對應的數據庫(分片)中;
3、進行隊列化處理
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適合什么樣的場景:
1、數據結構相對有限;
2、對頻繁GET的地方,對復雜對象進行緩存;
不要將自己綁定在非得以內存數據庫為主要存儲策略的方案上(don’t tie yourself to a solution where your in-memory DB is your main data store
關於Follow圖譜
第一版:簡單的數據庫表格(source id, target id, status)
需要來回答如下查詢:我關注誰?誰關注我?我是否關注某人?某人是否關注我?
當數據庫的壓力變大時,instagram開始在Redis中並發存儲關注圖譜,但這也帶來了內容一致性(consistency)的問題。不一致性一度帶來緩存失效問題。
PostGIS結合輕量的memcached緩存,可以支撐上萬的請求量。
需要注意點:
1、核心數據存儲部分有一個萬能的組件支撐,就像:Redis;
2、千萬不要試想用兩種工具去做同一個工作;
- 三、保持敏捷
2010年: 2位工程師
2011年: 3 位工程師
2012年: 5 位工程師
制勝法寶:
1、廣泛的單元測試和功能測試
2、堅持DRY(Don’t Repeat Yourself)原則
3、使用通知/信號機制實現解耦
4、我們大部分工作使用Python來完成,只有逼不得已的時候,才會用C
5、頻繁的代碼復查,盡量保持“智慧共享”。(frequent code reviews, pull requests to keep things in the ‘shared brain’)
6、廣泛的系統監控
- 四、往android平台擴展
12小時增加100萬新用戶
偉大的工具可以使讀取更具擴展性,例如:redis: slaveof <host> <port>(SLAVEOF 命令用於在 Redis 運行時動態地修改復制(replication)功能的行為)
更短的迭代周期
不要重復發明輪子,例如想開發一個系統監控的守護進程,完全沒有必要,HAProxy完全能勝任這一工作。
周圍要有強大的技術顧問;
技術團隊保持開放的氛圍;
give back; e.g. node2dm(我理解的意思是:回報開源世界,例如:node2dm,一個出自instagram的node.js服務器,用來向安卓C2DM服務提交推送請求)
關注優化,如何是我們的系統速度快上一倍?
staying nimble = remind yourself of what’s important(保持敏捷 = 時刻提醒自己,什么才是你最重要的)
前所未有的時代,兩個后端工程師能夠支撐3000萬用戶規模的系統,關鍵字是: simplicity(簡單)
cleanest solution with the fewest moving parts as possible(使用最少部件,最干凈的解決方案)
don’t over-optimize or expect to know ahead of time how site will scale(不要過度的優化,除非你提前知道自己的系統將如何擴展)
don’t think “someone else will join & take care of this”
因為這個PPT本身也傳承了instagram的simplicity哲學,因此很多信息只能靠猜,同時因為自己對相關技術認識還比較欠缺,無法很好的將其中的內容貫穿起來,整個內容翻譯下來有點支離破碎的感覺,歡迎高手拍磚指正。