---
id: e52d68870be3de9f644fcfc584bd8aec
author: Lemon Mint
title: 'gosuda.org/zstd: Drop-In-ersättning för DataDog/zstd-komprimering utan CGO och med krasch-isolering'
description: CGO_ENABLED=0 Go Zstandard-bibliotek som kör uppströms C-biblioteket libzstd 1.5.7 i en arbetsprocess med delat minne, med ett DataDog/zstd-kompatibelt API, återanvändbara kontexter och batchbearbetning i bulk.
language: sv
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` är ett Go-kompressionsbibliotek med `CGO_ENABLED=0` som kör den officiella C-implementationen av Zstandard (`libzstd 1.5.7`) i en isolerad arbetsprocess över [HQQ](https://gosuda.org/hqq)-delat minne. Det tillhandahåller ett drop-in-ersättande API för `github.com/DataDog/zstd` (inklusive engångs-`Compress`/`Decompress`, strömmande `io.Writer`/`io.Reader`, förberedda ordböcker och återanvändbara kontexter utan allokeringar) samtidigt som C-exekveringen hålls helt utanför Go-runtimens adressutrymme.

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

## Varför dekompression hör hemma utanför din Go-heap

I produktionsbackends befinner sig komprimering och dekompression direkt på gränsen till opålitlig indata. Loggsamlare, meddelandemäklare, RPC-gatewayer och lagringsmotorer dekomprimerar gigabyte med externt tillhandahållna ramar varje minut.

Många Go-team väljer `github.com/DataDog/zstd` eftersom det binder direkt mot uppströms C-biblioteket `libzstd`: C-implementationen levererar hög genomströmning per kärna, täta komprimeringsförhållanden med ordböcker för små poster samt off-heap C-arenor (`ZSTD_CCtx` och `ZSTD_DCtx`) som inte ökar tiden för skräpinsamlingens genomsökning av Go-heapen.

Att länka `libzstd` till en Go-tjänst via `cgo` medför dock två driftsmässiga problem:

1. **Friktion vid bygge och driftsättning**: Precis som `go-sqlite3` kräver `DataDog/zstd` `CGO_ENABLED=1` och en C-kompilatorverktygskedja för målplattformen. Korskompilering av tjänster eller byggande av statiska binärer för `linux/arm64` eller `windows/arm64` kräver externa C-sysroots.
2. **Delat adressutrymme vid opålitliga indata**: Dekomprimering av skadade eller angripande nyttolaster inuti samma virtuella adressutrymme som din Go-server innebär att varje fel i native C-kod eller i hantering av egna ordböcker kan avsluta hela Go-processen.

`gosuda.org/zstd` behåller den exakta uppströms C-implementationen `libzstd 1.5.7` och det välbekanta API:et från `github.com/DataDog/zstd`, men flyttar C-exekveringen till en verifierad barnprocess (`zstd_server`) som är ansluten till ditt Go-program via delat minne anpassat till cacheradens storlek.

## Drop-in-ersättning för `github.com/DataDog/zstd`

Migrering från `github.com/DataDog/zstd` kräver att endast importsökvägen ändras till `"gosuda.org/zstd"`. Ingen extern binär installation eller konfigurationskod behövs: vid första anropet materialiserar `gosuda.org/zstd` en inbäddad SLSA-attesterad `zstd_server`-binär för din plattform, verifierar dess SHA-256-digest via `gosuda.org/hqq/secureexec` och öppnar en pool av delade minnessessioner.

```go
package main

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

	"gosuda.org/zstd"
)

func main() {
	// 1. One-shot Compress / Decompress (speglar 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)
}
```

### Stödda plattformar och inbäddade binärer

Alla sex målplattformar levereras med förbyggda worker-binärer med SHA-256-fästning, inbäddade via plattformsspecifika build-taggar (`internal/embedded/embed_<goos>_<goarch>.go`):

| Målets OS   | Målarkitektur (`GOARCH`) | Inbäddad binär                  |   Binärstorlek | Byggverktygskedja & 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 |

## Inuti datavägen för delat minne

För att hålla genomströmningen konkurrenskraftig med in-process `cgo` undviker `gosuda.org/zstd` socketserialisering och heapallokeringar på den kritiska vägen.

### 1. Kodning av slots utan allokeringar (`zstd_ctx.go` och `c/zstd_hooks.c`)

När du använder en återanvändbar `zstd.Ctx` (eller när paketnivåfunktionerna `Compress` och `Decompress` lånar en `Ctx` från den interna sessionspoolen) flödar data direkt genom den mappade `StandardLink`-slotten:

```text
Go-anropare (zstd.Ctx)                  Delad minnesslot                      C11-worker (zstd_hooks.c)
--------------------                    ------------------                    -------------------------
src []byte  ------------------------->  Nyttolast i förfrågningsslot  ------->  ZSTD_compressCCtx(
                                                                                cctx, resp_slot, src, level)
dst []byte  <-------------------------  Nyttolast i svarsslot <-------------  Skriver den komprimerade ramen direkt
                                                                              till den delade svarsslotten
```

1. Den genererade `hqq-bindgen`-klienten kopierar `src` direkt till den minnesmappade förfrågningsslotten och vänder sekvensordet i `SeqLock`.
2. C-workern läser `src` på plats från förfrågningsslotten och skickar svarsslottens nyttolastpekare direkt som destinationsbuffert till `ZSTD_compressCCtx` eller `ZSTD_decompressDCtx`.
3. Go-klienten kopierar den resulterande slicen från svarsslotten till den av anroparen angivna `dst`-slicen. I stationärt läge utför `ctx.CompressTo(dst, src, level)` och `ctx.DecompressInto(dst, src)` `0 allocs/op`.

Förberedda ordböcker (`CDict` och `DDict`) lever i C-workern bakom generationskontrollerade 64-bitars handtag (`handle CDict`, `handle DDict` i `zstd.idl`). Att skapa en ordbok en gång via `ctx.NewCDict(rawDict, level)` tolkar ordbokens tabeller inuti C-workern och returnerar ett lättviktigt handtag som kan återanvändas över tusentals anrop utan att ordbokens byte skickas på nytt.

### 2. Amortering av IPC-overhead med bulkramning (`zstd_bulk.go`)

För stora nyttolaster (16 KiB och större) är den cirka 200 ns långa rundresan via delat minne försumbar jämfört med CPU-tiden som går åt inuti `libzstd`. För arbetslaster som komprimerar tusentals små meddelanden om 100 byte till 1 KiB samtidigt blir dock även 200 ns per post betydande.

`gosuda.org/zstd` tillhandahåller `CompressBulk` och `DecompressBulk` på `BulkCtx` (`zstd_bulk.go`) för att eliminera rundresor per post:

```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` packar hela `[][]byte`-batchen i en enda längdprefixerad förfrågningsram i delat minne. C-workern loopar över varje post i C (`compress_bulk` i `c/zstd_hooks.c`), skriver alla komprimerade ramar sammanhängande till svarsslotten och returnerar hela batchen i en enda rundresa via delat minne.

### 3. Att överleva avslutad worker utan att krascha anroparen

Eftersom `zstd_server` körs i en separat OS-process kan ett fatalt fel inuti C-workern aldrig fälla ned ditt Go-program:

- Om `zstd_server` dödas externt (till exempel genom `SIGKILL` eller en OOM-händelse) upptäcker HQQ-transportlagret den brutna motparten omedelbart och returnerar en typad `*rt.TransportError` från det pågående `Compress`- eller `Decompress`-anropet.
- Paketnivåfunktioner (`zstd.Compress`, `zstd.Decompress`, `zstd.NewWriter`, `zstd.NewReader`) upptäcker automatiskt att den delade standardworkern är borta, startar en ny verifierad `zstd_server`-instans vid nästa anrop och återupptar normal drift.

## Förvarets struktur

Kodbasen separerar drop-in-fasaden `DataDog/zstd` från de lågnivåprimitiver för session och bulk som tillhandahålls av `hqq-bindgen`:

```text
gosuda.org/zstd
├── autolaunch.go / hashes.go  # Drop-in Compress/Decompress-API, pool med automatisk återhämtning och SHA-256-hashar
├── zstd_stream.go             # Strömmande Writer/Reader (NewWriterLevelDict, NewReaderDict)
├── zstd_ctx.go                # Ctx utan allokeringar, samt CDict- och DDict-omslag över hqq-bindgen
├── zstd_bulk.go               # Bulkramning med en enda rundresa för CompressBulk och DecompressBulk
├── zstd.go                    # Genererad hqq-bindgen Go-klient för zstd IDL-tjänsten
├── zstd.idl                   # HQQ IDL-schema som definierar Context, CDict, DDict och RPC-metoder
├── internal/embedded/         # Plattformstaggade //go:embed zstd_server-binärer (6 OS/arkitekturmål)
└── c/                         # C11-serverimplementation (zstd_server.c, zstd_hooks.c, main.c)
```

## Komma igång

Installera `gosuda.org/zstd` med `go get` och använd det med `CGO_ENABLED=0`:

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

- **GitHub-förvar**: [https://github.com/gosuda/hqq-zstd](https://github.com/gosuda/hqq-zstd)
- **Arkitektur och 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)
