---
id: e52d68870be3de9f644fcfc584bd8aec
author: Lemon Mint
title: 'gosuda.org/zstd: Drop-In DataDog/zstd tömörítés nulla CGO-val és összeomlás-elkülönítéssel'
description: CGO_ENABLED=0 Go Zstandard könyvtár, amely megosztott memóriás munkavégzőben futtatja az upstream C libzstd 1.5.7 verziót, DataDog/zstd-kompatibilis API-val, újrahasznosítható kontextusokkal és kötegelt (bulk) feldolgozással.
language: hu
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` egy `CGO_ENABLED=0` Go tömörítőkönyvtár, amely a hivatalos C Zstandard (`libzstd 1.5.7`) motort egy izolált worker folyamatban futtatja, [HQQ](https://gosuda.org/hqq) megosztott memórián keresztül. A `github.com/DataDog/zstd` csomaghoz drop-in helyettesítő API-t biztosít (beleértve az egyszeri `Compress`/`Decompress` függvényeket, a streaming `io.Writer`/`io.Reader` típusokat, az előre feldolgozott szótárakat és az újrafelhasználható, nulla allokációs kontextusokat), miközben a C végrehajtás teljes egészében a Go futtatókörnyezet címtartományán kívül marad.

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

## Miért tartozik a dekompresszió a Go heapen kívülre

Éles backend rendszerekben a tömörítés és a kicsomagolás közvetlenül a nem megbízható bemeneti határon történik. A naplógyűjtők, üzenetközvetítők, RPC-átjárók és tárolómotorok percenként gigabájtnyi külsőleg megadott keretet bontanak ki.

Sok Go csapat a `github.com/DataDog/zstd` csomagot választja, mert közvetlenül a felső szintű C `libzstd` könyvtárhoz kapcsolódik: a C implementáció nagy egymagos átviteli sebességet, szoros szótáras tömörítési arányt kis rekordokon, valamint heapen kívüli C memóriaterületeket (`ZSTD_CCtx` és `ZSTD_DCtx`) biztosít, amelyek nem növelik a Go szemétgyűjtés bejárási idejét.

A `libzstd` `cgo` segítségével történő Go szolgáltatásba integrálása azonban két üzemeltetési problémát okoz:

1. **Build- és telepítési súrlódás**: A `go-sqlite3`-hoz hasonlóan a `DataDog/zstd` is megköveteli a `CGO_ENABLED=1` beállítást és a céloldali C fordítóeszköztárat. A szolgáltatások keresztfordítása vagy statikus bináris fájlok építése `linux/arm64` vagy `windows/arm64` célra külső C sysroot-okat igényel.
2. **Közös címtartomány nem megbízható bemeneteken**: A sérült vagy ellenséges adatok kicsomagolása ugyanabban a virtuális címtartományban, mint a Go szerver, azt jelenti, hogy a natív C kód vagy az egyéni szótárkezelés bármely hibája leállíthatja a teljes Go folyamatot.

A `gosuda.org/zstd` megtartja a pontosan azonos upstream C `libzstd 1.5.7` motort és az ismerős `github.com/DataDog/zstd` API-t, de a C végrehajtást egy ellenőrzött gyermekfolyamatba (`zstd_server`) helyezi, amely a Go programhoz cache-line méretű megosztott memórián keresztül kapcsolódik.

## Drop-in csere a `github.com/DataDog/zstd` csomagra

A `github.com/DataDog/zstd` csomagról történő áttéréshez csak az importútvonalat kell `"gosuda.org/zstd"` értékre cserélni. Nincs szükség külső bináris telepítésre vagy beállító kódra: az első hívásnál a `gosuda.org/zstd` kibont egy beágyazott, SLSA-attesztált `zstd_server` binárist az adott platformra, ellenőrzi annak SHA-256 digesztjét a `gosuda.org/hqq/secureexec` segítségével, majd megnyit egy megosztott memóriás munkamenet-készletet.

```go
package main

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

	"gosuda.org/zstd"
)

func main() {
	// 1. Egyszeri Compress / Decompress hívások (a github.com/DataDog/zstd API-t tükrözi)
	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 és Reader szótártámogatással
	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)
}
```

### Támogatott platformok és beágyazott bináris fájlok

Mind a hat célplatform előre lefordított, SHA-256 digesztjével rögzített worker binárisokat tartalmaz, amelyek platformspecifikus build tageken keresztül vannak beágyazva (`internal/embedded/embed_<goos>_<goarch>.go`):

| Céloperációs rendszer | Célarchitektúra (`GOARCH`) | Beágyazott bináris fájl         |    Bináris méret | Build-eszköztár és eredet                         |
| :--------------------- | :------------------------- | :------------------------------ | ---------------: | :------------------------------------------------ |
| **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 |

## Megosztott memórián belüli adatút

Ahhoz, hogy az átviteli sebesség versenyképes maradjon a folyamatba ágyazott `cgo` megoldással szemben, a `gosuda.org/zstd` elkerüli a socket-alapú szerializációt és a heap-allokációkat a kritikus úton.

### 1. Nulla allokációs slot-kódolás (`zstd_ctx.go` és `c/zstd_hooks.c`)

Amikor újrafelhasználható `zstd.Ctx` objektumot használ (vagy amikor a csomagszintű `Compress` és `Decompress` függvények egy `Ctx` objektumot kölcsönöznek a belső munkamenet-készletből), az adatok közvetlenül a leképezett `StandardLink` slotokon keresztül áramlanak:

```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. A generált `hqq-bindgen` kliens a `src` adatot közvetlenül a memórián leképezett kérési slotba másolja, és megfordítja a `SeqLock` sorszámszót.
2. A C worker a `src` adatot helyben olvassa a kérési slotból, és a válasz slot payload mutatóját közvetlenül célpufferként adja át a `ZSTD_compressCCtx` vagy a `ZSTD_decompressDCtx` függvénynek.
3. A Go kliens az eredményül kapott szeletet a válasz slotból a hívó által megadott `dst` szeletbe másolja. Állandósult állapotban a `ctx.CompressTo(dst, src, level)` és a `ctx.DecompressInto(dst, src)` `0 allocs/op` teljesítményt nyújt.

Az előre feldolgozott szótárak (`CDict` és `DDict`) a C workeren élnek, generáció-ellenőrzött 64 bites handle-ök mögött (`handle CDict`, `handle DDict` a `zstd.idl` fájlban). Egyszer létrehozva a szótárat a `ctx.NewCDict(rawDict, level)` hívással, a szótártáblák a C workeren kerülnek feldolgozásra, és egy könnyű handle-t kap vissza, amely a szótár bájtjainak újraküldése nélkül többezer hívás során újrafelhasználható.

### 2. Az IPC-költség amortizálása kötegelt keretezéssel (`zstd_bulk.go`)

Nagy adatmennyiségek (16 KiB és afölött) esetén a körülbelül 200 ns-os megosztott memórián belüli körforgási idő elhanyagolható a `libzstd` belsejében töltött CPU-időhöz képest. Azonban olyan munkaterhelések esetén, amelyek egyszerre több ezer kis, 100 bájttól 1 KiB-ig terjedő üzenetet tömörítenek, elemenként akár 200 ns-os költség is összeadódik.

A `gosuda.org/zstd` a `BulkCtx` típuson (`zstd_bulk.go`) keresztül biztosítja a `CompressBulk` és a `DecompressBulk` függvényeket, amelyek kiküszöbölik az elemenkénti körforgási időket:

```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)
```

A `CompressBulk` a teljes `[][]byte` köteget egyetlen, hosszúság-előtagos kérési keretbe csomagolja a megosztott memóriában. A C worker C nyelven iterál minden elemen (`compress_bulk` a `c/zstd_hooks.c` fájlban), a tömörített kereteket folytonosan írja a válasz slotba, és a teljes köteget egyetlen megosztott memórián belüli körforgással adja vissza.

### 3. A worker leállásának túlélése a hívó összeomlása nélkül

Mivel a `zstd_server` külön operációs rendszer-folyamatban fut, a C workeren belüli végzetes hiba soha nem állítja le a Go alkalmazást:

- Ha a `zstd_server` külső beavatkozás miatt leáll (például `SIGKILL` jelzés vagy OOM esemény következtében), a HQQ szállítási réteg azonnal észleli a megszakadt partnert, és egy típusos `*rt.TransportError` hibát ad vissza a folyamatban lévő `Compress` vagy `Decompress` hívásból.
- A csomagszintű függvények (`zstd.Compress`, `zstd.Decompress`, `zstd.NewWriter`, `zstd.NewReader`) automatikusan észlelik, hogy a megosztott alapértelmezett worker megszűnt, a következő hívásnál új, ellenőrzött `zstd_server` példányt indítanak, és visszaáll a normál működés.

## Tárolóstruktúra

A kódbázis elválasztja a `DataDog/zstd` drop-in homlokzatot az alacsony szintű `hqq-bindgen` munkamenet- és kötegelt primitívektől:

```text
gosuda.org/zstd
├── autolaunch.go / hashes.go  # Drop-in Compress/Decompress API, automatikus helyreállítási készlet és SHA-256 hash-ek
├── zstd_stream.go             # Streaming Writer/Reader (NewWriterLevelDict, NewReaderDict)
├── zstd_ctx.go                # Nulla allokációs Ctx, CDict és DDict burkolók a hqq-bindgen felett
├── zstd_bulk.go               # Egyetlen körforgású CompressBulk és DecompressBulk keretezés
├── zstd.go                    # A zstd IDL szolgáltatáshoz generált hqq-bindgen Go kliens
├── zstd.idl                   # HQQ IDL séma, amely a Context, CDict, DDict és RPC metódusokat definiálja
├── internal/embedded/         # Platformcímkézett //go:embed zstd_server binárisok (6 OS/architektúra célplatform)
└── c/                         # C11 szerverimplementáció (zstd_server.c, zstd_hooks.c, main.c)
```

## Első lépések

Telepítse a `gosuda.org/zstd` csomagot a `go get` paranccsal, és használja `CGO_ENABLED=0` mellett:

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

- **GitHub-tároló**: [https://github.com/gosuda/hqq-zstd](https://github.com/gosuda/hqq-zstd)
- **Architektúra és benchmarkok**: [docs/ARCHITECTURE.md](https://github.com/gosuda/hqq-zstd/blob/main/docs/ARCHITECTURE.md)
- **HQQ alapvető futtatókörnyezet**: [https://gosuda.org/hqq](https://gosuda.org/hqq)
