Digg架構(gòu)史:無數(shù)個如果會帶來無數(shù)個故事
譯文【51CTO精選譯文】編者按:之前一個月,Digg宣告被Betaworks收購,很多工程師由此成為了新公司的一員,本文作者Will Larson便是其中之一。這篇博客不是要討論Digg的產(chǎn)品決策或者是未來的計劃,而是純粹討論Digg背后的技術(shù)實現(xiàn)。Digg的興起,衰落,背后的工程團隊也經(jīng)歷了各種重組。從幾個人開始到四十多人,再縮減到十數(shù)人,團隊的管理發(fā)生了怎樣的變化?Digg的研發(fā)團隊是如何進行開發(fā)、測試與交付的?Will介紹了很多好玩的故事,對其他技術(shù)團隊而言,是寶貴的經(jīng)驗。
以下是Will博客的全文翻譯。
一個月之前,隨著Digg v1的二度啟動,歷史似乎再一次回到原點。而我們對于Digg的記憶也隨著四個月前Digg技術(shù)團隊加入SocialCode而逐漸模糊。現(xiàn)在似乎是回顧過去的最佳時機,讓我們一起來看看從2010年5月到2012年5月,Digg.com是如何在杰出的系統(tǒng)及團隊手中一步步構(gòu)筑成形的。
本文無心涉及任何爭論、也不打算渲染過多細節(jié),我們要做的只是告訴大家自己的工作經(jīng)歷與所建立的架構(gòu)。
團隊結(jié)構(gòu)、規(guī)模及組織方式
我們首先要介紹的是公司規(guī)模、團隊組織方式以及一系列裁員、招聘給人員結(jié)構(gòu)帶來的影響,這算是必要的背景介紹。
出于文章核心話題的考慮,我不會討論與銷售、財務、廣告管理、設計、人力資源、業(yè)務拓展團隊等有關(guān)的內(nèi)容;他們當然也是公司的重要組成部分、曾為企業(yè)帶來不可磨滅的貢獻,但這并不是本文要討論的主題。
我們的故事從一套非常傳統(tǒng)的企業(yè)布局開始,這里擁有特色鮮明的產(chǎn)品、工程技術(shù)及運營管理機制。產(chǎn)品團隊規(guī)模很小,只有四名成員、運營團隊則擁有大約八位工程師、品質(zhì)保障部門有六位工程師、而開發(fā)團隊則包含大約二十位開發(fā)人員。
開發(fā)團隊本身的結(jié)構(gòu)很單純,包括四大橫向部門(前端、API、平臺以及基礎設施)與兩大縱向部門(廣告和分析)。產(chǎn)品團隊的運營工作由功能性劃分、遵循縱向管理機制,協(xié)作方案則采用與各開發(fā)團隊橫向聯(lián)合的方式。
在經(jīng)歷了數(shù)次裁員及集體離職的沖擊之后,組織結(jié)構(gòu)最終回歸到極簡化的初始狀態(tài)。
在過去的一年中,我們的運營團隊只有三位成員、工程技術(shù)團隊有七位成員,而廣告團隊則有四位成員。
代碼審查與持續(xù)部署
在處理核心開發(fā)實踐的階段,我們的工程師隊伍一度擴張到四十人,但隨后又縮減為十四人。現(xiàn)在我們來看看整個開發(fā)實踐流程,包括如何處理合并工作、審查并部署代碼。
現(xiàn)在具體闡述以上流程圖所表達的信息:
1. 我們使用Git作為源代碼控制工具,使用Gerrit作為代碼審查工具。每一段代碼都需要接受審查并獲得批準,同時必須通過所有單元測試。
2. 每當有補丁集被提交至Gerrit做代碼審查,Jenkins都會自動運行其單元測試流程,并在測試結(jié)束后將成功或者失敗結(jié)果遞交Gerrit作為審查依據(jù)。
也就是說,代碼審查人員不必在那些被自動流程檢測出問題的補丁身上浪費時間。這同時意味著我們從來不會把那些無法通過單元測試的殘缺代碼合并到Git資源庫當中。
3. 一旦補丁集通過了Gerrit測試并獲得代碼審查人員的批準,這些代碼就會被合并到Git主分支當中,并通過Puppet以自動化形式部署到測試環(huán)境下。在順利部署到測試環(huán)境下并成功通過了集成在該環(huán)境中的測試流程后,這些新的補丁集就會被合并到Git中的產(chǎn)品分支里。
4. 我們以手動方式處理Jenkins工作并部署至產(chǎn)品環(huán)境,更新代碼的部署工作則由Puppet負責。
接下來我們著手進行產(chǎn)品的持續(xù)部署,但在經(jīng)歷了幾次嚴重的部署事故之后,我們決定委派專項人員處理這類工作,直到確認所有產(chǎn)品化流程都完全達到我們的預定效果。
如果遇上不得不采取持續(xù)部署的情況,我們決定進一步改善自己的測試機制,以保證盡量不讓問題漏網(wǎng)。但這么做有點事倍功半,我們其實沒那么多時間做這些繁瑣的工作。
在我看來,這套審查、測試及代碼部署系統(tǒng)堪稱Digg項目成功的最大功臣,同時也是代碼部署工作的一大建設性突破。它的結(jié)構(gòu)非常科學,足以在保證代碼標準的同時承受技術(shù)團隊由四十人縮減為十四人所帶來的人力匱乏。
應急流程與實踐
我們零零散散采用過很多實踐方案,但大多數(shù)都是被現(xiàn)狀推著走,而不是提前做好了充分準備。
1. 剛開始我們將單元測試的覆蓋率定得非常高,但隨著團隊規(guī)模的萎縮,我們不得不放棄了對新測試內(nèi)容的補充。這顯然算不上明智的決定,但在當時的情況下,我們不得不棄車保帥。經(jīng)過討論,我們認為單元測試在避免關(guān)鍵性故障方面的效果并不理想,例如在生產(chǎn)負荷下與多種組件相關(guān)的系統(tǒng)問題以及前端渲染問題等。
單元測試是我們的驕傲,在之后的幾年中它一直努力工作并幫我們解決了很多大麻煩。而Selenium測試則沒那么好運,它幾乎在我們停止維護的同時就瞬間失靈了,而且隨品質(zhì)保障團隊的離去一道徹底告別了我們。
2. 我們利用Thrift來定義并區(qū)分前端及平臺團隊的專屬接口,這些接口的作用是為不同團隊之間的溝通與協(xié)作提供橋梁。當然我們也果斷舍棄了很多存在設計缺陷的接口,它們都或多或少給工作造成過負面影響。不過總體而言,利用Thrift來定義團隊之間的類型與接口非常明智,它為我們提供了非常實用的溝通渠道。
3. 我們很少會對現(xiàn)有Thrift接口進行改動,一般更傾向于針對需要的功能推出新接口、更新客戶端使功能奏效然后刪除舊接口。這種處理方式有點尷尬,但是由于我們是以獨立方式分別部署前端及后端代碼的(而且會花幾分鐘時間把全部前端或后端服務器跑一遍),因此這是最安全也最理智的方式。畢竟隨意改動會帶來不可知的后果,我們可不想讓多年的心血毀在自己魯莽的嘗試中。
4. 我們利用一種新機制來啟動所有前端變更,并將其帶入用戶的子集中或者在出現(xiàn)問題時加以禁用。這種方式令我們將部署與試運行分離開來,進而保證了代碼部署工作的安全性與穩(wěn)定性,同時也賦予了我們準時完成新功能開發(fā)的能力。
起初我們打算利用這種機制對新功能進行A/B測試,但后來我們發(fā)現(xiàn)它最大的價值在于管理發(fā)行版以及收集來自受信任用戶群組的反饋意見。
我們還啟用了一些后端功能,希望借此解決極端情況下的性能或負載沖擊。萬事想在前頭才好,否則出現(xiàn)問題時我們只能盯著Jenkins的進度條手足無措了。
聊完了過去的開發(fā)歷程,我們再來看看開發(fā)出的系統(tǒng)成品。
康威如是說,或者叫“架構(gòu)”
如果大家看了我們在設計v4架構(gòu)時所采用的組織結(jié)構(gòu),再看看我們開發(fā)出的架構(gòu),就會發(fā)現(xiàn)這基本上就是康威定律的現(xiàn)實版體現(xiàn)(編輯注:康威定律根據(jù)計算機科學家Melvin Conway而命名,定律的大意就是:“任何一個設計系統(tǒng)的團隊,其設計出來的架構(gòu)總會帶著團隊本身組織架構(gòu)的條條框框”)。
我們擁有一個API團隊和一臺API服務器、一個前端團隊和一臺前端服務器、一個平臺團隊和一臺后端服務器、一個廣告團隊和一臺廣告服務器、一大堆由基礎設施團隊管理著的存儲數(shù)據(jù)以及專為分析團隊準備的Hadoop集群。
也就是說,對我們的團隊規(guī)模而言,這是一套非常標準的組織結(jié)構(gòu)。其中前端團隊負責通過PHP/HTML/JS進行統(tǒng)一開發(fā),狀態(tài)及存儲則由后端服務器管理,同時消息隊列則處理長時間運行的項目以及非事務類流程。
最特別的方面當數(shù)后端服務器了,這些Thrift服務器以gevent為基礎。但遺憾的是我們連一臺標準的高性能Python Thrift服務器也沒有,所以花了大量時間與gevent打交道,并想盡辦法讓gevent能安全地服務于客戶端池。另外我們還盡量避免在Python服務器上使用Thrift,這么做主要是為了減少同類服務器的使用量。
同時管理PHP及Python服務器的感覺令人抓狂,我的心中一直回響著“我從來沒想到會遇到這種情況”的聲音。但實踐出真知,我發(fā)現(xiàn)實際操作中并沒出現(xiàn)過太大的問題:在過去的一年時間里,我們團隊中的幾乎每位成員都以輕松愉快的心情同時使用這兩種語言,我也沒聽到過什么抱怨之聲。
作為力求系統(tǒng)產(chǎn)品完美的設計人員,使用Tornado、Apache+modwsgi+Pylons以及Python gevent服務器的現(xiàn)狀令我心生憤懣,不過跟上面幾個問題一樣,實際操作中沒遇到過什么障礙(但這要歸功于Jenkins與Puppet在系統(tǒng)部署方面的幫助,沒有它們倆相信整個流程會變得更加枯燥而痛苦)。
結(jié)束語
總而言之,我認為我們的流程及架構(gòu)非常合理,而且也很適合我們的工作習慣。如果我們的項目今天才剛剛開始,那么采用的方案很可能完全不同;如果我們的團隊沒有經(jīng)歷嚴重人員流失、如果我們沒有因為資金不足而不得不同時管理多套遺留系統(tǒng)與API……無數(shù)個如果會帶來無數(shù)個故事,這些有趣的話題不妨今后慢慢聊。
在為Digg付出了無數(shù)個日夜的辛勤勞作后,我認為圍繞數(shù)據(jù)庫與技術(shù)增值話題同樣值得寫一篇專題(包括Cassandra, MySQL, Redis, Memcache, HDFS, Hive, Hadoop, Tornado, Thrift servers, PHP, Python, Pylons, Gevent等等),但現(xiàn)在我還需要積蓄一些靈感。
又或者談談我們的組織結(jié)構(gòu)給我們的開發(fā)工作帶來了哪些影響?下一次我們再繼續(xù)討論吧。