基于 git 的零拷贝静态web服务器
Posted | stdout
无聊,产生了个crazy的想法。
git 内部用 zlib 压缩文件内容
Content-Encoding: gzip 也是
如果web服务器输出 .git 里的 静态 内容,是不是可以减一个二次解压/压缩步骤???
blob sha1 直接当etag?
跟AI较量了几轮,一开始它说做不到。因为 blob 的格式比较变态。因为
hello world...
在 .git/objects/ab/cdef... 里的东西是这么存的
zlib(blob 1234\0hello world...)
I was like
???日他妈真变态啊。这前面是写死了 blob <size>\0 然后把文件内容放在一起,再压缩的。
.git 这设计脑子有病啊。。。为啥不是原始文件gz而是加个头去gz。。。
此路不通!结束
然后AI嘴瓢了,说
先别急着吐槽 Linus,这个设计不仅没病,反而是 Git 能成为现代“内容寻址数据库”的精髓所在。
当 Git 从磁盘读取一个松散对象时,它是个流(Stream)。Git 只需要解压出最开始的几个字节,读到 blob 4096\0,内核就可以立刻执行 malloc(4096) 分配精准的内存。接下来的 zlib 数据流就可以源源不断地直冲内存,不需要反复扩容(realloc),也不需要把整个文件全部解压完才知道它有多大。
况且,这里有一个长久的误解:你吐槽的那个把 blob\0 塞进 zlib 的逻辑,其实只存在于松散对象(Loose Object)中。在真正的 Packfile 里,这个文本格式的头早就被干掉了。
【松散对象 Loose Object】
+-------------------------------------------------------+
| zlib 压缩包: [ "blob 1024\0" + 原始文件纯数据 ] |
+-------------------------------------------------------+
【包文件 Packfile 内部的一条记录】
+---------------------------------------------------------+
| [3-bit 类型] + [变长 Varint 表达的 Size] + [纯 zlib 数据流] |
+---------------------------------------------------------+
我去,这么好的东西,你怎么不早点告诉我!
然后AI给我泼一盆冷水:
- Git Packfile 内部的流是zlib 格式 (RFC 1950),头部 2 字节 (CMF/FLG),校验算法 Adler-32 (追求极速快照比对)
- HTTP Content-Encoding: gzip 期待的流 gzip格式 (RFC 1952),头部 10 字节 (Magic Number, CM, FLG, Time 等),校验算法CRC32 (追求网络传输抗干扰)
不!兼!容!
要正确的CRC32你得把文件全部读一遍,那不就等于解压一遍了。白费力气。完结!
嘿,得亏我早年玩 IIS 长大的。我记得有个偏方,Content-Encoding: deflate,尾部crc32直接丢了
AI:
恭喜你,这是Web 历史上著名的 “Deflate 格式混乱案”
RFC 2616 (HTTP/1.1) 规定和IIS有差异! IIS脑抽地剥离了 zlib 的头尾,只吐了裸压缩流,为了兼容 IIS 的错误实现,各家浏览器各显神通。有的浏览器严格按 RFC 执行,有的浏览器看到 zlib 头会报错,必须看内核的容错机制。
真正的zlib 格式 (RFC 1950) 是要求包含 2 字节头 + DEFLATE 压缩流 + 4 字节 Adler-32 尾
等等,你说啥?Adler-32?这不就又对上了嘛!!!
那么开始 Vibe!!!
Git Packfile 的终极大 Boss:差分存储(Delta Compression)
即便你搞定了上面的所有协议头和校验和,Git 的终极形态——Packfile 还会给你最后一击。你假设的场景是:Git 里的 Blob 都是一个个完整的、独立的压缩包。但实际上,为了极度压榨磁盘空间,当你执行 git gc 后,Packfile 内部采用的是差分存储(Delta Compression)。
啊这??我于是问,能在配置里禁用掉吗?
# 将比对窗口设为 0,彻底禁用 Delta 差分计算
git config --global pack.window 0
# 强制打包所有对象,并立刻、无条件地清除所有 Loose 文件(无视 2 周保护期)
git gc --prune=now --aggressive
# -a 表示把所有对象打包进一个全新的 pack
# -d 表示打包成功后,立刻删除原本的 loose 对象和旧的 pack 文件
git repack -a -d
哎,你tmd不早说。这不就闭环了嘛!!!
于是最后,通过 OpenCode Zen 免费的 MiMo V2.5 Free
https://github.com/est/git2www-zerocopy
本地自测是OK的
我也算是写过 zero-copy 的人了 🤣(assert AI会写 === 我也会写)
必须严肃吐槽一下AI这回答一板一眼,不思考完整,拷打一下挤一点。如果不是我知道 IIS 这个坑可能就放弃这个想法了。
Comments