---
id: e52d68870be3de9f644fcfc584bd8aec
author: Lemon Mint
title: 'gosuda.org/zstd: Drop-In DataDog/zstd-compressie zonder CGO en met crashisolatie'
description: CGO_ENABLED=0 Go-bibliotheek voor Zstandard die de upstream C-bibliotheek libzstd 1.5.7 uitvoert in een worker met gedeeld geheugen, met een API die compatibel is met DataDog/zstd, herbruikbare contexten en bulkbatchverwerking.
language: nl
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` is een `CGO_ENABLED=0` Go-compressiebibliotheek die de officiële C Zstandard-engine (`libzstd 1.5.7`) uitvoert binnen een geïsoleerd workerproces via gedeeld geheugen van [HQQ](https://gosuda.org/hqq). Het biedt een drop-in vervangende API voor `github.com/DataDog/zstd` (inclusief eenmalige `Compress`/`Decompress`, streaming `io.Writer`/`io.Reader`, vooraf verwerkte woordenboeken en herbruikbare contexten zonder allocaties), terwijl de C-uitvoering volledig buiten de adresruimte van de Go-runtime blijft.

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

## Waarom decompressie buiten je Go-heap hoort

In productiebackends bevinden compressie en decompressie zich direct op de grens met onbetrouwbare invoer. Log-collectors, berichtenbrokers, RPC-gateways en opslagengines decomprimeren elke minuut gigabytes aan extern aangeleverde frames.

Veel Go-teams kiezen voor `github.com/DataDog/zstd` omdat het rechtstreeks koppelt aan de upstream C-bibliotheek `libzstd`: de C-implementatie levert een hoge doorvoer per core, sterke dictionary-compressieratio's op kleine records, en off-heap C-arena's (`ZSTD_CCtx` en `ZSTD_DCtx`) die de scantijd van de Go-garbagecollector niet verhogen.

Het koppelen van `libzstd` aan een Go-service via `cgo` brengt echter twee operationele knelpunten met zich mee:

1. **Frictie bij build en deployment**: Net als `go-sqlite3` vereist `DataDog/zstd` `CGO_ENABLED=1` en een doel-C-compilertoolchain. Cross-compilatie van services of het bouwen van statische binaries voor `linux/arm64` of `windows/arm64` vereist externe C-sysroots.
2. **Gedeelde adresruimte bij onbetrouwbare invoer**: Het decomprimeren van beschadigde of kwaadwillige payloads binnen dezelfde virtuele adresruimte als je Go-server betekent dat elke bug in native C-code of in de afhandeling van aangepaste woordenboeken het volledige Go-proces kan doen eindigen.

`gosuda.org/zstd` behoudt de exacte upstream C-engine `libzstd 1.5.7` en de vertrouwde API van `github.com/DataDog/zstd`, maar verplaatst de C-uitvoering naar een geverifieerd childproces (`zstd_server`) dat via cache-line-gedeeld geheugen verbonden is met je Go-programma.

## Drop-in vervanging voor `github.com/DataDog/zstd`

Migreren vanuit `github.com/DataDog/zstd` vereist alleen het wijzigen van het importpad naar `"gosuda.org/zstd"`. Er is geen externe binaire installatie of installatiecode nodig: bij de eerste aanroep materialiseert `gosuda.org/zstd` een ingebedde SLSA-geattesteerde `zstd_server`-binary voor jouw platform, verifieert de SHA-256-digest ervan via `gosuda.org/hqq/secureexec`, en opent een pool van gedeelde-geheugensessies.

```go
package main

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

	"gosuda.org/zstd"
)

func main() {
	// 1. One-shot Compress / Decompress (mirrors 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 and Reader with Dictionary Support
	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)
}
```

### Ondersteunde platformen en ingebedde binaries

Alle zes doelplatformen worden geleverd met vooraf gebouwde, op SHA-256 vastgepinde workerbinaries, ingebed via platformspecifieke build-tags (`internal/embedded/embed_<goos>_<goarch>.go`):

| Doel-OS     | Doel-architectuur (`GOARCH`) | Ingebedde binary                |   Binarygrootte | Buildtoolchain en herkomst                        |
| :---------- | :--------------------------- | :------------------------------ | --------------: | :------------------------------------------------ |
| **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 |

## Binnenin het gedeeld-geheugen-datapad

Om de doorvoer concurrerend te houden met in-process `cgo`, vermijdt `gosuda.org/zstd` socketserialisatie en heap-allocaties op het hot path.

### 1. Codering in slots zonder allocaties (`zstd_ctx.go` en `c/zstd_hooks.c`)

Wanneer je een herbruikbare `zstd.Ctx` gebruikt (of wanneer de pakketniveau-functies `Compress` en `Decompress` een `Ctx` lenen uit de interne sessiepool), stroomt data rechtstreeks via de gemapte `StandardLink`-slot:

```text
Go Caller (zstd.Ctx)                    Shared-Memory Slot                    C11 Worker (zstd_hooks.c)
--------------------                    ------------------                    -------------------------
src []byte  ------------------------->  Request Slot Payload  ------------->  ZSTD_compressCCtx(
                                                                                cctx, resp_slot, src, level)
dst []byte  <-------------------------  Response Slot Payload <-------------  Writes compressed frame directly
                                                                              into shared response slot
```

1. De gegenereerde `hqq-bindgen`-client kopieert `src` rechtstreeks naar de geheugengemapte requestslot en wisselt het `SeqLock`-sequentiewoord om.
2. De C-worker leest `src` ter plaatse uit de requestslot en geeft de payloadpointer van de responseslot rechtstreeks door als doelbuffer aan `ZSTD_compressCCtx` of `ZSTD_decompressDCtx`.
3. De Go-client kopieert het resulterende slice uit de responseslot naar het door de aanroeper aangeleverde `dst`-slice. In de steady state voeren `ctx.CompressTo(dst, src, level)` en `ctx.DecompressInto(dst, src)` `0 allocs/op` uit.

Vooraf verwerkte woordenboeken (`CDict` en `DDict`) leven op de C-worker achter generatiegecontroleerde 64-bits handles (`handle CDict`, `handle DDict` in `zstd.idl`). Het eenmalig aanmaken van een woordenboek via `ctx.NewCDict(rawDict, level)` parseert de woordenboektabellen binnen de C-worker en retourneert een lichtgewicht handle die over duizenden aanroepen kan worden hergebruikt zonder de woordenboekbytes opnieuw te verzenden.

### 2. IPC-overhead amortiseren met bulk-framing (`zstd_bulk.go`)

Voor grote payloads (16 KiB en groter) is de ~200 ns durende round trip via gedeeld geheugen verwaarloosbaar ten opzichte van de CPU-tijd die binnen `libzstd` wordt besteed. Voor workloads die duizenden kleine berichten van 100 bytes tot 1 KiB in één keer comprimeren, telt het betalen van zelfs 200 ns per item echter op.

`gosuda.org/zstd` biedt `CompressBulk` en `DecompressBulk` op `BulkCtx` (`zstd_bulk.go`) om round trips per item te elimineren:

```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` verpakt de volledige `[][]byte`-batch in één frame met lengteprefixen in het gedeelde geheugen. De C-worker doorloopt elk item in C (`compress_bulk` in `c/zstd_hooks.c`), schrijft alle gecomprimeerde frames aaneengesloten naar de responseslot en retourneert de volledige batch in één enkele round trip via gedeeld geheugen.

### 3. Overleven van workerbeëindiging zonder de aanroeper te laten crashen

Omdat `zstd_server` in een afzonderlijk OS-proces draait, brengt een fatale fout in de C-worker nooit je Go-applicatie tot stilstand:

- Als `zstd_server` extern wordt beëindigd (bijvoorbeeld door `SIGKILL` of een OOM-gebeurtenis), detecteert de HQQ-transportlaag de verbroken peer onmiddellijk en retourneert een getypeerde `*rt.TransportError` uit de lopende `Compress`- of `Decompress`-aanroep.
- Pakketniveau-functies (`zstd.Compress`, `zstd.Decompress`, `zstd.NewWriter`, `zstd.NewReader`) detecteren automatisch dat de gedeelde standaardworker verdwenen is, starten bij de volgende aanroep een nieuwe geverifieerde `zstd_server`-instantie en hervatten de normale werking.

## Repositorystructuur

De codebase scheidt de drop-in `DataDog/zstd`-facade van de laagniveau-primitieven voor `hqq-bindgen`-sessies en bulkverwerking:

```text
gosuda.org/zstd
├── autolaunch.go / hashes.go  # Drop-in Compress/Decompress API, auto-recovery pool, and SHA-256 hashes
├── zstd_stream.go             # Streaming Writer/Reader (NewWriterLevelDict, NewReaderDict)
├── zstd_ctx.go                # Zero-allocation Ctx, CDict, and DDict wrappers over hqq-bindgen
├── zstd_bulk.go               # Single-round-trip CompressBulk and DecompressBulk framing
├── zstd.go                    # Generated hqq-bindgen Go client for the zstd IDL service
├── zstd.idl                   # HQQ IDL schema defining Context, CDict, DDict, and RPC methods
├── internal/embedded/         # Platform-tagged //go:embed zstd_server binaries (6 OS/Arch targets)
└── c/                         # C11 server implementation (zstd_server.c, zstd_hooks.c, main.c)
```

## Aan de slag

Installeer `gosuda.org/zstd` met `go get` en gebruik het met `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)
- **Architectuur en 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)
