我教一个存储桶说 Git
如果我只是将 git 服务器指向一个对象存储桶会发生什么?在我将代理沙箱移植到 Go 的时候,我建立了一切都是基于 billy,这是一个 Go 的文件系统抽象。这个项目的整个诀窍是教一个 Tigris 存储桶足够像一个文件系统,这样一个 shell 解释器及其工具就无法分辨出区别。billy 是让整个 facade 变得完整的关键层。在我让事情正常工作之后,我意识到我在使用 billy 时远远超出了它的正常用例。它最初是为了 go-git 而制作的,这是一个纯 Go 实现的 git 协议和数据格式。它根本不依赖于 /usr/bin/git 二进制文件的存在。billy 的文件系统接口上的每个方法都是因为 go-git 需要它而存在的。这让我有了一个可怕的想法:我已经有了一个可以像文件系统一样发出嘎嘎声的存储桶,而 go-git 的本地语言是“文件系统”。它可以像这样工作吗?让我们来看看。Git 一直是一个对象存储器 如果你剥去表层,git 仓库有四个基本的东西:对象,或压缩的数据块。任何单个仓库中的大多数对象都是文件。树,或映射到其他对象的对象。简而言之:树就是文件夹。提交,或指向一个树和其父提交的对象。这让你能够确定哪些文件属于一个逻辑变更集。引用、分支和标签,它们是指向对象堆的小型可变指针。注意 在我开始处理这个问题之前,我一直认为 git 仅仅存储对空文件夹所做的补丁,以此重建你的仓库历史。事实并非如此。它实际上跟踪整个文件,这也解释了为什么大型二进制块让工具的表现如此糟糕。差异的心理模型在日常使用 git 时工作得很好;但在存储层面,它是错误的,而这篇文章正是关于这个层面的。例如,假设我刚刚创建了一个新的 git 仓库并提交了一个 README.md 文件。 .git 文件夹的树看起来像这样: $ tree .git .git ├── COMMIT_EDITMSG ├── config ├── HEAD ├── index ├── objects │ ├── 5e │ │ └── b8151eb669aa4467b6dea2c4bce19183cd0b41 │ ├── 6a │ │ └── 6a8ecfcae2632152486aca3d9150ef83dedd66 │ ├── f4 │ │ └── d2487a1c6d742c8037c0296ddf80625190bd80 │ ├── info │ └── pack └── refs ├── heads │ └── main └── tags 正如你所看到的,有三个对象。其中一个是提交 5eb8151eb669aa4467b6dea2c4bce19183cd0b41,另一个是树,最后一个是 README 文件。主分支也指向该提交: $ cat .git/refs/heads/main 5eb8151eb669aa4467b6dea2c4bce19183cd0b41 有趣的是,其中一半是内容寻址的。一旦被提交,内容寻址的部分就不会改变。Git 对象非常适合 Tigris 的内部模型,因为它们是仅附加的存储,就像 Tigris 构建的基本模型一样。经常变化的部分是引用,它们会更新以指向最新的提交。不过,这些都是小型文件,这意味着 Tigris 可以毫不费力地处理它们。然而,当我们在服务器上托管 git 仓库时,我们最终创建了单点故障。我们的 git 仓库托管在可以且会发生故障的单台机器上。整个实现依赖于 git 对象与文件系统对象的 1:1 关联,因为每一个人(甚至 GitHub)都需要调用 git 二进制文件来实际存储文件。托管 git 仓库成为我们无状态云原生环境中最有状态的服务之一。确实,git 理论上是去中心化的,但我们大多数人最终还是将我们的 git 仓库放在一个大存储中,这个存储的正常运行时间存疑:GitHub。为了公平起见,GitHub 的运营规模是我们都无法真正想象的。自成立以来,他们一直在推动极限,甚至需要获得 Engine Yard 的支持,以便维护更大的服务器以应对负载。他们必须用一个大型的挂载文件系统来处理一切,因为 git 的工具没有其他选择。人类无法理解的恐怖灾难 现在假设这种怪异的现象让你感到足够烦恼,希望采取一些行动。要构建一个 git 服务器而不在本地文件系统中存储所有内容,你必须以某种方式讲 git 的语言,而常规选项实际上都不是很理想:如果你调用 git 二进制文件,那么你的“库”就是 git 进程的 argv,而你的错误处理就是屏幕抓取输出。在内部,git 用许多子命令实现其功能,而不是将其全部暴露为库。这段代码由 load-bearing 对 die() 的调用连接在一起,这意味着如果出现问题,就杀死进程。如果你与 libgit 连接到 git 的核心,你会继承“当事情变坏时,死亡”的行为,导致你的应用程序突然开始随机崩溃。这对正常运行时间很不利。如果你尝试使用 libgit2(那个实际上是一个库的重写),你必须考虑到它被 GPL(带有链接例外)所困扰,试着解释那它就会变得很复杂...
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡