GoSuda

gosuda.org/zstd: Kompresi DataDog/zstd Drop-In dengan Nol CGO dan Isolasi Crash

By Lemon Mint
views ...

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:

  1. Gesekan Pembangunan dan Penyebaran: Sama seperti go-sqlite3, DataDog/zstd memerlukan CGO_ENABLED=1 dan toolchain kompiler C target. Layanan lintas-kompilasi atau membangun biner statis untuk linux/arm64 atau windows/arm64 memerlukan sysroot C eksternal.
  2. 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 TargetArsitektur Target (GOARCH)Biner yang DisematkanUkuran BinerToolchain Build & Provenans
Linuxamd64, arm64zstd_server_linux_<arch>~770 - 880 KiBGCC -O3, SLSA Build L3 Provenance
macOSarm64, amd64zstd_server_darwin_<arch>~660 - 795 KiBAppleClang -O3, SLSA Build L3 Provenance
Windowsamd64zstd_server_windows_amd64.exe~818 KiBMSVC -O2, SLSA Build L3 Provenance
Windowsarm64zstd_server_windows_arm64.exe~551 KiBzig 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
  1. Klien hqq-bindgen yang dihasilkan menyalin src langsung ke dalam slot permintaan yang dipetakan memori dan membalik kata urutan SeqLock.
  2. Pekerja C membaca src di tempat dari slot permintaan dan meneruskan penunjuk payload slot respons secara langsung sebagai buffer tujuan ke ZSTD_compressCCtx atau ZSTD_decompressDCtx.
  3. Klien Go menyalin irisan yang dihasilkan dari slot respons ke dalam irisan dst yang disediakan pemanggil. Dalam kondisi mapan, ctx.CompressTo(dst, src, level) dan ctx.DecompressInto(dst, src) melakukan 0 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_server dimatikan secara eksternal (misalnya, oleh SIGKILL atau peristiwa OOM), lapisan transportasi HQQ mendeteksi rekan yang rusak segera dan mengembalikan *rt.TransportError bertipe dari panggilan Compress atau Decompress yang sedang berlangsung.
  • Fungsi tingkat paket (zstd.Compress, zstd.Decompress, zstd.NewWriter, zstd.NewReader) secara otomatis mendeteksi bahwa pekerja default bersama telah hilang, memunculkan instans zstd_server baru 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