---
id: e52d68870be3de9f644fcfc584bd8aec
author: Lemon Mint
title: 'gosuda.org/zstd: Drop-In-erstatning for DataDog/zstd med nul CGO og crash-isolering'
description: CGO_ENABLED=0 Go Zstandard-bibliotek, der kører upstream C libzstd 1.5.7 i en worker med delt hukommelse, med en DataDog/zstd-kompatibel API, genbrugelige kontekster og bulk-batching.
language: da
date: 2026-10-18T14:07:11.281986997Z
path: /zstd
go_package: gosuda.org/zstd
go_repourl: https://github.com/gosuda/hqq-zstd.git
category: lowlevel
---

`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](https://gosuda.org/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.

```bash
go 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:

1. **Byggeri- og udrulningsfriktion**: Ligesom `go-sqlite3` kræver `DataDog/zstd` `CGO_ENABLED=1` og en målrettet C-compilerværktøjskæde. Krydskompilering af tjenester eller opbygning af statiske binære filer til `linux/arm64` eller `windows/arm64` kræver eksterne C-sysroots.
2. **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.

```go
package main

import (
	"bytes"
	"fmt"
	"io"
	"log"

	"gosuda.org/zstd"
)

func main() {
	// 1. Engangs-Compress / Decompress (spejler github.com/DataDog/zstd)
	src := []byte("shared-memory zstd payload without cgo")
	compressed, err := zstd.CompressLevel(nil, src, zstd.BestSpeed)
	if err != nil {
		log.Fatal(err)
	}
	plain, err := zstd.Decompress(nil, compressed)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("one-shot: %d bytes -> %d bytes (%s)\n", len(src), len(compressed), plain)

	// 2. Streaming Writer og Reader med ordbogsunderstøttelse
	var buf bytes.Buffer
	w := zstd.NewWriterLevel(&buf, zstd.DefaultCompression)
	if _, err := w.Write(src); err != nil {
		log.Fatal(err)
	}
	if err := w.Close(); err != nil {
		log.Fatal(err)
	}

	r := zstd.NewReader(&buf)
	defer r.Close()
	streamed, err := io.ReadAll(r)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("streamed: %s\n", streamed)
}
```

### 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:

```text
Go-kaldende kode (zstd.Ctx)             Slot i delt hukommelse                C11-arbejder (zstd_hooks.c)
---------------------------             ----------------------                -------------------------
src []byte  ------------------------->  Nyttelast i anmodningsslot  ------------>  ZSTD_compressCCtx(
                                                                                    cctx, resp_slot, src, level)
dst []byte  <-------------------------  Nyttelast i svarslot  <-------------  Skriver den komprimerede ramme direkte
                                                                                  ind i den delte svarslot
```

1. Den genererede `hqq-bindgen`-klient kopierer `src` direkte ind i den hukommelsesmappede anmodningsslot og vender sekvensordet i `SeqLock`.
2. C-arbejderen læser `src` på stedet fra anmodningsslotten og sender svarslottens nyttelastpointer direkte som destinationsbuffer til `ZSTD_compressCCtx` eller `ZSTD_decompressDCtx`.
3. Go-klienten kopierer den resulterende slice fra svarslotten over i den af kalderen leverede `dst`-slice. I steady state udfører `ctx.CompressTo(dst, src, level)` og `ctx.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:

```go
bctx, err := client.NewBulkCtx(1 << 20)
if err != nil {
	log.Fatal(err)
}
defer bctx.Close()

items := [][]byte{
	[]byte(`{"event":"login","user":101}`),
	[]byte(`{"event":"purchase","user":101,"amount":4200}`),
	[]byte(`{"event":"logout","user":101}`),
}
compressedItems, 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_server` dræbes eksternt (for eksempel via `SIGKILL` eller en OOM-hændelse), registrerer HQQ-transportlaget den brudte modpart med det samme og returnerer en typet `*rt.TransportError` fra det igangværende `Compress`- eller `Decompress`-kald.
- Pakkeniveau-funktioner (`zstd.Compress`, `zstd.Decompress`, `zstd.NewWriter`, `zstd.NewReader`) registrerer automatisk, at den delte standardarbejder er væk, starter en ny verificeret `zstd_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`:

```text
gosuda.org/zstd
├── autolaunch.go / hashes.go  # Drop-in Compress/Decompress-API, pulje med automatisk genopretning og SHA-256-hashes
├── zstd_stream.go             # Streaming Writer/Reader (NewWriterLevelDict, NewReaderDict)
├── zstd_ctx.go                # Ctx, CDict og DDict uden allokeringer, indpakninger over hqq-bindgen
├── zstd_bulk.go               # Indramning af CompressBulk og DecompressBulk med én round trip
├── zstd.go                    # Genereret hqq-bindgen Go-klient for zstd IDL-tjenesten
├── zstd.idl                   # HQQ IDL-skema, der definerer Context, CDict, DDict og RPC-metoder
├── internal/embedded/         # Platformsmærkede //go:embed zstd_server-binære filer (6 OS/arkitektur-mål)
└── 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`:

```bash
go get gosuda.org/zstd@v0.3.10507
```

- **GitHub-repository**: [https://github.com/gosuda/hqq-zstd](https://github.com/gosuda/hqq-zstd)
- **Arkitektur og benchmarks**: [docs/ARCHITECTURE.md](https://github.com/gosuda/hqq-zstd/blob/main/docs/ARCHITECTURE.md)
- **HQQ Core Runtime**: [https://gosuda.org/hqq](https://gosuda.org/hqq)
