故事開端:可重復的一致性部署(2007年至2010年)
在Reddit剛剛起步的時候,只有幾名工程師,整個網站是一個使用Python開發的大單體,部署在幾臺固定的服務器上。大部分部署工作通過一個叫作push的Perl腳本進行。
他們使用了負載均衡器,對請求進行分類,把流量分配給不同類型的服務器群。分流帶來的好處顯而易見,一方面可以輕松應對流量高峰,一方面避免不同服務器群之間的互相影響。
在部署應用時,push工具遍歷服務器清單,通過SSH登錄服務器,運行一些列命令更新服務器的代碼,然后重啟服務器。整個部署過程是串行化的,也就是逐臺服務器部署。這樣做有個好處,如果在部署了幾臺服務器后發生異常,可以立即停止后續的部署,并回滾已經部署的服務器,避免將問題擴散到整個生產環境。
團隊增長(2011年)
隨著團隊成員越來越多,在進行部署時需要做更多的協調工作。他們修改了push工具,通過IRC聊天機器人來觸發部署事件。大體的部署流程沒有太大變化,只是引入了機器人,使用機器人可以幫團隊成員節省一些時間和精力。
隨著網站流量的增長,他們加入了更多的服務器。這個時候他們仍然需要通過人工來更新push的主機清單。他們使用uWSGI來管理工作進程,在重啟應用程序時,uWSGI會殺掉運行中的進程并啟動新的進程。因為啟動新進程需要一小段時間,所以如果重啟的是整個服務器群,在這段時間內服務器群就無法提供服務。隨著服務器數量越來越多,部署的時間也相應變長。
重構部署工具(2012年)
后來他們使用Python重寫push工具,不再使用硬編碼的方式提供主機清單,而是從DNS服務器上獲取主機清單,所以如果有新的服務器加入,就不需要再去修改工具本身了。
他們還把主機清單的順序打亂,來自不同服務器群的主機都有機會得到優先的部署,而不是像之前那樣需要一個服務器群接著一個服務器群地部署。不過打亂主機順序也會帶來一個問題,就是在出現問題時很難回退。所以他們使用種子(seed)的方式來打亂主機清單順序,在回退代碼時可以使用之前的順序。
另外,在部署代碼時,他們使用了Git的修訂版(revision)代替了原先的master分支,避免在部署過程中有人意外提交代碼到master上,這樣可以辦證部署的總是相同版本的代碼。
自動伸縮(2013年)
他們開始使用云服務,云服務的自動伸縮功能可以在流量不是很大的時候節約成本,而在流量增長時又可以自動伸縮。在向云端遷移的過程中,push工具從DNS獲取主機清單的能力讓整個遷移過程變得相當順暢。不管主機清單如何發生變動,對于工具來說都沒有任何影響。他們還使用Cunicorn代替了uWSGI。
服務器增長(2014年)
隨著流量和服務器數量的增長,部署時間也越來越長,最糟糕的情況下,一個正常的部署需要將近一個小時的時間。于是,他們再次重寫了部署工具,并將其改名為rollingpin。新工具可以進行并行部署,加快了部署速度,把部署時間再次降回到5分鐘。新工具也比舊工具更加智能,在挑選服務器時可以交錯地從不同服務器群中選擇服務器進行部署,避免一次性重啟整個服務器群導致服務不可用。
員工增長(2015年)
工程師團隊的規模也在不斷增長,需要部署的東西也越來越多。遵循一次只進行一次部署的規則變得越來越困難,工程師們在協調發布順序方面也耗費了不少時間和精力。于是,他們給聊天機器人使用了協調部署隊列。工程師向機器人申請部署鎖,要么獲得部署鎖,要么被放入隊列。這樣就可以保證部署次序,工程師在等待部署鎖的過程中可以做一些其他的事情。
他們還修改了部署工具,讓它向Graphite發送度量指標,這樣就可以很容易地跟蹤部署變更。
兩種服務(2015年)
后來,移動版的網站上線,它采用了完全不同的技術棧,有自己的服務器和構建流程。部署工具的解耦API在這個時候才真正派上用場。因為每個項目可以在不同的位置進行構建,他們就可以通過同一個系統來管理所有的服務。
25種服務(2016年)
此時,Reddit的服務種類從兩個發展到幾十個,團隊數量也從兩個變成15個。他們通過后端服務框架Baseplate來構建新服務,或者使用nodejs構建移動Web應用。rollingpin不再關心部署的是哪一種應用,他們的部署基礎設施已經具備了足夠的通用性。
安全網(2017年)
高度的并行部署會導致多臺服務器同時重啟,降低了處理請求的能力,還會讓其他服務器過載。Gunicorn的主進程使用了與uWSGI類似的模型,會一次性重啟所有的工作進程,在新工作進程啟動過程中無法處理任何請求。于是他們使用Stripe的Einhorn代替了Gunicorn。Einhorn在重啟工作進程時會先創建新的工作進程,等新進程準備就緒之后才會把舊進程停掉。
不過新的模型也存在一個問題,因為重啟一個工作進程需要30秒鐘的時間,如果新代碼里包含了bug,在30秒之內是無法發現它們的,可是在這段時間內可能已經部署了好幾臺服務器了。為了解決這個問題,他們引入了一種機制,他們輪詢Einhorn的狀態,等待新工作進程準備就緒,在這之前不允許部署下一臺服務器。為了加快速度,他們加大了并行數,因為現在進行并行部署是安全的。
為此,部署時間下降了很多,部署800臺服務器只需要7分鐘。
未來
Reddit的基礎設施在支持團隊增長的同時,還要不斷地進行構建。Reddit的增長速度處于歷史制高點,他們現今面臨的問題主要來自兩個方面:提高工程師自制能力,同時保證生產環境基礎設施的安全,并為工程師提供一個安全網,讓他們能夠放心地進行快速的部署。