---
id: e52d68870be3de9f644fcfc584bd8aec
author: Lemon Mint
title: 'gosuda.org/zstd: Drop-In-erstatning for DataDog/zstd med null CGO og krasjisolering'
description: CGO_ENABLED=0 Go Zstandard-bibliotek som kjører upstream C libzstd 1.5.7 i en arbeider med delt minne, med et API kompatibelt med DataDog/zstd, gjenbrukbare kontekster og bulkbatching.
language: "no"
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 som kjører det offisielle C Zstandard-motoren (`libzstd 1.5.7`) i en isolert arbeidsprosess over [HQQ](https://gosuda.org/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.

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

1. **Friksjon ved bygging og utrulling**: Akkurat som `go-sqlite3` krever `DataDog/zstd` `CGO_ENABLED=1` og en måldrettet C-kompilatorverktøykjede. Krysskompilering av tjenester eller bygging av statiske binærfiler for `linux/arm64` eller `windows/arm64` krever eksterne C-sysroots.
2. **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.

```go
package main

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

	"gosuda.org/zstd"
)

func main() {
	// 1. Engangs-Compress / Decompress (speiler 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. Strømmende Writer og Reader med støtte for ordbøker
	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)
}
```

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

```text
Go-kaller (zstd.Ctx)                    Slot i delt minne                     C11-arbeider (zstd_hooks.c)
--------------------                    -----------------                     ---------------------------
src []byte  ------------------------->  Nyttelast i forespørselsslot  ------->  ZSTD_compressCCtx(
                                                                                cctx, resp_slot, src, level)
dst []byte  <-------------------------  Nyttelast i responsslot  <-------------  Skriver komprimert ramme direkte
                                                                              inn i delt responsslot
```

1. Den genererte `hqq-bindgen`-klienten kopierer `src` rett inn i den minnemappede forespørselsslotten og endrer `SeqLock`-sekvensordet.
2. C-arbeideren leser `src` på stedet fra forespørselsslotten og sender responsslotens nyttelastpeker direkte som målbuffer til `ZSTD_compressCCtx` eller `ZSTD_decompressDCtx`.
3. Go-klienten kopierer den resulterende slicen fra responsslotten inn i den av kalleren oppgitte `dst`-slicen. I stabil tilstand utfører `ctx.CompressTo(dst, src, level)` og `ctx.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:

```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 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_server` avsluttes eksternt (for eksempel via `SIGKILL` eller en OOM-hendelse), oppdager HQQ-transportlaget den brutte motparten umiddelbart og returnerer en typet `*rt.TransportError` fra det pågående `Compress`- eller `Decompress`-kallet.
- Pakkenivåfunksjoner (`zstd.Compress`, `zstd.Decompress`, `zstd.NewWriter`, `zstd.NewReader`) oppdager automatisk at den delte standardarbeideren er borte, starter en ny verifisert `zstd_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`:

```text
gosuda.org/zstd
├── autolaunch.go / hashes.go  # Drop-in Compress/Decompress-API, pool for automatisk gjenoppretting og SHA-256-hasher
├── zstd_stream.go             # Strømmende Writer/Reader (NewWriterLevelDict, NewReaderDict)
├── zstd_ctx.go                # Allokeringsfrie Ctx-, CDict- og DDict-omslag over hqq-bindgen
├── zstd_bulk.go               # Innramming for CompressBulk og DecompressBulk med én enkelt rundtur
├── zstd.go                    # Generert hqq-bindgen Go-klient for zstd IDL-tjenesten
├── zstd.idl                   # HQQ IDL-skjema som definerer Context, CDict, DDict og RPC-metoder
├── internal/embedded/         # Plattformmerkede //go:embed zstd_server-binærfiler (6 OS/arkitektur-mål)
└── 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`:

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

- **GitHub-repositorium**: [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)
