git repack多包使用及相关性能测试
1、git數據結構
git 中存在四種數據結構,即object包含四種,分別是tree對象、blob對象、commit對象、tag對象
1.1 blob對象
存儲文件內容,內容是二進制的形式,通過SHA-1算法對文件內容和頭信息進行計算得到key(文件名)。
如果一個commitId為73c17abe44977ee82cd949f489996c2715335119,則這個blob文件在.git/objects/73文件夾下,名為c17abe44977ee82cd949f489996c2715335119,也就是說hash值的前兩位為objects目錄下子目錄的名字,剩余38位為文件名。
1.2 tree對象
可以看作一個目錄,管理一些“tree”對象或是“blob”對象。它有一串指向“blob”對象或是其它“tree”對象的指針,一般用來表示內容之間的目錄層次關系(就像文件和子目錄)
1.3 commit對象:
commit對象指向一個“tree對象”,并且帶有相關的描述信息,標記項目某一個特定時間點的狀態。它包括一些關于時間點的元數據,如時間戳、最近一次提交的作者、指向上次提交的指針等
commit、tree、blob關系可以總結如下:
一個commit對應一個tree對應多個blob
1.4 tag對象:
一個tag對象包括一個對象名(SHA1簽名)、對象類型、標簽名、標簽創建人的名字(“tagger”), 還有一條可能包含有簽名(signature)的消息。
通過
總結
git每次提交存儲的都是整個文件,而不是采用增量,所以會導致存儲數據量很大,git針對此采用了zlib對數據進行壓縮,可以采用cat-file命令來查看
一旦將內容存儲在了對象數據庫中,那么可以通過 cat-file 命令從 Git 那里取回數據。 為 cat-file 指定 -p 選項可指示該命令自動判斷內容的類型,并為我們顯示大致的內容:
2、git pack
git向倉庫中推送文件時存儲使用的是“松散文件”,如果有一個1.txt現在是10k,下次推送增加了0.1k,也就是說現在是10.1k,name第二個版本就會重新產生一個1.1k的文件,這樣會產生磁盤浪費,所以git會將這些文件打包成一個二進制類型的包文件(packfile),并生成對應的.idx索引文件,以節省空間和提升效率。這些被打包的文件存儲在.git/objects/pack目錄下,執行find .git/objects/ -type f命令如下
看到.git/objects目錄下的文件詳情,包含了8個松散文件、一個pack文件、一個idx文件,如果想查看更詳細的內容可以執行
git count-objects -v命令
git count-objects -v命令結果的各個含義如下:
- count: 松散對象數
- size:松散對象占用的磁盤空間,單位為KB
- in-pack:在pack文件中的objects數量
- size-pack:pack文件占用的空間,單位為KB
- prune-packable:同時在松散對象和packs文件中都包含的objects數量,這種objects可以執行git prune-packed命令修剪
- garbage:對象數據庫中既不是有效松散對象也不是有效包的文件數
- size-garbage:垃圾文件占用的磁盤空間,單位為KB
3、git repack
3.1 repack作用
用于將當前不駐留在“pack”中的所有對象合并到包中。它還可用于將現有包重新組織為一個更高效的包。pack文件是單獨壓縮的對象的集合,應用了增量壓縮,存儲在單個文件中,并具有關聯的索引文件。而且pack文件用于減少鏡像系統、備份引擎、磁盤存儲等上的負載。
3.2 單包與多包
3.2.1 單包
在重新打包時repack會有一些options可供選擇,如-d, -A,如果加上了-A,則重新打包時就會將新的松散文件與之前的pack共同打包成一個pack。
在單包時通常會將加上--write-bitmap-index來生成.bitmap文件(bitmap文件存儲有關包文件或多包索引(MIDX)中對象集的可達性信息),此option會覆蓋repack.writeBitmaps值,當然如果不指定此option,也可通過命令git config --global repack.writeBitmaps true,然后通過git config -l查看是否成功設置此option。需要注意的是--write-bitmap-index option只在單包時才會生效,也就是說只在與-a、-A或-m一起使用時有意義,因為位圖必須能夠引用所有可訪問的對象(多包如何設置bitmap后面會涉及)。
3.2.2 多包
隨著文件數越來越多,pack文件就會越來越大,單包策略的缺點就暴露了出來,如果使用單包,包大小高達30g甚至更大,當有新的松散文件時、或gc時,觸發的repack將會非常慢。
針對上述問題,可以采用多包的方式,為每個packfile設置一個限制(pack.packSizeLimit),超過這個限制就分包,同時每次repack重新打包時將新的松散對象采用增量(git repack -d)打包,然后在于之前的小于某個限制(git multi-pack-index repack --batch-size=<size>)的所有pack重新打包,看下如下命令:
# 設置每個packfile的大小為3g,-d表示采用增量的方式將新松散文件打包,使用--write-midx 開啟多包索引 git -c pack.threads=4 -c pack.packSizeLimit=3g -c repack.packKeptObjects=true -c core.multiPackIndex=true repack -l -d -n --write-midx # git multi-pack-index repack --batch-size=<size>,將小于size的packfile重新打包成一個或多個packfile,如果兩個packfile都小于size打小,但是重新repack后生成的新packfile大于pack.packSizeLimit,那么將不予合并打包 git -c pack.threads=4 -c repack.packKeptObjects=true -c pack.packSizeLimit=3g -c core.multiPackIndex=true multi-pack-index repack --batch-size=2g # 重新生成bitmap git multi-pack-index write --bitmap3.3 repack單包與多包性能對比
當測試repack相關功能時,為了驗證單包和多包性能問題,需要保持每次松散對象數量是一致的,因此當執行完單包命令之前需要將objects文件夾備份,并在執行完單包命令之后將備份的objects重新復制回去并執行unpack命令,流程如下:
3.3.1 前置條件:
已有40w個松散對象被打包成一個pack(約7.5g),以及10w個松散對象(約2g)。本次通過直接執行命令觀看效果,因此使用了root權限。
- 1、將.git/objects整個目錄備份,并將10w個文件產生的對應的pack(記為pack-d69d44271fc40005eed5c8e0d7ec82c15e80dddd.pack)文件備份
- 2、執行cat pack-d69d44271fc40005eed5c8e0d7ec82c15e80dddd.pack | git unpack-objects,將pack-d69d44271fc40005eed5c8e0d7ec82c15e80dddd.pack重新unpack成loose objects,需要注意的是執行unpack-objects命令的pack需要從.git/objects目錄下移走
- 3、驗證單包/多包命令
- 4、回到步驟2循環執行
3.3.2 測試命令
測試時可參考下述命令
單包
- gc:
- repack
多包
- gc
- repack
3.3.3 測試結果及分析
1、耗時分析
- 單包repack
- 多包repack
重寫bitmap耗時約1m 18s
可以看到多包repack總耗時約在4m 42s
2、cpu分析
左邊是單包,右邊是多包
可以看到單包時cpu使用超50%耗時約420s,而多包則在140s
3、IO讀寫
總結
整理IO讀寫并進行估算后,結果如下(舊邏輯即為單包,新邏輯即為多包)
繪圖如下
可以看到使用多包處理后資源占用明顯降低,耗時減少。
相關文檔
1、Git-內部原理-Git-對象
2、git-gc
3、git-config
4、git-pack-objects
5、git-multi-pack-index
6、git-repack
7、git-count-objects
8、bitmap
9、Git數據存儲的原理淺析
總結
以上是生活随笔為你收集整理的git repack多包使用及相关性能测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Docker--网络详解
- 下一篇: 2022哈工大软件构造我的学习笔记(1)