gosuda.org/zstd: Drop-In DataDog/zstd Compression with Zero CGO and Crash Isolation
gosuda.org/zstd on CGO_ENABLED=0 -muotoinen Go-pakkauskirjasto, joka suorittaa virallista C Zstandard (libzstd 1.5.7) -moottoria eristetyssä taustaprosessissa HQQ -jaetun muistin kautta. Se tarjoaa suoraan korvattavan API:n kirjastolle github.com/DataDog/zstd (mukaan lukien kertaluonteiset Compress/Decompress-toiminnot, suoratoistavat io.Writer/io.Reader-rajapinnat, esikäsitellyt sanakirjat ja uudelleenkäytettävät zero-allocation-kontekstit) pitäen samalla C-koodin suorituksen täysin Go-ajuaikaympäristön osoiteavaruuden ulkopuolella.
1go get gosuda.org/zstd@v0.3.10507
Miksi purkaminen kuuluu Go-keon ulkopuolelle
Tuotantotaustajärjestelmissä pakkaus ja purkaminen sijaitsevat suoraan epäluotettavan syötteen rajapinnalla. Lokienkerääjät, sanomanvälittäjät, RPC-yhdyskäytävät ja tallennusmoottorit purkavat gigatavuittain ulkoisesti toimitettuja kehyksiä joka minuutti.
Monet Go-tiimit valitsevat kirjaston github.com/DataDog/zstd, koska se sitoutuu suoraan ylävirran C libzstd-toteutukseen: C-toteutus tarjoaa korkean yhden ytimen suorituskyvyn, tiukat sanakirjan pakkaussuhteet pienille tietueille sekä keon ulkopuoliset C-muistialueet (ZSTD_CCtx ja ZSTD_DCtx), jotka eivät kasvata Go-muistinhallinnan skannausaikoja.
Kirjaston libzstd linkittäminen Go-palveluun cgo-rajapinnan kautta tuo kuitenkin mukanaan kaksi toiminnallista ongelmaa:
- Käännös- ja käyttöönottohaasteet: Aivan kuten
go-sqlite3,DataDog/zstdedellyttää asetustaCGO_ENABLED=1ja kohde-C-kääntäjätyökaluketjua. Palveluiden ristiinkääntäminen tai staattisten binaaritiedostojen luominen ympäristöillelinux/arm64taiwindows/arm64vaatii ulkoisia C-järjestelmätiedostoja. - Jaettu osoiteavaruus epäluotettavilla syötteillä: Vioittuneiden tai haitallisten hyötykuormien purkaminen samassa virtuaalisessa osoiteavaruudessa Go-palvelimen kanssa tarkoittaa, että mikä tahansa virhe natiivissa C-koodissa tai mukautetussa sanakirjan käsittelyssä voi pysäyttää koko Go-prosessin.
gosuda.org/zstd säilyttää tarkan ylävirran C libzstd 1.5.7 -moottorin ja tutun github.com/DataDog/zstd-rajapinnan, mutta siirtää C-koodin suorituksen varmennettuun lapsiprosessiin (zstd_server), joka on yhteydessä Go-ohjelmaasi välimuistilinjan jaetun muistin kautta.
Suora korvike kirjastolle github.com/DataDog/zstd
Siirtyminen kirjastosta github.com/DataDog/zstd edellyttää vain tuontipolun muuttamista muotoon "gosuda.org/zstd". Mitään ulkoista binaariasennusta tai asetuskoodia ei tarvita: ensimmäisellä kutsulla gosuda.org/zstd muodostaa alustallesi upotetun SLSA-varmennetun zstd_server-binaaritiedoston, tarkistaa sen SHA-256-tiivisteen funktion gosuda.org/hqq/secureexec kautta ja avaa jaetun muistin istuntoaltaan.
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}
Tuetut alustat ja upotetut binaaritiedostot
Kaikki kuusi kohdealustaa sisältävät esirakennetut, SHA-256-tiivisteillä sidotut taustaprosessibinaaritiedostot, jotka on upotettu alustakohtaisten käännöstunnisteiden (internal/embedded/embed_<goos>_<goarch>.go) kautta:
| Kohde-OS | Kohdearkkitehtuuri (GOARCH) | Upotettu binaari | Binaarikoko | Käännöstyökaluketju ja alkuperä |
|---|---|---|---|---|
| Linux | amd64, arm64 | zstd_server_linux_<arch> | ~770 - 880 KiB | GCC -O3, SLSA Build L3 -alkuperä |
| macOS | arm64, amd64 | zstd_server_darwin_<arch> | ~660 - 795 KiB | AppleClang -O3, SLSA Build L3 -alkuperä |
| Windows | amd64 | zstd_server_windows_amd64.exe | ~818 KiB | MSVC -O2, SLSA Build L3 -alkuperä |
| Windows | arm64 | zstd_server_windows_arm64.exe | ~551 KiB | zig cc -target aarch64-windows-gnu -O3, SLSA L3 |
Jaetun muistin datapolun sisällä
Jotta suorituskyky pysyisi kilpailukykyisenä prosessinsisäisen cgo-mekanismin kanssa, gosuda.org/zstd välttää socket-sarjoittamista ja keon varauksia herkällä polulla.
1. Nollavarauksinen paikkakoodaus (zstd_ctx.go ja c/zstd_hooks.c)
Kun käytät uudelleenkäytettävää zstd.Ctx-kontekstia (tai kun pakettitason Compress- ja Decompress-funktiot lainaavat Ctx-kontekstin sisäisestä istuntoaltaasta), data kulkee suoraan muistiin kuvatun StandardLink-paikan kautta:
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
- Generoitu
hqq-bindgen-asiakasohjelma kopioi kohteensrcsuoraan muistiin kuvattuun pyyntöpaikkaan ja kääntääSeqLock-sekvenssisanan. - C-taustaprosessi lukee kohteen
srcsuoraan pyyntöpaikasta ja välittää vastauspaikan hyötykuorman osoitteen suoraan kohdepuskurina funktioilleZSTD_compressCCtxtaiZSTD_decompressDCtx. - Go-asiakasohjelma kopioi tuloksena saadun viipaleen vastauspaikasta kutsujan toimittamaan
dst-viipaleeseen. Vakaassa tilassa funktiotctx.CompressTo(dst, src, level)jactx.DecompressInto(dst, src)suorittavat0 allocs/op-operaatioita.
Esikäsitellyt sanakirjat (CDict ja DDict) sijaitsevat C-taustaprosessissa sukupolvitarkistettujen 64-bittisten kahvojen takana (handle CDict, handle DDict tiedostossa zstd.idl). Sanakirjan luominen kerran funktion ctx.NewCDict(rawDict, level) kautta jäsentää sanakirjataulukot C-taustaprosessin sisällä ja palauttaa kevyen kahvan, jota voidaan käyttää uudelleen tuhansien kutsujen ajan ilman sanakirjatavujen lähettämistä uudelleen.
2. IPC-yleiskustannusten tasoittaminen massakehyksillä (zstd_bulk.go)
Suurille hyötykuormille (16 KiB ja yli) noin 200 nanoseunnin jaetun muistin edestakainen matka on mitätön verrattuna libzstd-kirjaston sisällä käytettyyn suoritinaikaan. Työkuormille, jotka pakkaavat tuhansia pieniä 100 tavun - 1 KiB:n viestejä kerralla, jopa 200 nanoseunnin maksaminen per kohde kuitenkin kasvaa merkittäväksi.
gosuda.org/zstd tarjoaa funktiot CompressBulk ja DecompressBulk rakenteelle BulkCtx (zstd_bulk.go) kohteena olevien edestakaisten matkojen poistamiseksi:
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 pakkaa koko [][]byte-erän yhdeksi pituusetuliitteellä varustetuksi pyyntökehykseksi jaetussa muistissa. C-taustaprosessi silmukoi jokaisen kohteen läpi C-kielellä (compress_bulk tiedostossa c/zstd_hooks.c), kirjoittaa kaikki pakatut kehykset peräkkäin vastauspaikkaan ja palauttaa koko erän yhdellä jaetun muistin edestakaisella matkalla.
3. Taustaprosessin päättymisestä selviäminen kaatamatta kutsujaa
Koska zstd_server toimii erillisessä käyttöjärjestelmän prosessissa, C-taustaprosessin vakava virhe ei koskaan kaada Go-sovellustasi:
- Jos
zstd_serverlopetetaan ulkoisesti (esimerkiksiSIGKILL-signaalilla tai muistin loppumisella eli OOM-tapahtumalla), HQQ-siirtokerros havaitsee katkenneen vertaisverkkoyhteyden välittömästi ja palauttaa tyypitetyn virheen*rt.TransportErrormeneillään olevastaCompress- taiDecompress-kutsusta. - Pakettitason funktiot (
zstd.Compress,zstd.Decompress,zstd.NewWriter,zstd.NewReader) havaitsevat automaattisesti, että jaettu oletustaustaprosessi on poissa, käynnistävät uuden varmennetunzstd_server-instanssin seuraavalla kutsulla ja jatkavat normaalia toimintaa.
Repositorion rakenne
Koodikanta erottaa suoraan käytettävän DataDog/zstd-julkisivun matalan tason hqq-bindgen-istunnosta ja massaprimitiiveistä:
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)
Aloittaminen
Asenna gosuda.org/zstd komennolla go get ja käytä sitä asetuksella CGO_ENABLED=0:
1go get gosuda.org/zstd@v0.3.10507
- GitHub-repositorio: https://github.com/gosuda/hqq-zstd
- Arkkitehtuuri ja suorituskykytestit: docs/ARCHITECTURE.md
- HQQ Core -ajuaikaympäristö: https://gosuda.org/hqq