gosuda.org/zstd: Drop-In-erstatning for DataDog/zstd med nul CGO og crash-isolering

gosuda.org/zstd er et CGO_ENABLED=0 Go-komprimeringsbibliotek, der kører den officielle C Zstandard-motor (libzstd 1.5.7) inde i en isoleret arbejdsproces over HQQ delt hukommelse. Det tilbyder en drop-in-erstatnings-API for github.com/DataDog/zstd (herunder engangs-Compress/Decompress, streaming io.Writer/io.Reader, forudbearbejdede ordbøger og genbrugelige kontekster med nul allokeringer), samtidig med at C-eksekveringen holdes helt uden for Go-runtimens adresserum.
1go get gosuda.org/zstd@v0.3.10507
Hvorfor dekompression hører hjemme uden for din Go-heap
I produktionsbackends sidder komprimering og dekomprimering direkte på grænsen til utroværdigt input. Log-indsamlere, meddelelsesmæglere, RPC-gateways og lagringsmotorer dekomprimerer gigabytes af eksternt leverede rammer hvert minut.
Mange Go-teams vælger github.com/DataDog/zstd, fordi det binder direkte til upstream C libzstd: C-implementationen leverer høj gennemstrømning pr. enkelt kerne, stramme ordbogskomprimeringsforhold på små poster og off-heap C-arenaer (ZSTD_CCtx og ZSTD_DCtx), som ikke øger Go's scanningstid for affaldsindsamling.
At linke libzstd ind i en Go-tjeneste via cgo medfører dog to driftsmæssige smertepunkter:
- Byggeri- og udrulningsfriktion: Ligesom
go-sqlite3kræverDataDog/zstdCGO_ENABLED=1og en målrettet C-compilerværktøjskæde. Krydskompilering af tjenester eller opbygning af statiske binære filer tillinux/arm64ellerwindows/arm64kræver eksterne C-sysroots. - Delt adresserum ved utroværdigt input: Dekomprimering af korrupte eller fjendtlige nyttelaster inde i samme virtuelle adresserum som din Go-server betyder, at enhver fejl i nativ C-kode eller tilpasset ordbogshåndtering kan afslutte hele Go-processen.
gosuda.org/zstd bevarer den nøjagtige upstream C libzstd 1.5.7-motor og den velkendte github.com/DataDog/zstd-API, men flytter C-eksekveringen ind i en verificeret underproces (zstd_server), som er forbundet til dit Go-program over delt hukommelse justeret til cache-linjer.
Drop-in-erstatning for github.com/DataDog/zstd
Migrering fra github.com/DataDog/zstd kræver kun, at importstien ændres til "gosuda.org/zstd". Der er ingen installation af eksterne binære filer eller opsætningskode påkrævet: ved det første kald materialiserer gosuda.org/zstd en indlejret SLSA-attesteret zstd_server-binær fil til din platform, verificerer dens SHA-256-digest via gosuda.org/hqq/secureexec og åbner en pulje af delt-hukommelsessessioner.
1package main
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7 "log"
8
9 "gosuda.org/zstd"
10)
11
12func main() {
13 // 1. Engangs-Compress / Decompress (spejler 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 og Reader med ordbogsunderstøttelse
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}
Understøttede platforme og indlejrede binære filer
Alle seks målplatforme leveres med forudbyggede, SHA-256-fastlåste arbejdsbinære filer, indlejret via platformsspecifikke build-tags (internal/embedded/embed_<goos>_<goarch>.go):
| Målstyresystem | Målarkitektur (GOARCH) | Indlejret binær fil | Binær størrelse | Byggeværktøjskæde og proveniens |
|---|---|---|---|---|
| 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 |
Inde i datastien med delt hukommelse
For at holde gennemstrømningen konkurrencedygtig med in-process cgo undgår gosuda.org/zstd socket-serialisering og heap-allokeringer på den kritiske sti.
1. Kodning af slots uden allokeringer (zstd_ctx.go og c/zstd_hooks.c)
Når du bruger en genbrugelig zstd.Ctx (eller når pakkeniveau-funktionerne Compress og Decompress låner en Ctx fra den interne sessionspulje), flyder data direkte gennem den kortlagte StandardLink-slot:
1Go-kaldende kode (zstd.Ctx) Slot i delt hukommelse C11-arbejder (zstd_hooks.c)
2--------------------------- ---------------------- -------------------------
3src []byte -------------------------> Nyttelast i anmodningsslot ------------> ZSTD_compressCCtx(
4 cctx, resp_slot, src, level)
5dst []byte <------------------------- Nyttelast i svarslot <------------- Skriver den komprimerede ramme direkte
6 ind i den delte svarslot
- Den genererede
hqq-bindgen-klient kopierersrcdirekte ind i den hukommelsesmappede anmodningsslot og vender sekvensordet iSeqLock. - C-arbejderen læser
srcpå stedet fra anmodningsslotten og sender svarslottens nyttelastpointer direkte som destinationsbuffer tilZSTD_compressCCtxellerZSTD_decompressDCtx. - Go-klienten kopierer den resulterende slice fra svarslotten over i den af kalderen leverede
dst-slice. I steady state udførerctx.CompressTo(dst, src, level)ogctx.DecompressInto(dst, src)0 allocs/op.
Forudbearbejdede ordbøger (CDict og DDict) lever på C-arbejderen bag generationskontrollerede 64-bit-håndtag (handle CDict, handle DDict i zstd.idl). Oprettelse af en ordbog én gang via ctx.NewCDict(rawDict, level) parser ordbogens tabeller inde i C-arbejderen og returnerer et letvægtshåndtag, der kan genbruges på tværs af tusindvis af kald uden at sende ordbogsbytene igen.
2. Amortisering af IPC-overhead med bulk-indramning (zstd_bulk.go)
For store nyttelaster (16 KiB og derover) er den ca. 200 ns lange round trip via delt hukommelse ubetydelig sammenlignet med CPU-tiden brugt inde i libzstd. For arbejdsbelastninger, der komprimerer tusindvis af små beskeder på 100 byte til 1 KiB på én gang, lægger selv 200 ns pr. element dog sig op.
gosuda.org/zstd tilbyder CompressBulk og DecompressBulk på BulkCtx (zstd_bulk.go) for at eliminere round trips pr. element:
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 pakker hele [][]byte-batchen ind i en enkelt længdeprefikset anmodningsramme i delt hukommelse. C-arbejderen itererer over hvert element i C (compress_bulk i c/zstd_hooks.c), skriver alle komprimerede rammer sammenhængende ind i svarslotten og returnerer hele batchen i en enkelt round trip via delt hukommelse.
3. Overlevelse af arbejdsafslutning uden at styrte kalderen
Fordi zstd_server kører i en separat OS-proces, bringer en fatal fejl inde i C-arbejderen aldrig din Go-applikation ned:
- Hvis
zstd_serverdræbes eksternt (for eksempel viaSIGKILLeller en OOM-hændelse), registrerer HQQ-transportlaget den brudte modpart med det samme og returnerer en typet*rt.TransportErrorfra det igangværendeCompress- ellerDecompress-kald. - Pakkeniveau-funktioner (
zstd.Compress,zstd.Decompress,zstd.NewWriter,zstd.NewReader) registrerer automatisk, at den delte standardarbejder er væk, starter en ny verificeretzstd_server-instans ved næste kald og genoptager normal drift.
Repository-layout
Kodebasen adskiller drop-in-facaden DataDog/zstd fra de lavniveau-primitiver for session og bulk i hqq-bindgen:
1gosuda.org/zstd
2├── autolaunch.go / hashes.go # Drop-in Compress/Decompress-API, pulje med automatisk genopretning og SHA-256-hashes
3├── zstd_stream.go # Streaming Writer/Reader (NewWriterLevelDict, NewReaderDict)
4├── zstd_ctx.go # Ctx, CDict og DDict uden allokeringer, indpakninger over hqq-bindgen
5├── zstd_bulk.go # Indramning af CompressBulk og DecompressBulk med én round trip
6├── zstd.go # Genereret hqq-bindgen Go-klient for zstd IDL-tjenesten
7├── zstd.idl # HQQ IDL-skema, der definerer Context, CDict, DDict og RPC-metoder
8├── internal/embedded/ # Platformsmærkede //go:embed zstd_server-binære filer (6 OS/arkitektur-mål)
9└── c/ # C11-serverimplementation (zstd_server.c, zstd_hooks.c, main.c)
Kom i gang
Installer gosuda.org/zstd med go get og brug det med CGO_ENABLED=0:
1go get gosuda.org/zstd@v0.3.10507
- GitHub-repository: https://github.com/gosuda/hqq-zstd
- Arkitektur og benchmarks: docs/ARCHITECTURE.md
- HQQ Core Runtime: https://gosuda.org/hqq