В серверной экосистеме Go библиотека klauspost/compress от шведского разработчика Клауса Поста давно завоевала статус золотого стандарта системного сжатия данных. Если высоконагруженному бэкенду требуется сжимать трафик на лету, сохранять терабайты временных рядов в InfluxDB, распределять блоки в CockroachDB или отдавать файлы в MinIO, стандартные пакеты compress/* из SDK обычно заменяют на оптимизированные решения Клауса Поста. Причина проста: агрессивное использование инструкций AVX2, AVX-512 и ARM NEON позволяет выжимать максимум гигабайт в секунду из каждого процессорного ядра.
Мажорный релиз klauspost/compress 1.20 расширяет горизонты библиотеки: теперь она ориентирована не только на современные высокоэффективные алгоритмы (zstd, S2, snappy), но и на интеграцию с унаследованными протоколами операционных систем и специфическими архивными форматами. В релиз вошли нативная реализация алгоритма LZW, декодер формата Microsoft XPRESS (MS-XCA) и глубокая переработка ассемблерных кодировщиков для архитектуры arm64.
Нативная поддержка LZW и распаковка Microsoft XPRESS
Хотя алгоритм Лемпеля — Зива — Велча (Lempel-Ziv-Welch, LZW) известен индустрии еще с 1980-х годов, он до сих пор активно используется в графических форматах (GIF), старых Unix-архивах (compress/.Z), а также в ряде промышленных сетевых протоколов. Стандартный пакет compress/lzw в Go решает базовую задачу, но создает заметное количество промежуточных аллокаций памяти и уступает в скорости при интенсивном потоковом вводе-выводе.
В версии 1.20 появился новый пакет github.com/klauspost/compress/lzw (PR #1189 от самого Клауса Поста). Он предоставляет оптимизированные структуры Reader и Writer со сниженным потреблением памяти, поддержкой произвольного порядка следования бит (LSB/MSB) и ширины литералов от 6 до 8 бит.
Второе важное новшество — пакет github.com/klauspost/compress/xpress (PR #1195, автор Gowtham). Он реализует алгоритм декомпрессии по официальной спецификации Microsoft [MS-XCA]: Xpress Compression Algorithm. Формат XPRESS лежит в основе десятков корпоративных протоколов экосистемы Windows:
- Вызовы удаленных процедур Windows RPC;
- Сетевая репликация каталогов Active Directory (MS-DRSR);
- Сжатие файлов файловой системы NTFS через механизм WOF (Windows Overlay Filter);
- Образы дисков и обновлений Windows Imaging Format (WIM).
Поддерживаются оба варианта алгоритма, описанные Microsoft: базовый потоковый LZ77 и гибридный режим LZ77 с префиксным кодированием Хаффмана (Huffman). Ранее Go-разработчикам, создававшим инструменты сетевой криминалистики, парсеры дампов реестра или контроллеры домена, приходилось подключать внешние библиотеки на Си через CGO, что ломало статическую сборку и снижало пропускную способность. Теперь разбор дампов выполняется на чистом Go.
Ассемблер arm64 и защита кооперативного планировщика
Помимо новых алгоритмов, релиз 1.20 содержит важные низкоуровневые оптимизации для серверов на базе архитектуры ARM (AWS Graviton, Ampere Altra, Apple Silicon):
- Генерация ассемблера S2 через
avo: разработчица Лиз Фонг-Джонс (Liz Fong-Jones) транслировала генераторы кодировщиков алгоритма S2 с архитектуры amd64 на arm64 с помощью тулкитаavo(PR #1187). Это устранило многолетнее отставание пропускной способности S2 на ARM-процессорах; - Оптимизация чтения таблиц в
zstdиhuff0: замена парных инструкций загрузки на специализированную инструкциюMOVWQZXи очистка регистровых зависимостей в конвейере декодера дали прирост скорости до 8–12% на arm64; - Защита планировщика горутин в
xxhash: в ассемблерных функциях вычисления контрольных сумм ограничен максимальный объем непрерываемой обработки данных. Без этого длинные ассемблерные циклы могли блокировать системные потоки ОС, мешая планировщику Go переключать соседние горутины и вызывая задержки стоп-зе-ворлд в сборщике мусора, что особенно важно в свете грядущих улучшений в Go 1.27.
Практический сценарий: потоковый LZW и разбор буфера XPRESS
Посмотрим, как работать с новыми пакетами на практике. В первом листинге продемонстрирован полный потоковый цикл: сжатие данных с помощью lzw.Writer в буфер оперативной памяти и последующее восстановление через lzw.Reader:
package main
import (
"bytes"
"fmt"
"io"
"log"
"github.com/klauspost/compress/lzw"
)
func main() {
var buffer bytes.Buffer
payload := []byte("Потоковое сжатие LZW с минимальными аллокациями памяти в klauspost/compress")
// 1. Инициализация потокового кодировщика (порядок бит LSB, ширина литерала 8)
writer := lzw.NewWriter(&buffer, lzw.LSB, 8)
if _, err := writer.Write(payload); err != nil {
log.Fatalf("Ошибка сжатия LZW: %v", err)
}
if err := writer.Close(); err != nil {
log.Fatalf("Ошибка закрытия потока: %v", err)
}
// 2. Чтение и распаковка сжатого потока байт
reader := lzw.NewReader(&buffer, lzw.LSB, 8)
defer reader.Close()
decompressed, err := io.ReadAll(reader)
if err != nil {
log.Fatalf("Ошибка распаковки LZW: %v", err)
}
fmt.Printf("Успешно распаковано %d байт: %s\n", len(decompressed), string(decompressed))
}
Во втором листинге показана функция декомпрессии бинарного полезного груза, сжатого по спецификации Microsoft XPRESS:
package main
import (
"fmt"
"log"
"github.com/klauspost/compress/xpress"
)
// DecompressPayload выполняет декомпрессию буфера MS-XCA без вызова CGO
func DecompressPayload(compressed []byte, expectedSize int) []byte {
// Выделение целевого среза под распакованные данные
destination := make([]byte, expectedSize)
// Декодирование буфера (поддерживаются LZ77 и Huffman-варианты MS-XCA)
bytesWritten, err := xpress.Decode(destination, compressed)
if err != nil {
log.Fatalf("Сбой декодирования Microsoft XPRESS: %v", err)
}
fmt.Printf("Восстановлено %d байт из полезной нагрузки XPRESS\n", bytesWritten)
return destination[:bytesWritten]
}
Нюансы внедрения и вердикт
При переходе на klauspost/compress 1.20 важно учитывать, что пакет xpress пока поддерживает исключительно декомпрессию данных. Сжатие в формат MS-XCA в текущей версии не реализовано (для взаимодействия с протоколами Windows на чтение этого более чем достаточно).
Обновление однозначно рекомендуется к внедрению в проектах, работающих на облачных ARM-инстансах или взаимодействующих с корпоративной инфраструктурой Microsoft: вы получаете прирост скорости на arm64 без изменения прикладного кода и чистый Go-стек без головной боли с CGO.
