---
id: e52d68870be3de9f644fcfc584bd8aec
author: Lemon Mint
title: 'gosuda.org/zstd: Kompresi Drop-In DataDog/zstd tanpa CGO dan dengan Isolasi Crash'
description: CGO_ENABLED=0 Pustaka Go Zstandard yang menjalankan libzstd C upstream 1.5.7 dalam worker memori bersama dengan API yang kompatibel dengan DataDog/zstd, konteks yang dapat digunakan kembali, dan batching massal.
language: id
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` adalah pustaka kompresi Go dengan `CGO_ENABLED=0` yang menjalankan mesin Zstandard C resmi (`libzstd 1.5.7`) di dalam proses pekerja yang terisolasi melalui memori bersama [HQQ](https://gosuda.org/hqq). Pustaka ini menyediakan API pengganti langsung (drop-in) untuk `github.com/DataDog/zstd` (termasuk `Compress`/`Decompress` sekali panggil, `io.Writer`/`io.Reader` streaming, kamus yang telah diproses sebelumnya, dan konteks tanpa alokasi yang dapat digunakan ulang), sambil menjaga agar eksekusi C sepenuhnya berada di luar ruang alamat runtime Go.

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

## Mengapa Dekompresi Harus Berada di Luar Heap Go Anda

Dalam backend produksi, kompresi dan dekompresi berada langsung pada batas input yang tidak tepercaya. Pengumpul log, broker pesan, gateway RPC, dan mesin penyimpanan mendekompresi gigabyte frame yang berasal dari luar setiap menit.

Banyak tim Go memilih `github.com/DataDog/zstd` karena pustaka ini terikat langsung ke `libzstd` C hulu: implementasi C memberikan throughput single-core yang tinggi, rasio kompresi kamus yang ketat pada rekaman kecil, serta arena C di luar heap (`ZSTD_CCtx` dan `ZSTD_DCtx`) yang tidak memperbesar waktu pemindaian garbage collection Go.

Namun, menautkan `libzstd` ke layanan Go melalui `cgo` menimbulkan dua kendala operasional:

1. **Gesekan Build dan Deployment**: Seperti `go-sqlite3`, `DataDog/zstd` memerlukan `CGO_ENABLED=1` dan toolchain kompiler C target. Kompilasi silang layanan atau pembuatan biner statis untuk `linux/arm64` atau `windows/arm64` memerlukan sysroot C eksternal.
2. **Ruang Alamat Bersama pada Input yang Tidak Tepercaya**: Mendekompresi payload yang rusak atau bersifat adversarial di dalam ruang alamat virtual yang sama dengan server Go Anda berarti setiap bug dalam kode C native atau penanganan kamus kustom dapat menghentikan seluruh proses Go.

`gosuda.org/zstd` mempertahankan mesin `libzstd 1.5.7` C hulu yang persis sama serta API `github.com/DataDog/zstd` yang familiar, tetapi memindahkan eksekusi C ke dalam proses anak terverifikasi (`zstd_server`) yang terhubung ke program Go Anda melalui memori bersama yang disejajarkan dengan cache line.

## Pengganti Langsung untuk `github.com/DataDog/zstd`

Bermigrasi dari `github.com/DataDog/zstd` hanya memerlukan perubahan jalur impor menjadi `"gosuda.org/zstd"`. Tidak diperlukan instalasi biner eksternal ataupun kode pengaturan: pada panggilan pertama, `gosuda.org/zstd` mengeluarkan biner `zstd_server` yang tertanam dan telah diattestasi SLSA untuk platform Anda, memverifikasi digest SHA-256-nya melalui `gosuda.org/hqq/secureexec`, dan membuka kumpulan sesi memori bersama.

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

### Platform yang Didukung dan Biner Tertanam

Keenam platform target dikirim dengan biner worker prebuilt yang dipin SHA-256 dan tertanam melalui build tag khusus platform (`internal/embedded/embed_<goos>_<goarch>.go`):

| Target OS   | Target Arsitektur (`GOARCH`) | Biner Tertanam                  |  Ukuran Biner | Toolchain Build & Provenance                      |
| :---------- | :--------------------------- | :------------------------------ | ------------: | :------------------------------------------------ |
| **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 |

## Di Dalam Jalur Data Memori Bersama

Untuk menjaga throughput tetap kompetitif dengan `cgo` dalam proses, `gosuda.org/zstd` menghindari serialisasi soket dan alokasi heap pada jalur panas (hot path).

### 1. Penyandian Slot Tanpa Alokasi (`zstd_ctx.go` dan `c/zstd_hooks.c`)

Ketika Anda menggunakan `zstd.Ctx` yang dapat digunakan ulang (atau ketika fungsi `Compress` dan `Decompress` tingkat paket meminjam `Ctx` dari kumpulan sesi internal), data mengalir langsung melalui slot `StandardLink` yang dipetakan:

```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. Klien `hqq-bindgen` yang dihasilkan menyalin `src` langsung ke slot permintaan yang dipetakan ke memori dan membalik kata urutan `SeqLock`.
2. Worker C membaca `src` di tempat dari slot permintaan dan meneruskan pointer payload slot respons secara langsung sebagai buffer tujuan ke `ZSTD_compressCCtx` atau `ZSTD_decompressDCtx`.
3. Klien Go menyalin slice hasil dari slot respons ke slice `dst` yang disediakan pemanggil. Dalam kondisi steady state, `ctx.CompressTo(dst, src, level)` dan `ctx.DecompressInto(dst, src)` menghasilkan `0 allocs/op`.

Kamus yang telah diproses sebelumnya (`CDict` dan `DDict`) berada di worker C di balik handle 64-bit yang diperiksa generasinya (`handle CDict`, `handle DDict` dalam `zstd.idl`). Membuat kamus sekali melalui `ctx.NewCDict(rawDict, level)` akan mengurai tabel kamus di dalam worker C dan mengembalikan handle ringan yang dapat digunakan ulang di ribuan panggilan tanpa mengirim ulang byte kamus.

### 2. Mengamortisasi Overhead IPC dengan Framing Massal (`zstd_bulk.go`)

Untuk payload besar (16 KiB ke atas), round trip memori bersama sekitar 200 ns dapat diabaikan dibandingkan waktu CPU yang dihabiskan di dalam `libzstd`. Namun, untuk beban kerja yang mengompresi ribuan pesan kecil berukuran 100 byte hingga 1 KiB sekaligus, membayar 200 ns per item akan menumpuk.

`gosuda.org/zstd` menyediakan `CompressBulk` dan `DecompressBulk` pada `BulkCtx` (`zstd_bulk.go`) untuk menghilangkan round trip per item:

```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` mengemas seluruh batch `[][]byte` ke dalam satu frame permintaan berprefiks panjang di memori bersama. Worker C mengulang setiap item di C (`compress_bulk` dalam `c/zstd_hooks.c`), menulis semua frame terkompresi secara berurutan ke slot respons, dan mengembalikan seluruh batch dalam satu round trip memori bersama.

### 3. Bertahan dari Terminasi Worker Tanpa Membuat Pemanggil Crash

Karena `zstd_server` berjalan dalam proses OS yang terpisah, kegagalan fatal di dalam worker C tidak pernah menjatuhkan aplikasi Go Anda:

- Jika `zstd_server` dihentikan dari luar (misalnya, oleh `SIGKILL` atau peristiwa OOM), lapisan transport HQQ segera mendeteksi peer yang rusak dan mengembalikan `*rt.TransportError` bertipe dari panggilan `Compress` atau `Decompress` yang sedang berjalan.
- Fungsi tingkat paket (`zstd.Compress`, `zstd.Decompress`, `zstd.NewWriter`, `zstd.NewReader`) secara otomatis mendeteksi bahwa worker bawaan bersama telah hilang, memunculkan instans `zstd_server` terverifikasi yang baru pada panggilan berikutnya, dan melanjutkan operasi normal.

## Tata Letak Repositori

Basis kode memisahkan fasad `DataDog/zstd` pengganti langsung dari primitif sesi dan bulk `hqq-bindgen` tingkat rendah:

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

## Memulai

Pasang `gosuda.org/zstd` dengan `go get` dan gunakan dengan `CGO_ENABLED=0`:

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

- **Repositori GitHub**: [https://github.com/gosuda/hqq-zstd](https://github.com/gosuda/hqq-zstd)
- **Arsitektur & Benchmark**: [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)
