- Nhiều trình quản lý gói đã dùng Git như một cơ sở dữ liệu nhờ sự tiện lợi trong quản lý phiên bản và cộng tác, nhưng khi quy mô tăng lên thì vấp phải các vấn đề về hiệu năng và bảo trì
- Cargo, Homebrew, CocoaPods và các công cụ khác cuối cùng đã chuyển sang chỉ mục dựa trên HTTP hoặc CDN do kích thước chỉ mục Git ngày càng phình to, tốc độ cập nhật chậm và sự kém hiệu quả trong môi trường CI
- vcpkg vẫn hoạt động dựa trên hash cây Git, và trong môi trường clone nông (shallow clone) thì xảy ra lỗi build cùng các cách lách phức tạp
- Hệ thống module của Go đã đưa vào GOPROXY và cơ sở dữ liệu checksum (sumdb) để loại bỏ phụ thuộc vào Git và cải thiện bảo mật cũng như tốc độ
- Git rất xuất sắc cho cộng tác mã nguồn, nhưng liên tục cho thấy rằng nó không phù hợp cho việc truy vấn metadata gói hoặc quản lý registry quy mô lớn
Sự thất bại lặp đi lặp lại của các nỗ lực dùng Git như cơ sở dữ liệu
- Git hấp dẫn nhờ các ưu điểm như lịch sử phiên bản, cấu trúc phân tán, hosting miễn phí, nhưng khi dùng như cơ sở dữ liệu thì sẽ chạm tới giới hạn mở rộng
- Nhiều trình quản lý gói đã chọn Git làm chỉ mục, nhưng theo thời gian suy giảm hiệu năng và gánh nặng hạ tầng ngày càng nghiêm trọng
Cargo
- Chỉ mục crates.io khởi đầu là một kho Git, và mọi client đều thực hiện clone toàn bộ
- Khi kho ngày càng lớn, ở giai đoạn delta resolution xuất hiện nút thắt hiệu năng của libgit2
- Trong môi trường CI, mỗi lần build lại tải xuống toàn bộ chỉ mục nên cực kỳ lãng phí
- Thông qua RFC 2789, giao thức sparse HTTP được đưa vào để chỉ lấy metadata cần thiết qua HTTPS
- Tính đến tháng 4 năm 2025, 99% request sử dụng chế độ sparse
- Chỉ mục Git vẫn còn tồn tại nhưng đa số người dùng không còn truy cập tới nó
Homebrew
- GitHub đã yêu cầu Homebrew ngừng dùng shallow clone, và việc cập nhật bị chỉ ra là “một phép toán rất tốn kém”
- Thư mục
.git của homebrew-core gần chạm mốc 1GB, và khi cập nhật thì bị chậm do delta resolution
- Vào tháng 2 năm 2023, trong Homebrew 4.0.0, việc cập nhật tap đã chuyển sang cách tải xuống JSON
- Việc loại bỏ Git fetch giúp tăng tốc cập nhật, và chu kỳ tự động cập nhật cũng đổi từ 5 phút sang 24 giờ
CocoaPods
- Trình quản lý gói cho iOS/macOS CocoaPods có kho Specs gồm hàng trăm nghìn podspec đã trở nên quá lớn
- Việc clone và cập nhật mất nhiều phút, và phần lớn thời gian CI bị tiêu tốn cho các thao tác Git
- GitHub áp dụng CPU rate limit, và shallow clone bị xác định là nguyên nhân gây tải cho máy chủ
- Nhóm đã áp dụng các biện pháp tạm thời như dừng fetch tự động, chuyển sang clone đầy đủ, sharding kho
- Từ phiên bản 1.8, công cụ này chuyển sang phân phối HTTP dựa trên CDN, giúp người dùng tiết kiệm khoảng 1GB dung lượng đĩa và tăng tốc cài đặt đáng kể
Nixpkgs
- Ở phía client, Nix vốn đã dùng channel dựa trên tarball để tránh clone Git
- Biểu thức gói được cung cấp qua HTTP từ S3 và CDN
- Tuy vậy, hạ tầng của GitHub vẫn chịu áp lực từ kho 83GB và 20.000 fork
- Tháng 11 năm 2025, GitHub báo cáo lỗi thất bại đồng thuận giữa các bản sao và lỗi trong công việc bảo trì
- Clone cục bộ chỉ 2.5GB, nhưng toàn bộ mạng fork gây áp lực lên dung lượng lưu trữ của GitHub
vcpkg
- vcpkg, trình quản lý gói C++ của Microsoft, quản lý phiên bản bằng hash cây Git
- Để tái hiện các port tại một thời điểm commit cụ thể thông qua
builtin-baseline, cần toàn bộ lịch sử
- Trong môi trường shallow clone (GitHub Actions, DevContainers), sẽ xảy ra lỗi build
- Cách khắc phục là cần đặt
fetch-depth: 0, tức phải tải xuống toàn bộ lịch sử
- Do cấu trúc hash cây Git nên không thể truy vết commit, và đây là giới hạn mang tính cấu trúc không thể sửa được
- Công cụ này vẫn chỉ hỗ trợ registry dựa trên kho Git, không có phương án thay thế bằng HTTP hay CDN
Hệ thống module của Go
- Đội ngũ kỹ thuật của Grab cho biết sau khi đưa vào module proxy, thời gian
go get đã giảm từ 18 phút xuống 12 giây
- Cách làm cũ yêu cầu phải clone toàn bộ kho của từng dependency mới có thể đọc được
go.mod
- Nhóm Go lo ngại về sự phụ thuộc vào công cụ VCS và các lỗ hổng bảo mật
- Từ Go 1.13, GOPROXY trở thành mặc định, cung cấp mã nguồn module và
go.mod qua HTTP
- sumdb (cơ sở dữ liệu checksum) đảm bảo tính toàn vẹn và tính bền vững của module
Các vấn đề phổ biến khi dùng Git như cơ sở dữ liệu
- Wiki dựa trên Git (Gollum) trở nên chậm trong việc duyệt thư mục và tải trang khi kho quá lớn
- GitLab có kế hoạch ngừng dùng Gollum
- CMS dựa trên Git (Decap) vướng giới hạn request GitHub API (5.000 lần)
- Hiệu năng suy giảm từ khoảng 10.000 mục trở lên, và người dùng mới với cache trống có thể gây bùng nổ request
- Công cụ GitOps (ArgoCD) gặp vấn đề vượt quá dung lượng đĩa khi clone kho
- Một commit đơn lẻ có thể làm mất hiệu lực toàn bộ cache, còn monorepo lớn cần cơ chế mở rộng riêng
Những lý do mang tính cấu trúc khiến Git không phù hợp làm cơ sở dữ liệu
- Giới hạn thư mục: số lượng file càng nhiều thì càng chậm
- CocoaPods từng tạo ra đối tượng cây khổng lồ do có 16.000 thư mục, và đã giải quyết bằng sharding theo hash
- Vấn đề phân biệt chữ hoa chữ thường: Git có phân biệt, nhưng macOS và Windows thì không
- Azure DevOps đã thêm chức năng chặn ở phía máy chủ để ngăn xung đột
- Giới hạn độ dài đường dẫn: giới hạn 260 ký tự của Windows gây lỗi
git status
- Thiếu các chức năng của cơ sở dữ liệu:
- Không có CHECK/UNIQUE constraint, khóa, chỉ mục hay chức năng migration
- Mỗi trình quản lý gói đều phải tự xây dựng hệ thống kiểm tra và lập chỉ mục riêng
Kết luận
- Git rất xuất sắc cho cộng tác mã nguồn, nhưng không phù hợp cho truy vấn metadata gói hay quản lý registry quy mô lớn
- Phần lớn các trình quản lý gói cuối cùng đều chuyển sang chỉ mục dựa trên HTTP hoặc cơ sở dữ liệu
- Các ưu điểm của Git như lịch sử phiên bản, quy trình PR rất hấp dẫn, nhưng nó thất bại khi được dùng để thay thế cơ sở dữ liệu
- Khi thiết kế một trình quản lý gói mới, dù chỉ mục Git có vẻ hấp dẫn đến đâu thì vẫn sẽ chạm tới cùng những giới hạn như các trường hợp Cargo, Homebrew, CocoaPods, vcpkg và Go
2 bình luận
Họ dùng git vì nó tiện hơn là phải xây riêng một hệ thống để nhận đóng góp từ cộng đồng. Bảo đó là giới hạn thì tôi không thấy đồng tình lắm, mà cũng chẳng thấy phương án thay thế nào cho những vấn đề thực tế cả.
Ý kiến trên Hacker News
Việc này trông giống một dạng bi kịch của tài sản chung. GitHub thì miễn phí và có nhiều tính năng tuyệt vời nên ai cũng muốn dùng. Nhưng kiểu quyết định này luôn xảy ra khi có ngoại tác
Ngoại tác mà tôi coi là quan trọng nhất là thời gian của người dùng. Phần lớn các công ty phần mềm chỉ quan tâm chi phí thời gian kỹ sư, còn thời gian của người dùng thì bị bỏ qua. Họ tập trung phát triển tính năng nhưng không tối ưu thời gian tương tác của người dùng. Ví dụ, nếu tôi bỏ 1 giờ để làm ứng dụng nhanh hơn 1 giây, thì một triệu người dùng sẽ tiết kiệm được 277 giờ mỗi năm. Nhưng vì thời gian người dùng là ngoại tác nên kiểu tối ưu này hiếm khi được thực hiện
Cuối cùng người dùng phải tải thêm dữ liệu vô ích và chờ đợi lâu hơn, còn lập trình viên thì không phải chịu trách nhiệm cho sự lãng phí đó
Tôi đang làm Cargo/UV cho C. Bài viết rất hay và tôi đồng cảm sâu sắc.
Lúc mới bắt đầu thì vận hành registry thật sự rất khó. Không chỉ phải viết mã, đảm bảo chất lượng công cụ, mở rộng cộng đồng, mà còn phải tính đến hạ tầng có thể chịu được lưu lượng toàn cầu. Trong tình huống đó, giải pháp dựa trên git rất hấp dẫn
Nhưng vấn đề là sparse checkout. Tôi muốn quản lý phiên bản manifest gói bằng git, nhưng lại phải theo dõi các commit tùy ý nên rất kém hiệu quả. Cuối cùng thành ra phải push hai commit, nên thực tế là không khả thi
Tôi nghĩ cách tiếp cận của Conan là thực dụng nhất. Thay vì khả năng tái lập hoàn hảo, họ đưa logic có điều kiện vào manifest. Cũng có thể ánh xạ manifest theo từng khoảng phiên bản. Không hoàn hảo, nhưng là một thỏa hiệp thực dụng và hữu ích.
Tất nhiên giải pháp thật sự là dùng cơ sở dữ liệu, nhưng cũng chẳng có ai trả hộ chi phí máy chủ và bảo trì nên ngoài thực tế rất khó
Nếu vấn đề là tiền bạc và tính độc lập thì cũng có thể dùng P2P. Tuy nhiên nếu không có cache CI thì lưu lượng có thể tăng vọt
Cấu trúc mirror của các bản phân phối Linux như Debian, Fedora, openSUSE cũng đáng tham khảo
Bài này đang trộn lẫn hai vấn đề. Một là dùng git làm cơ sở dữ liệu chỉ mục gói, hai là lấy mã của từng gói bằng git. Hai chuyện đó tách biệt.
Chỉ mục có thể ở git còn gói thì ở zip/tar, hoặc ngược lại. Trường hợp của Go thì thậm chí còn không có chỉ mục
Chuyện backend của GitHub hay 20.000 fork đều không liên quan đến bản chất. Ngay cả không có working tree của git thì vẫn có thể tra cứu key-value hiệu quả.
Lập luận “rewrite lịch sử git giống như migration DB” cũng kỳ lạ. Chẳng phải chạy một Postgres còn tốt hơn sao?
Cách tiếp cận kiểu “lúc còn chạy được thì dùng cách dễ, khi nào không ổn thì sửa” là thực tế.
Julia cũng làm như vậy, và số package của họ mới khoảng 1/7 của Rust nên chưa có vấn đề gì.
Có thể cải thiện bằng cách chỉ tải file Registry.toml cấp cao nhất rồi mới tải package cần thiết. Không phải vấn đề lớn
Văn hóa “Move fast and break things” đã tạo ra đống phần mềm chậm chạp và đầy lỗi như hiện nay
Tôi đồng ý với kết luận rằng “Git là một cơ sở dữ liệu tuyệt vời để khởi đầu package manager”
Tôi đứng về phía “cuối cùng vẫn ổn mà”. Nó đã giúp rất nhiều cho giai đoạn vận hành ban đầu, và vấn đề scale có thể xử lý sau
Ở đây có survivorship bias. Cargo thành công nên chỉ mục git của nó mới phình ra và gây vấn đề.
Phần lớn dự án nhỏ vẫn đang dùng git rất ổn như một giao thức phân phối dữ liệu.
Ở giai đoạn đầu khi chưa rõ có scale hay không, tận dụng git và GitHub để tập trung vào vấn đề cốt lõi là hợp lý
Mỗi khi thấy một bài trên trang đầu HN kiểu “thứ bạn đang làm hiện giờ là sai”, tôi lại thấy khiêm tốn hơn.
Tôi cũng từng vài lần rơi vào tình huống đó. Lần này là bài về PG Notify.
Nhưng hiện giờ tôi đang phát triển một mình, còn chẳng biết dự án có thành công hay không, nên phân phối plugin bằng git là phương án thực tế nhất.
Dù vậy nếu sau này gặp vấn đề scale thì tôi sẽ tham khảo bài này
Cá nhân tôi host code bằng Forgejo. Nó được bảo vệ bằng mTLS mà không phơi ra ngoài.
Nhưng Go module lại yêu cầu chứng chỉ nên không nhận diện được instance Forgejo của tôi.
Dù dùng SSH thì nó vẫn đòi truy cập HTTPS, nên cuối cùng tôi phải dùng replace directive với bản sao cục bộ. Khá phiền
.gitvào cuối đường dẫn module và đặt$GOPRIVATEthì có thể dùng xác thực lệnh git mà không cần yêu cầu HTTPS. Xem tài liệu chính thứcKhông chỉ package manager, rất nhiều dự án nhỏ cũng crowdsource dữ liệu vào repository git.
Phần lớn quy mô nhỏ nên chưa chạm phải giới hạn kỹ thuật.
Tuy vậy cấu trúc như vậy lại làm tăng rào cản tham gia của người không phải lập trình viên. Package manager là ngoại lệ, còn với dự án thông thường thì đây là vấn đề
Tôi đã tạo một thư viện mã nguồn mở tên là Datatig để giúp xử lý vấn đề này.
Tài liệu thuyết trình liên quan ở đây. Sau này tôi định tham khảo bài viết này để bổ sung thêm nội dung về mở rộng quy mô