---
id: e52d68870be3de9f644fcfc584bd8aec
author: Lemon Mint
title: 'gosuda.org/zstd: Drop-In náhrada DataDog/zstd s kompresí bez CGO a izolací pádů'
description: CGO_ENABLED=0 Go knihovna Zstandard spouštějící upstream C knihovnu libzstd 1.5.7 v pracovním procesu se sdílenou pamětí, s API kompatibilním s DataDog/zstd, opakovaně použitelnými kontexty a dávkovým zpracováním.
language: cs
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` je knihovna pro kompresi v Go s `CGO_ENABLED=0`, která spouští oficiální C engine Zstandard (`libzstd 1.5.7`) uvnitř izolovaného pracovního procesu přes sdílenou paměť [HQQ](https://gosuda.org/hqq). Poskytuje API jako náhradu za `github.com/DataDog/zstd` (včetně jednorázových `Compress`/`Decompress`, streamovacích `io.Writer`/`io.Reader`, předem zpracovaných slovníků a znovupoužitelných kontextů s nulovou alokací), přičemž provádění C kódu zůstává zcela mimo adresní prostor běhového prostředí Go.

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

## Proč by dekomprese měla probíhat mimo haldu Go

V produkčních backendech se komprese a dekomprese nacházejí přímo na hranici nedůvěryhodného vstupu. Sběrače logů, message brokery, RPC brány a úložné enginy dekomprimují každou minutu gigabajty externě dodaných rámců.

Mnoho týmů v Go volí `github.com/DataDog/zstd`, protože se váže přímo na upstream C `libzstd`: C implementace poskytuje vysokou propustnost na jednom jádře, těsné poměry komprese se slovníkem u malých záznamů a off-heap C arény (`ZSTD_CCtx` a `ZSTD_DCtx`), které nezvyšují dobu prohledávání paměti garbage collectorem v Go.

Propojení `libzstd` s Go službou přes `cgo` však přináší dva provozní problémy:

1. **Obtíže při sestavení a nasazení**: Stejně jako `go-sqlite3` vyžaduje `DataDog/zstd` `CGO_ENABLED=1` a cílový toolchain C kompilátoru. Křížová kompilace služeb nebo sestavení statických binárních souborů pro `linux/arm64` či `windows/arm64` vyžaduje externí C sysroot.
2. **Sdílený adresní prostor při nedůvěryhodných vstupech**: Dekomprese poškozených nebo protivníkových datových částí ve stejném virtuálním adresním prostoru jako váš Go server znamená, že jakákoli chyba v nativním C kódu nebo ve vlastní práci se slovníky může ukončit celý proces Go.

`gosuda.org/zstd` zachovává přesný upstream C engine `libzstd 1.5.7` a známé API `github.com/DataDog/zstd`, ale přesouvá provádění C kódu do ověřeného child procesu (`zstd_server`), který je s vaším Go programem propojen přes sdílenou paměť zarovnanou na cache line.

## Náhrada za `github.com/DataDog/zstd` bez úprav kódu

Migrace z `github.com/DataDog/zstd` vyžaduje změnit pouze importní cestu na `"gosuda.org/zstd"`. Není potřeba instalovat žádný externí binární soubor ani provádět nastavení: při prvním volání `gosuda.org/zstd` vytvoří z vestavěného binárního souboru `zstd_server` s attestací SLSA pro vaši platformu, ověří jeho digest SHA-256 pomocí `gosuda.org/hqq/secureexec` a otevře fond relací se sdílenou pamětí.

```go
package main

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

	"gosuda.org/zstd"
)

func main() {
	// 1. Jednorázové Compress / Decompress (kopíruje 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. Streamovací Writer a Reader s podporou slovníků
	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)
}
```

### Podporované platformy a vestavěné binární soubory

Všech šest cílových platforem obsahuje předkompilované pracovní binární soubory s pevným SHA-256, vestavěné pomocí specifických build tagů pro platformu (`internal/embedded/embed_<goos>_<goarch>.go`):

| Cílový OS   | Cílová architektura (`GOARCH`) | Vestavěný binární soubor        |  Velikost binárního souboru | Build toolchain a provenience                     |
| :---------- | :----------------------------- | :------------------------------ | --------------------------: | :------------------------------------------------ |
| **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 |

## Uvnitř datové cesty se sdílenou pamětí

Aby `gosuda.org/zstd` udržel propustnost konkurenceschopnou vůči procesu `cgo` běžícímu v rámci stejného procesu, vyhýbá se serializaci přes sockety a alokacím na heapu v kritické cestě.

### 1. Kódování slotů bez alokací (`zstd_ctx.go` a `c/zstd_hooks.c`)

Při použití znovupoužitelného `zstd.Ctx` (nebo když funkce na úrovni balíčku `Compress` a `Decompress` vypůjčí `Ctx` z interního fondu relací) data proudí přímo přes namapovaný slot `StandardLink`:

```text
Go volající (zstd.Ctx)                  Slot sdílené paměti                   C11 worker (zstd_hooks.c)
--------------------                    -------------------                   -------------------------
src []byte  ------------------------->  Payload požadavkového slotu  ------->  ZSTD_compressCCtx(
                                                                                cctx, resp_slot, src, level)
dst []byte  <-------------------------  Payload odpovědního slotu  <---------  Zapisuje komprimovaný rámec přímo
                                                                              do sdíleného odpovědního slotu
```

1. Generovaný klient `hqq-bindgen` zkopíruje `src` přímo do namapovaného požadavkového slotu a přepne sekvenční slovo `SeqLock`.
2. C worker čte `src` na místě z požadavkového slotu a předává ukazatel na payload odpovědního slotu přímo jako cílový buffer do `ZSTD_compressCCtx` nebo `ZSTD_decompressDCtx`.
3. Go klient zkopíruje výsledný slice z odpovědního slotu do volajícím poskytnutého slice `dst`. V ustáleném stavu `ctx.CompressTo(dst, src, level)` a `ctx.DecompressInto(dst, src)` provádějí `0 allocs/op`.

Předem zpracované slovníky (`CDict` a `DDict`) žijí v C workeru za 64bitovými handly s kontrolou generace (`handle CDict`, `handle DDict` v `zstd.idl`). Jednorázové vytvoření slovníku pomocí `ctx.NewCDict(rawDict, level)` naparsuje tabulky slovníku uvnitř C workeru a vrátí lehký handle, který lze znovu použít v tisících volání bez opětovného odesílání bajtů slovníku.

### 2. Amortizace režie IPC pomocí hromadného rámování (`zstd_bulk.go`)

U velkých datových částí (16 KiB a více) je round trip sdílené paměti přibližně 200 ns zanedbatelný oproti času CPU strávenému uvnitř `libzstd`. U úloh, které komprimují tisíce malých zpráv o velikosti 100 bajtů až 1 KiB najednou, však i 200 ns na položku se sčítá.

`gosuda.org/zstd` poskytuje `CompressBulk` a `DecompressBulk` na `BulkCtx` (`zstd_bulk.go`), aby odstranil round trip pro každou položku:

```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` zabalí celou dávku `[][]byte` do jediného rámce požadavku s předponou délky ve sdílené paměti. C worker prochází každou položku v C (`compress_bulk` v `c/zstd_hooks.c`), zapisuje všechny komprimované rámce souvisle do odpovědního slotu a vrací celou dávku v jediném round tripu sdílené paměti.

### 3. Přežití ukončení workeru bez pádu volajícího

Protože `zstd_server` běží v samostatném procesu operačního systému, fatální selhání uvnitř C workeru nikdy neshodí vaši Go aplikaci:

- Pokud je `zstd_server` ukončen zvenčí (například signálem `SIGKILL` nebo událostí OOM), transportní vrstva HQQ okamžitě detekuje rozbitého partnera a vrátí typovanou chybu `*rt.TransportError` z probíhajícího volání `Compress` nebo `Decompress`.
- Funkce na úrovni balíčku (`zstd.Compress`, `zstd.Decompress`, `zstd.NewWriter`, `zstd.NewReader`) automaticky zjistí, že sdílený výchozí worker zmizel, při dalším volání spustí novou ověřenou instanci `zstd_server` a obnoví normální provoz.

## Rozložení repozitáře

Kódová základna odděluje facade `DataDog/zstd` pro drop-in použití od nízkoúrovňových primitiv relací a hromadných operací `hqq-bindgen`:

```text
gosuda.org/zstd
├── autolaunch.go / hashes.go  # Drop-in API Compress/Decompress, fond s automatickým obnovením a hashe SHA-256
├── zstd_stream.go             # Streamovací Writer/Reader (NewWriterLevelDict, NewReaderDict)
├── zstd_ctx.go                # Ctx bez alokací, obaly CDict a DDict nad hqq-bindgen
├── zstd_bulk.go               # Rámování CompressBulk a DecompressBulk v jediném round tripu
├── zstd.go                    # Generovaný klient hqq-bindgen pro službu zstd IDL
├── zstd.idl                   # Schéma HQQ IDL definující Context, CDict, DDict a RPC metody
├── internal/embedded/         # Binární soubory zstd_server s tagy platforem pro //go:embed (6 cílů OS/architektura)
└── c/                         # Implementace serveru v C11 (zstd_server.c, zstd_hooks.c, main.c)
```

## Začínáme

Nainstalujte `gosuda.org/zstd` pomocí `go get` a používejte jej s `CGO_ENABLED=0`:

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

- **Repozitář na GitHubu**: [https://github.com/gosuda/hqq-zstd](https://github.com/gosuda/hqq-zstd)
- **Architektura a benchmarky**: [docs/ARCHITECTURE.md](https://github.com/gosuda/hqq-zstd/blob/main/docs/ARCHITECTURE.md)
- **Jádro běhového prostředí HQQ**: [https://gosuda.org/hqq](https://gosuda.org/hqq)
