gosuda.org/zstd: Kompresi DataDog/zstd Drop-In dengan Nol CGO dan Isolasi Crash
gosuda.org/zstd adalah pustaka kompresi Go CGO_ENABLED=0 yang menjalankan mesin resmi C Zstandard (libzstd 1.5.7) di dalam proses pekerja terisolasi melalui memori bersama HQQ. Ini menyediakan API pengganti langsung untuk github.com/DataDog/zstd (termasuk Compress/Decompress satu tembakan, streaming io.Writer/io.Reader, kamus yang telah diproses sebelumnya, dan konteks alokasi nol yang dapat digunakan kembali) sambil menjaga eksekusi C sepenuhnya di luar ruang alamat runtime Go.
1go get gosuda.org/zstd@v0.3.10507
Mengapa Dekompresi Berada di Luar Heap Go Anda
Dalam backend produksi, kompresi dan dekompresi berada tepat di batas input yang tidak tepercaya. Pengumpul log, pialang pesan, gateway RPC, dan mesin penyimpanan mendekompresi gigabita bingkai yang dipasok dari luar setiap menit.
Banyak tim Go memilih github.com/DataDog/zstd karena terikat langsung dengan C hulu libzstd: implementasi C menghadirkan throughput inti tunggal yang tinggi, rasio kompresi kamus yang ketat pada catatan kecil, dan area C di luar heap (ZSTD_CCtx dan ZSTD_DCtx) yang tidak menggelembungkan waktu pemindaian pengumpulan sampah Go.
Namun, menautkan libzstd ke dalam layanan Go melalui cgo membawa dua masalah operasional:
- Gesekan Pembangunan dan Penyebaran: Sama seperti
go-sqlite3,DataDog/zstdmemerlukanCGO_ENABLED=1dan toolchain kompiler C target. Layanan lintas-kompilasi atau membangun biner statis untuklinux/arm64atauwindows/arm64memerlukan sysroot C eksternal. - Ruang Alamat Bersama pada Input yang Tidak Tepercaya: Mendekompresi payload yang rusak atau bersifat musuh di dalam ruang alamat virtual yang sama dengan server Go Anda berarti segala bug dalam kode C asli atau penanganan kamus kustom dapat menghentikan seluruh proses Go.
gosuda.org/zstd mempertahankan mesin C hulu yang persis sama libzstd 1.5.7 dan API github.com/DataDog/zstd yang familiar, tetapi memindahkan eksekusi C ke dalam proses anak yang diverifikasi (zstd_server) yang terhubung ke program Go Anda melalui memori bersama baris tembolok.
Pengganti Langsung untuk github.com/DataDog/zstd
Bermigrasi dari github.com/DataDog/zstd hanya memerlukan pengubahan jalur impor menjadi "gosuda.org/zstd". Tidak ada instalasi biner eksternal atau kode penyiapan yang diperlukan: pada panggilan pertama, gosuda.org/zstd mewujudkan biner zstd_server yang disematkan dengan atestasi SLSA untuk platform Anda, memverifikasi ringkasan SHA-256 melalui gosuda.org/hqq/secureexec, dan membuka kumpulan sesi memori bersama.
1package main
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7 "log"
8
9 "gosuda.org/zstd"
10)
11
12func main() {
13 // 1. One-shot Compress / Decompress (mirrors github.com/DataDog/zstd)
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. Streaming Writer and Reader with Dictionary Support
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}
Platform yang Didukung dan Biner yang Disematkan
Keenam platform target dikirimkan dengan biner pekerja pra-bangun yang disematkan SHA-256 melalui tag build khusus platform (internal/embedded/embed_<goos>_<goarch>.go):
| OS Target | Arsitektur Target (GOARCH) | Biner yang Disematkan | Ukuran Biner | Toolchain Build & Provenans |
|---|---|---|---|---|
| Linux | amd64, arm64 | zstd_server_linux_<arch> | ~770 - 880 KiB | GCC -O3, SLSA Build L3 Provenance |
| macOS | arm64, amd64 | zstd_server_darwin_<arch> | ~660 - 795 KiB | AppleClang -O3, SLSA Build L3 Provenance |
| Windows | amd64 | zstd_server_windows_amd64.exe | ~818 KiB | MSVC -O2, SLSA Build L3 Provenance |
| Windows | arm64 | zstd_server_windows_arm64.exe | ~551 KiB | zig cc -target aarch64-windows-gnu -O3, SLSA L3 |
Di Dalam Jalur Data Memori Bersama
Untuk menjaga throughput tetap kompetitif dengan cgo dalam proses, gosuda.org/zstd menghindari serialisasi soket dan alokasi heap pada jalur aktif.
1. Pengkodean Slot Alokasi Nol (zstd_ctx.go dan c/zstd_hooks.c)
Ketika Anda menggunakan zstd.Ctx yang dapat digunakan kembali (atau ketika fungsi tingkat paket Compress dan Decompress meminjam Ctx dari kumpulan sesi internal), data mengalir langsung melalui slot StandardLink yang dipetakan:
1Go Caller (zstd.Ctx) Shared-Memory Slot C11 Worker (zstd_hooks.c)
2-------------------- ------------------ -------------------------
3src []byte -------------------------> Request Slot Payload -------------> ZSTD_compressCCtx(
4 cctx, resp_slot, src, level)
5dst []byte <------------------------- Response Slot Payload <------------- Writes compressed frame directly
6 into shared response slot
- Klien
hqq-bindgenyang dihasilkan menyalinsrclangsung ke dalam slot permintaan yang dipetakan memori dan membalik kata urutanSeqLock. - Pekerja C membaca
srcdi tempat dari slot permintaan dan meneruskan penunjuk payload slot respons secara langsung sebagai buffer tujuan keZSTD_compressCCtxatauZSTD_decompressDCtx. - Klien Go menyalin irisan yang dihasilkan dari slot respons ke dalam irisan
dstyang disediakan pemanggil. Dalam kondisi mapan,ctx.CompressTo(dst, src, level)danctx.DecompressInto(dst, src)melakukan0 allocs/op.
Kamus yang telah diproses sebelumnya (CDict and DDict) tinggal pada pekerja C di belakang penanganan 64-bit yang diperiksa generasinya (handle CDict, handle DDict dalam zstd.idl). Membuat kamus sekali melalui ctx.NewCDict(rawDict, level) menguraikan tabel kamus di dalam pekerja C dan mengembalikan penanganan ringan yang dapat digunakan kembali ribuan kali tanpa mengirim ulang byte kamus.
2. Mengamortisasi Overhead IPC dengan Pembingkaian Massal (zstd_bulk.go)
Untuk payload besar (16 KiB ke atas), perjalanan pulang pergi memori bersama ~200 ns dapat diabaikan dibandingkan dengan waktu CPU yang dihabiskan di dalam libzstd. Namun, untuk beban kerja yang mengompresi ribuan pesan kecil berukuran 100 byte hingga 1 KiB sekaligus, membayar bahkan 200 ns per item akan menumpuk.
gosuda.org/zstd menyediakan CompressBulk dan DecompressBulk pada BulkCtx (zstd_bulk.go) untuk menghilangkan perjalanan pulang pergi per item:
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 mengemas seluruh batch [][]byte ke dalam satu bingkai permintaan yang diawali panjang dalam memori bersama. Pekerja C melakukan perulangan atas setiap item dalam C (compress_bulk di c/zstd_hooks.c), menulis semua bingkai terkompresi secara berdampingan ke dalam slot respons, dan mengembalikan seluruh batch dalam satu perjalanan pulang pergi memori bersama.
3. Selamat dari Penghentian Pekerja Tanpa Menyebabkan Crash pada Pemanggil
Karena zstd_server berjalan dalam proses OS yang terpisah, kegagalan fatal di dalam pekerja C tidak akan pernah menjatuhkan aplikasi Go Anda:
- Jika
zstd_serverdimatikan secara eksternal (misalnya, olehSIGKILLatau peristiwa OOM), lapisan transportasi HQQ mendeteksi rekan yang rusak segera dan mengembalikan*rt.TransportErrorbertipe dari panggilanCompressatauDecompressyang sedang berlangsung. - Fungsi tingkat paket (
zstd.Compress,zstd.Decompress,zstd.NewWriter,zstd.NewReader) secara otomatis mendeteksi bahwa pekerja default bersama telah hilang, memunculkan instanszstd_serverbaru yang terverifikasi pada panggilan berikutnya, dan melanjutkan operasi normal.
Tata Letak Repositori
Basis kode memisahkan fasad DataDog/zstd pengganti langsung dari sesi tingkat rendah hqq-bindgen dan primitif massal:
1gosuda.org/zstd
2├── autolaunch.go / hashes.go # Drop-in Compress/Decompress API, auto-recovery pool, and SHA-256 hashes
3├── zstd_stream.go # Streaming Writer/Reader (NewWriterLevelDict, NewReaderDict)
4├── zstd_ctx.go # Zero-allocation Ctx, CDict, and DDict wrappers over hqq-bindgen
5├── zstd_bulk.go # Single-round-trip CompressBulk and DecompressBulk framing
6├── zstd.go # Generated hqq-bindgen Go client for the zstd IDL service
7├── zstd.idl # HQQ IDL schema defining Context, CDict, DDict, and RPC methods
8├── internal/embedded/ # Platform-tagged //go:embed zstd_server binaries (6 OS/Arch targets)
9└── c/ # C11 server implementation (zstd_server.c, zstd_hooks.c, main.c)
Memulai
Instal gosuda.org/zstd dengan go get dan gunakan dengan CGO_ENABLED=0:
1go get gosuda.org/zstd@v0.3.10507
- Repositori GitHub: https://github.com/gosuda/hqq-zstd
- Arsitektur & Tolok Ukur: docs/ARCHITECTURE.md
- Runtime Inti HQQ: https://gosuda.org/hqq