DGit 介紹

boblu 8年前發布 | 14K 次閱讀 DGit Git 版本控制系統 Github

GitHub的數百臺服務器中存儲著超過3500萬倉庫以及超過3000萬的Gists 代碼片段。去年以來,我們創建了 DGit,DGit是一個分布式存儲系統,DGit顯著地提高了Git存儲的可用性,可靠性。

DGit是“Distributed Git”的簡寫,即分布式Git。眾所周知,Git本身就是分布式的,任何的Git倉庫備份都是包含該項目所有歷史版本的所有的文件,分支,以及提交記錄。DGit利用Git的這個特性為每個倉庫在三個服務器中保存著三份備份。DGit的的設計初衷是為了實現Git存儲沒有單點故障的可用性要求。甚至其中的兩個備份都不可用,倉庫仍能保持可讀狀態;類似 fetches,clones,以及大部分的web操作依然可用。

DGit 的備份機制是在應用層的,而不是硬件層的磁盤。要知道DGit的備份是通過Git協議同步的三份松耦合的完整倉庫,而不是完整的磁盤鏡像。這樣的設計讓我們可以很靈活地決策備份存儲在哪里,以及哪個備份用于讀操作。

假設一個文件服務器需要下線,DGit可以自動地判斷哪些倉庫的備份少于3份,并且自動創建一個新的備份到其他可用的服務器上。這個”自愈“的程序使用集群中剩下所有服務器作為操作源和目的。這個自愈程序的吞吐量是多對多并行的,所以性能上會很快,而且這個過程不會引起服務中斷。

DGit 使用原生的Git技術

大多數的終端用戶都是在 .git 文件夾中存儲Git倉庫的對象,打包文件以及引用。他們利用Git命令行工具或者GitHub Desktop這樣的圖形化客戶端,或者Git的IDE插件去訪問倉庫。也許這會很讓人驚訝,GitHub的倉庫存儲 DGit,也是使用同樣的Git原生的技術。那么為什么不使用 SAN?(Storage Area Network 網絡存儲),為什么不用分布式的文件系統?為什么不用云技術去抽象這個問題?

答案很簡單:因為原生的Git技術足夠快并且很可靠。

Git對于延遲是很敏感的,一個簡單的Git命令,如 git log 或者 git blame,就有可能需要加載上千個Git對象然后遍歷完這些對象。如果其中有任何底層的延遲,系統的性能將急劇下降。因此,利用分布式文件系統存儲 Git倉庫是不可取的(這點GIT@OSC碼云2014年曾經以活生生的反面例子證明過了,詳情歡迎找@yashin 開噴)。Git的最佳性能取決于磁盤的訪問性能,因此,DGit的文件存儲使用的是SSD。

在服務的高層來說,Git 倉庫之間的數據交換也通過協議做了最大的優化(例如push,fetch操作)。所以我們直接使用Git的這些協議做DGit的備份同步。

Git是成熟的久經考驗的技術。所以我們已經有一輛F1賽車了干嘛還要重復造輪子呢?

GitHub的哲學就是我們的服務器使用Git的習慣要盡可能像我們的用戶使用Git一樣。DGit繼續著這個傳統。我們的職員中有幾個Git以及 libgit2 項目的核心貢獻者,如果我們發現了一個性能瓶頸或者別的問題,我們修復了這些問題的同時也會貢獻到這幾個開源項目中讓所有人都可以受益。以我們對Git技術對經驗水平和專業知識看來,使用Git原生技術作為DGit的備份方案是一個明智的選擇。

GitHub 架構, 之前和之后

一直到最近,我們倉庫的備份機制都是使用現成的磁盤級別的備份技術-也就是 RAID 和 DRBD。我們的文件系統都是主重備份的。每一個在線等文件服務器都有一個通過專用網線實時備份的替身。每一個在線的文件都有四個備份:兩個備份在主服務器上,使用的是RAID,另外兩個備份在熱備的服務器上,使用 DRBD。當文件服務器發生任何狀況的時候(類似:硬件故障,軟件崩潰,機器超負載),需要運維人員去確定故障原因并且切換到熱備的服務器。因此,這個方案由于高冗余,數據可靠性級別還是很高的,但是這個故障恢復的程序需要人工干預,不可避免地會出現倉庫訪問失效,即無法保證可用性。為了讓意外盡可能少發生,我們都是使用專業的,高可靠性的服務器存儲倉庫。

現在,我們使用DGit,每一個倉庫分別獨立地存儲在我們的文件服務器集群中的三個服務器上。DGit自動地為每個倉庫選擇宿主服務器,同步備份到各個宿主服務器,并選擇一個最佳到服務器來響應每個讀請求。寫操作時同步地寫入到三個備份中,保證至少兩個備份寫入成果才確認提交這個寫操作。

Windows Kernel-Mode Drivers Written in Rust

GitHub的倉庫現在存儲在一個叫 github-dfs 的集群中,dfs 是 “DGit file server”的簡稱。這些倉庫是利用Git和libgit2存儲在每個服務器的本地磁盤中的。這個集群的客戶端包括web前端以及響應用戶的Git客戶端的代理。

Windows Kernel-Mode Drivers Written in Rust

DGit 的優勢

DGit帶來了很多優勢無論對GitHub用戶而言還是對GitHub內部對基礎設施團隊而言。這也是容納未來更多創新的關鍵性的基礎建設。

  • 文件服務器不再需要部署完全一致的主從熱備,需要物理距離接近可以用網線連接起來。現在我們可以使用一個異構的文件服務器集群,無論配置是不是最好的。

  • 以前的方案當一個服務器故障了,更換它通常是緊急的,因為它的備份服務器是沒有剩余的。兩個熱備服務器同時斷電會導致上千個倉庫下線。現在當服務器故障,DGit將自動地快速地創建一個新的備份到集群中。

  • 故障對路由功能的影響更小了。我們只是在故障的服務器恢復之前停止路由到該服務器,不像之前我們需要重啟并同步整個服務器。現在的方式重啟生產環境的機器也是安全的并且服務不中斷沒有過渡期。因為使用DGit單個服務器的故障對整體服務的破壞力是很小的,我們不再需要等待人工處理故障,DGit可以立即繞過故障機器進行路由。

  • 我們不需要熱備一個服務器,卻讓這個服務器一直是空閑的。在DGit中,所有服務器的CPU和內存都在活躍地處理用戶的請求。寫操作像pushes 必須寫到該倉庫的每個備份,而讀操作可以從該倉庫的任意一個備份讀取。因為讀操作遠遠多于寫操作,而每個倉庫備份于三個服務器上,所以使用DGit每個倉庫可以處理多于以前方式接近3倍的吞吐量。以下圖表展示了Git進程的CPU 負載,藍色曲線代表舊的文件服務,綠色代表DGit服務。藍色曲線僅代表舊文件服務器主從熱備的主服務器,并不包含從服務器。從圖表我們可以看出DGit服務器的負載更低,在波峰大概比舊系統低3倍的負載,在波谷大約低兩倍。從整體沒有看出3倍性能的提升是因為所有的文件服務器必須承擔備份維護的后臺任務。

Windows Kernel-Mode Drivers Written in Rust

  • DGit 會自動地平衡各個服務器上的磁盤和CPU利用率。增加新機器完全不需要提前準備:DGit會隨機地移動倉庫到新的機器上,直到集群的CPU和磁盤空間達到一個平衡。對于已有倉庫的擴展或者收縮,DGit也會移動這些倉庫保持磁盤空間的平衡。對于有寫倉庫變得更活躍或者不再活躍,DGit也會移動這些倉庫從而保持CPU和內存的平衡。以下圖表中,表示三個DGit服務集群,紅色代表磁盤接近用滿的狀態;藍色代表為了緩解磁盤空間壓力新增的服務集群;綠色代表第三個集群,這個集群內一個服務器中的一些倉庫被移動到另外兩個服務器上。倉庫在所有的DGit文件服務器中移動,直到所有服務器的磁盤空間利用率到達一個相當的水平。

Windows Kernel-Mode Drivers Written in Rust

  • DGit降低了倉庫共享一個服務器的成本。在DGit之前,一個集合的倉庫存儲在同一個服務器上。如果其中一個倉庫太大了,或者太活躍了,或者太受歡迎了,那么這個服務器上的其他倉庫也會變的很慢。在DGit中,同一個服務器上的其他倉庫可以直接訪問放在其他的備份,這個其他的備份不太可能和這個很忙的倉庫的其他備份放在同一個服務器。

  • 倉庫備份的去耦合意外著我們可以將備份存儲在不同的區域,甚至不同的數據中心。可用性的到提升,并且我們可以按地理位置就近原則給用戶提供服務。

首發上線

DGit是一個很大的系統更改,我們必須平滑地切換過來。DGit最復雜的部分是備份機制不再像以前那么容易理解:每份倉庫都明確地存儲在三個服務器上,而不是像以前只存在一組主從熱備服務器中。因此,DGit必須要負責自身的串行化處理,加鎖,故障處理,以及再同步,而不是像之前使用 DRBD,RAID來控制備份同步。以上這些豐富的主題就是我們今后的文章需要去解析的。一言以蔽之,我們在使用DGit來存儲用戶的數據之前必須要徹底地測試它。我們的部署過程包括很多步驟:

  • 首先,我們先把DGit開發團隊成員的私人倉庫遷移到DGit中。

  • 其次遷移GitHub的一些私有的,并且不在生產環境運行的倉庫。當然,事前我們都會開個issue征求我們的同事允許。這是一個禮貌的警告,也是一個向GitHub其他員工介紹DGit的方式。

  • 再遷移剩下的GitHub的私有倉庫。

  • 接下來三個月我們不再遷移新的倉庫,而是進行大量的自動化測試,證明DGit滿足生產環境運營要求,以及修復一些偶然的bug。

  • 三個月的穩定運行后,我們遷移GitHub自己的開源項目倉庫到DGit中。接著是用戶fork我們的倉庫。例如, Linguist 是GitHub所有的,但這個倉庫大概被fork了1500次到別的用戶名下。存儲一些開源項目可以測試DGit高網絡負載的能力和吞吐量。

  • 然后我們開始遷移非GitHub所有的開源項目。我們根據GitHub的 sshowcases 以及 trendingrepositories, 優先著眼于被fork了很多的開源項目,如:Ruby,Rails,Bootstrap,D3, 等等。在DGit還只是存儲少量倉庫的時候,我們盡可能壓榨DGit的吞吐量,盡可能嘗試各種運用場景。

  • 六個月之后,我們對DGit的性能比較滿意,足夠支撐GitHub的存儲了,最后我們才開始逐步把大部分倉庫遷移到DGit。

Windows Kernel-Mode Drivers Written in Rust

在首發上線期間,我們慣例地關掉一些服務器,有時候一次關閉多個,用戶的操作沒有被中斷。

截止于發布這篇文章的時候,已經有58%的倉庫和96% 的Gists代碼片段存儲在DGit中,這表示GitHub上67% 的Git操作都是基于DGit之上的。接下來我們會盡快把DGit前時代的主從熱服務器變成DGit服務器。

github總是力求獲取、推送、查看項目倉庫能夠更快和更可靠。DGit是在倉庫存儲層多年來滿足這些目標同時允許進行水平擴展和提供容錯能力。

在下個月我們將會跟進深入理解DGit技術內幕的帖子。

本文地址:http://www.oschina.net/translate/introducing-dgit

原文地址:http://githubengineering.com/introducing-dgit/

 本文由用戶 boblu 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!