gosuda.org/zstd: Sıfır CGO ve Çökme İzolasyonu ile DataDog/zstd'nin Doğrudan Yerine Kullanılabilen Sıkıştırma Kütüphanesi

gosuda.org/zstd, CGO_ENABLED=0 ile çalışan bir Go sıkıştırma kütüphanesidir; resmi C Zstandard (libzstd 1.5.7) motorunu, HQQ paylaşımlı belleği üzerinden yalıtılmış bir çalışan süreç (worker process) içinde çalıştırır. github.com/DataDog/zstd için doğrudan yerine geçebilen bir API sunar (tek seferlik Compress/Decompress, akış tabanlı io.Writer/io.Reader, önceden işlenmiş sözlükler ve yeniden kullanılabilir sıfır ayırmalı bağlamlar dahil) ve C yürütmesini Go çalışma zamanı adres alanının tamamen dışında tutar.
1go get gosuda.org/zstd@v0.3.10507
Sıkıştırma ve Açmanın Neden Go Yığınınızın Dışında Yer Alması Gerektiği
Üretim ortamındaki arka uç sistemlerinde sıkıştırma ve sıkıştırma açma işlemleri doğrudan güvenilmeyen girdi sınırında gerçekleşir. Günlük toplayıcıları, mesaj aracıları, RPC ağ geçitleri ve depolama motorları, her dakika gigabaytlarca dışarıdan sağlanan çerçeveyi açar.
Birçok Go ekibi github.com/DataDog/zstd kütüphanesini tercih eder; çünkü bu kütüphane doğrudan üst akış C libzstd ile bağlanır: C uygulaması yüksek tek çekirdek verimi, küçük kayıtlarda sıkı sözlük sıkıştırma oranları ve Go çöp toplama tarama sürelerini artırmayan, yığın dışı C bellek alanları (ZSTD_CCtx ve ZSTD_DCtx) sunar.
Ancak libzstd kütüphanesini cgo üzerinden bir Go servisine bağlamak iki operasyonel sorun doğurur:
- Derleme ve Dağıtım Sürtünmesi:
go-sqlite3gibi,DataDog/zstddeCGO_ENABLED=1ve hedef bir C derleyici araç zinciri gerektirir.linux/arm64veyawindows/arm64için servisleri çapraz derlemek ya da statik ikili dosyalar oluşturmak harici C sysroot'ları gerektirir. - Güvenilmeyen Girdilerde Paylaşılan Adres Alanı: Bozuk veya düşmanca yükleri Go sunucunuzla aynı sanal adres alanında açmak, yerel C kodundaki veya özel sözlük işlemesindeki herhangi bir hata tüm Go sürecini sonlandırabilir.
gosuda.org/zstd, tam olarak üst akış C libzstd 1.5.7 motorunu ve tanıdık github.com/DataDog/zstd API'sini korur; ancak C yürütmesini, önbellek hattı paylaşımlı belleği üzerinden Go programınıza bağlı doğrulanmış bir alt süreçe (zstd_server) taşır.
github.com/DataDog/zstd İçin Doğrudan Yerine Geçen Kütüphane
github.com/DataDog/zstd kütüphanesinden geçiş yapmak yalnızca içe aktarma yolunun "gosuda.org/zstd" olarak değiştirilmesini gerektirir. Harici bir ikili dosya kurulumu veya kurulum kodu gerekmez: ilk çağrıda gosuda.org/zstd, platformunuz için gömülü, SLSA ile onaylanmış bir zstd_server ikili dosyasını açığa çıkarır, SHA-256 özetini gosuda.org/hqq/secureexec aracılığıyla doğrular ve bir paylaşımlı bellek oturum havuzu açar.
1package main
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7 "log"
8
9 "gosuda.org/zstd"
10)
11
12func main() {
13 // 1. Tek seferlik Compress / Decompress (github.com/DataDog/zstd ile aynıdır)
14 src := []byte("shared-memory zstd payload without cgo")
15 compressed, err := zstd.CompressLevel(nil, src, zstd.BestSpeed)
16 if err != nil {
17 log.Fatal(err)
18 }
19 plain, err := zstd.Decompress(nil, compressed)
20 if err != nil {
21 log.Fatal(err)
22 }
23 fmt.Printf("one-shot: %d bytes -> %d bytes (%s)\n", len(src), len(compressed), plain)
24
25 // 2. Sözlük desteğiyle akış Writer ve Reader
26 var buf bytes.Buffer
27 w := zstd.NewWriterLevel(&buf, zstd.DefaultCompression)
28 if _, err := w.Write(src); err != nil {
29 log.Fatal(err)
30 }
31 if err := w.Close(); err != nil {
32 log.Fatal(err)
33 }
34
35 r := zstd.NewReader(&buf)
36 defer r.Close()
37 streamed, err := io.ReadAll(r)
38 if err != nil {
39 log.Fatal(err)
40 }
41 fmt.Printf("streamed: %s\n", streamed)
42}
Desteklenen Platformlar ve Gömülü İkili Dosyalar
Altı hedef platformun tamamı, platforma özgü derleme etiketleri (internal/embedded/embed_<goos>_<goarch>.go) aracılığıyla gömülü, SHA-256 ile sabitlenmiş önceden derlenmiş çalışan ikili dosyalarla gelir:
| Hedef İşletim Sistemi | Hedef Mimari (GOARCH) | Gömülü İkili Dosya | İkili Dosya Boyutu | Derleme Araç Zinciri ve Köken |
|---|---|---|---|---|
| Linux | amd64, arm64 | zstd_server_linux_<arch> | ~770 - 880 KiB | GCC -O3, SLSA Build L3 Köken |
| macOS | arm64, amd64 | zstd_server_darwin_<arch> | ~660 - 795 KiB | AppleClang -O3, SLSA Build L3 Köken |
| Windows | amd64 | zstd_server_windows_amd64.exe | ~818 KiB | MSVC -O2, SLSA Build L3 Köken |
| Windows | arm64 | zstd_server_windows_arm64.exe | ~551 KiB | zig cc -target aarch64-windows-gnu -O3, SLSA L3 |
Paylaşımlı Bellek Veri Yolunun İçinde
gosuda.org/zstd, süreç içi cgo ile rekabetçi verimi korumak için sıcak yolda soket serileştirmesinden ve yığın ayırmalarından kaçınır.
1. Sıfır Ayırmalı Yuva Kodlaması (zstd_ctx.go ve c/zstd_hooks.c)
Yeniden kullanılabilir bir zstd.Ctx kullandığınızda (veya paket düzeyindeki Compress ve Decompress fonksiyonları dahili oturum havuzundan bir Ctx ödünç aldığında), veri eşlenmiş StandardLink yuvası üzerinden doğrudan akar:
1Go Çağrıcı (zstd.Ctx) Paylaşımlı Bellek Yuvası C11 Çalışanı (zstd_hooks.c)
2--------------------- ------------------------ ---------------------------
3src []byte -------------------------> İstek Yuvası Yükü ----------------> ZSTD_compressCCtx(
4 cctx, resp_slot, src, level)
5dst []byte <------------------------- Yanıt Yuvası Yükü <---------------- Sıkıştırılmış çerçeveyi doğrudan
6 paylaşımlı yanıt yuvasına yazar
- Üretilmiş
hqq-bindgenistemcisi,srcverisini bellek eşlemeli istek yuvasına doğrudan kopyalar veSeqLocksıra sözcüğünü çevirir. - C çalışanı
srcverisini istek yuvasından yerinde okur ve yanıt yuvasının yük işaretçisini hedef arabellek olarak doğrudanZSTD_compressCCtxveyaZSTD_decompressDCtxfonksiyonuna geçirir. - Go istemcisi ortaya çıkan dilimi yanıt yuvasından çağıranın sağladığı
dstdilimine kopyalar. Kararlı durumdactx.CompressTo(dst, src, level)vectx.DecompressInto(dst, src)işlemleri0 allocs/opgerçekleştirir.
Önceden işlenmiş sözlükler (CDict ve DDict), zstd.idl içindeki nesil kontrollü 64 bitlik tutamaçların (handle CDict, handle DDict) arkasında C çalışanı üzerinde yaşar. ctx.NewCDict(rawDict, level) ile bir sözlüğü bir kez oluşturmak, sözlük tablolarını C çalışanının içinde ayrıştırır ve sözlük baytlarını yeniden göndermeden binlerce çağrı boyunca yeniden kullanılabilen hafif bir tutamaç döndürür.
2. Toplu Çerçeveleme ile IPC Ek Yükünün Amortismanı (zstd_bulk.go)
Büyük yükler (16 KiB ve üzeri) için yaklaşık 200 ns'lik paylaşımlı bellek gidiş-dönüş süresi, libzstd içinde harcanan CPU süresiyle karşılaştırıldığında ihmal edilebilir düzeydedir. Ancak her biri 100 bayt ile 1 KiB arasında olan binlerce küçük mesajı bir seferde sıkıştıran iş yükleri için, öğe başına 200 ns bile birikir.
gosuda.org/zstd, öğe başına gidiş-dönüşleri ortadan kaldırmak için BulkCtx (zstd_bulk.go) üzerinde CompressBulk ve DecompressBulk sağlar:
1bctx, err := client.NewBulkCtx(1 << 20)
2if err != nil {
3 log.Fatal(err)
4}
5defer bctx.Close()
6
7items := [][]byte{
8 []byte(`{"event":"login","user":101}`),
9 []byte(`{"event":"purchase","user":101,"amount":4200}`),
10 []byte(`{"event":"logout","user":101}`),
11}
12compressedItems, err := bctx.CompressBulk(nil, items, zstd.DefaultCompression)
CompressBulk, tüm [][]byte grubunu paylaşımlı bellekte tek bir uzunluk önekli istek çerçevesine paketler. C çalışanı, her öğe üzerinde C içinde döngü yapar (c/zstd_hooks.c içindeki compress_bulk), sıkıştırılmış tüm çerçeveleri yanıt yuvasına bitişik olarak yazar ve tüm grubu tek bir paylaşımlı bellek gidiş-dönüşünde döndürür.
3. Çağıranı Çökertmeden Çalışan Sonlanmasından Kurtulma
zstd_server ayrı bir işletim sistemi sürecinde çalıştığı için, C çalışanının içindeki ölümcül bir hata Go uygulamanızı asla çökertmez:
zstd_serverdışarıdan sonlandırılırsa (örneğinSIGKILLveya bellek yetersizliği olayı ile), HQQ taşıma katmanı bozulmuş eşi hemen algılar ve devam edenCompressveyaDecompressçağrısından tipli bir*rt.TransportErrordöndürür.- Paket düzeyindeki işlevler (
zstd.Compress,zstd.Decompress,zstd.NewWriter,zstd.NewReader), paylaşılan varsayılan çalışanın ortadan kalktığını otomatik olarak algılar, bir sonraki çağrıda yeni bir doğrulanmışzstd_serverörneği başlatır ve normal işleyişe devam eder.
Depo Yapısı
Kod tabanı, doğrudan DataDog/zstd yüzünü düşük seviyeli hqq-bindgen oturum ve toplu ilkellerinden ayırır:
1gosuda.org/zstd
2├── autolaunch.go / hashes.go # Doğrudan Compress/Decompress API'si, otomatik kurtarma havuzu ve SHA-256 özetleri
3├── zstd_stream.go # Akış Writer/Reader (NewWriterLevelDict, NewReaderDict)
4├── zstd_ctx.go # hqq-bindgen üzerinde sıfır ayırmalı Ctx, CDict ve DDict sarmalayıcıları
5├── zstd_bulk.go # Tek gidiş-dönüşlü CompressBulk ve DecompressBulk çerçevelemesi
6├── zstd.go # Üretilmiş hqq-bindgen Go istemcisi (zstd IDL servisi için)
7├── zstd.idl # Context, CDict, DDict ve RPC yöntemlerini tanımlayan HQQ IDL şeması
8├── internal/embedded/ # Platform etiketli //go:embed zstd_server ikili dosyaları (6 OS/Mimari hedefi)
9└── c/ # C11 sunucu uygulaması (zstd_server.c, zstd_hooks.c, main.c)
Başlarken
gosuda.org/zstd kütüphanesini go get ile kurun ve CGO_ENABLED=0 ile kullanın:
1go get gosuda.org/zstd@v0.3.10507
- GitHub Deposu: https://github.com/gosuda/hqq-zstd
- Mimari ve Kıyaslamalar: docs/ARCHITECTURE.md
- HQQ Çekirdek Çalışma Zamanı: https://gosuda.org/hqq