gosuda.org/zstd: Drop-In-erstatning for DataDog/zstd med null CGO og krasjisolering

gosuda.org/zstd er et CGO_ENABLED=0 Go-komprimeringsbibliotek som kjører det offisielle C Zstandard-motoren (libzstd 1.5.7) i en isolert arbeidsprosess over HQQ delt minne. Det tilbyr et drop-in-erstatningsgrensesnitt for github.com/DataDog/zstd (inkludert engangs-Compress/Decompress, strømmende io.Writer/io.Reader, forhåndsbehandlede ordbøker og gjenbrukbare kontekster uten allokeringer), samtidig som C-kjøringen holdes helt utenfor adresserommet til Go-runtime.
1go get gosuda.org/zstd@v0.3.10507
Hvorfor dekomprimering hører hjemme utenfor Go-heapen
I produksjonsbaserte backend-systemer ligger komprimering og dekomprimering direkte på grensen mot utrusted inndata. Loggsamlere, meldingsmeglere, RPC-gatewayer og lagringsmotorer dekomprimerer gigabyte med eksternt leverte rammer hvert minutt.
Mange Go-team velger github.com/DataDog/zstd fordi den binder direkte mot opprinnelig C-libzstd: C-implementasjonen gir høy gjennomstrømning per kjerne, presise komprimeringsforhold for ordbøker på små poster, og C-arenaer utenfor heapen (ZSTD_CCtx og ZSTD_DCtx) som ikke øker tiden for søppelinnsamlerens skanning i Go.
Å koble libzstd inn i en Go-tjeneste via cgo medfører imidlertid to operasjonelle utfordringer:
- Friksjon ved bygging og utrulling: Akkurat som
go-sqlite3kreverDataDog/zstdCGO_ENABLED=1og en måldrettet C-kompilatorverktøykjede. Krysskompilering av tjenester eller bygging av statiske binærfiler forlinux/arm64ellerwindows/arm64krever eksterne C-sysroots. - Delt adresserom ved utrusted inndata: Dekomprimering av korrupte eller ondsinnede nyttelaster i samme virtuelle adresserom som Go-serveren din betyr at enhver feil i native C-kode eller egendefinert ordbokshåndtering kan avslutte hele Go-prosessen.
gosuda.org/zstd beholder den eksakte opprinnelige C-motoren libzstd 1.5.7 og det kjente API-et til github.com/DataDog/zstd, men flytter C-kjøringen over i en verifisert barneprosess (zstd_server) koblet til Go-programmet ditt over delt minne tilpasset cache-linjer.
Drop-in-erstatning for github.com/DataDog/zstd
Migrering fra github.com/DataDog/zstd krever kun endring av importstien til "gosuda.org/zstd". Ingen ekstern binærinstallasjon eller oppsettskode er nødvendig: ved første kall materialiserer gosuda.org/zstd en innebygd SLSA-attestert zstd_server-binærfil for plattformen din, verifiserer dens SHA-256-digest via gosuda.org/hqq/secureexec, og åpner en delt-minne-sesjonspool.
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 (speiler 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. Strømmende Writer og Reader med støtte for ordbøker
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}
Støttede plattformer og innebygde binærfiler
Alle seks målplattformer leveres med forhåndsbygde, SHA-256-festede arbeiderbinærfiler innebygd via plattformspesifikke build-tagger (internal/embedded/embed_<goos>_<goarch>.go):
| Målsystem | Målarkitektur (GOARCH) | Innebygd binærfil | Binærstørrelse | Byggeverktøykjede og proveniens |
|---|---|---|---|---|
| Linux | amd64, arm64 | zstd_server_linux_<arch> | ~770 - 880 KiB | GCC -O3, SLSA Build L3-proveniens |
| macOS | arm64, amd64 | zstd_server_darwin_<arch> | ~660 - 795 KiB | AppleClang -O3, SLSA Build L3-proveniens |
| Windows | amd64 | zstd_server_windows_amd64.exe | ~818 KiB | MSVC -O2, SLSA Build L3-proveniens |
| Windows | arm64 | zstd_server_windows_arm64.exe | ~551 KiB | zig cc -target aarch64-windows-gnu -O3, SLSA L3 |
Inne i datastien over delt minne
For å holde gjennomstrømningen konkurransedyktig med in-process cgo, unngår gosuda.org/zstd socket-serialisering og heap-allokeringer på den kritiske stien.
1. Allokeringsfri slot-koding (zstd_ctx.go og c/zstd_hooks.c)
Når du bruker en gjenbrukbar zstd.Ctx (eller når pakkenivåfunksjonene Compress og Decompress låner en Ctx fra den interne sesjonspoolen), flyter data direkte gjennom den mappede StandardLink-slotten:
1Go-kaller (zstd.Ctx) Slot i delt minne C11-arbeider (zstd_hooks.c)
2-------------------- ----------------- ---------------------------
3src []byte -------------------------> Nyttelast i forespørselsslot -------> ZSTD_compressCCtx(
4 cctx, resp_slot, src, level)
5dst []byte <------------------------- Nyttelast i responsslot <------------- Skriver komprimert ramme direkte
6 inn i delt responsslot
- Den genererte
hqq-bindgen-klienten kopierersrcrett inn i den minnemappede forespørselsslotten og endrerSeqLock-sekvensordet. - C-arbeideren leser
srcpå stedet fra forespørselsslotten og sender responsslotens nyttelastpeker direkte som målbuffer tilZSTD_compressCCtxellerZSTD_decompressDCtx. - Go-klienten kopierer den resulterende slicen fra responsslotten inn i den av kalleren oppgitte
dst-slicen. I stabil tilstand utførerctx.CompressTo(dst, src, level)ogctx.DecompressInto(dst, src)0 allocs/op.
Forhåndsbehandlede ordbøker (CDict og DDict) lever på C-arbeideren bak generasjonskontrollerte 64-bits håndtak (handle CDict, handle DDict i zstd.idl). Å opprette en ordbok én gang via ctx.NewCDict(rawDict, level) parser ordbokstabellene inne i C-arbeideren og returnerer et lettvekts håndtak som kan gjenbrukes på tvers av tusenvis av kall uten å sende ordbokbytene på nytt.
2. Amortisering av IPC-overhead med bulkinnramming (zstd_bulk.go)
For store nyttelaster (16 KiB og større) er den ~200 ns lange rundturen over delt minne ubetydelig sammenlignet med CPU-tiden brukt inne i libzstd. For arbeidsbelastninger som komprimerer tusenvis av små meldinger på 100 byte til 1 KiB samtidig, legger imidlertid selv 200 ns per element seg opp.
gosuda.org/zstd tilbyr CompressBulk og DecompressBulk på BulkCtx (zstd_bulk.go) for å eliminere rundturer per 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 inn i en enkelt lengdeprefikset forespørselsramme i delt minne. C-arbeideren løkker over hvert element i C (compress_bulk i c/zstd_hooks.c), skriver alle komprimerte rammer sammenhengende inn i responsslotten, og returnerer hele batchen i én enkelt rundtur over delt minne.
3. Å overleve avslutning av arbeideren uten å krasje kalleren
Fordi zstd_server kjører i en separat OS-prosess, tar en fatal feil inne i C-arbeideren aldri ned Go-applikasjonen din:
- Hvis
zstd_serveravsluttes eksternt (for eksempel viaSIGKILLeller en OOM-hendelse), oppdager HQQ-transportlaget den brutte motparten umiddelbart og returnerer en typet*rt.TransportErrorfra det pågåendeCompress- ellerDecompress-kallet. - Pakkenivåfunksjoner (
zstd.Compress,zstd.Decompress,zstd.NewWriter,zstd.NewReader) oppdager automatisk at den delte standardarbeideren er borte, starter en ny verifisertzstd_server-instans ved neste kall, og gjenopptar normal drift.
Oppsett av repositoriet
Kodebasen skiller drop-in-fasaden DataDog/zstd fra de lavnivå sesjons- og bulkprimitivene i hqq-bindgen:
1gosuda.org/zstd
2├── autolaunch.go / hashes.go # Drop-in Compress/Decompress-API, pool for automatisk gjenoppretting og SHA-256-hasher
3├── zstd_stream.go # Strømmende Writer/Reader (NewWriterLevelDict, NewReaderDict)
4├── zstd_ctx.go # Allokeringsfrie Ctx-, CDict- og DDict-omslag over hqq-bindgen
5├── zstd_bulk.go # Innramming for CompressBulk og DecompressBulk med én enkelt rundtur
6├── zstd.go # Generert hqq-bindgen Go-klient for zstd IDL-tjenesten
7├── zstd.idl # HQQ IDL-skjema som definerer Context, CDict, DDict og RPC-metoder
8├── internal/embedded/ # Plattformmerkede //go:embed zstd_server-binærfiler (6 OS/arkitektur-mål)
9└── c/ # C11-serverimplementasjon (zstd_server.c, zstd_hooks.c, main.c)
Kom i gang
Installer gosuda.org/zstd med go get og bruk det med CGO_ENABLED=0:
1go get gosuda.org/zstd@v0.3.10507
- GitHub-repositorium: https://github.com/gosuda/hqq-zstd
- Arkitektur og benchmarks: docs/ARCHITECTURE.md
- HQQ Core Runtime: https://gosuda.org/hqq