عنوان:

‫پشتیبانی از فشرده‌سازی Zstandard (Zstd) در NET 11.


نویسنده: وحید نصیری
تاریخ: ۱۴۰۵/۰۳/۱۳ ۰۸:۲۰
آدرس: www.dntips.ir
بهینه‌سازی حجم داده‌های انتقالی و ذخیره‌شده، یکی از کلیدی‌ترین ارکان افزایش کارایی (Performance) و کاهش هزینه‌های زیرساخت است. فریم‌ورک دات‌نت، سال‌هاست که با ارائه استریم‌های فشرده‌سازی متعددی نظیر DeflateStream، GZipStream، ZLibStream و در نسخه‌های اخیر BrotliStream، ابزارهای قدرتمندی را در اختیار توسعه‌دهندگان قرار داده است. با این حال، نیاز به الگوریتمی که بتواند تعادلی بی‌نقص میان سرعت فوق‌العاده بالا و نسبت فشرده‌سازی ایده‌آل برقرار کند، همواره در پروژه‌های مقیاس‌بزرگ احساس می‌شد.
در نسخه جدید .NET 11، عضو جدیدی به نام ZstandardStream به این مجموعه اضافه شده است که به ما اجازه می‌دهد از پتانسیل عظیم الگوریتم Zstandard (یا به اختصار Zstd) به صورت بومی (Native) بدون نیاز به کتابخانه‌های شخص ثالث استفاده کنیم. در این مقاله، به بررسی ساختار این الگوریتم، قابلیت‌ها، نحوه پیاده‌سازی و ابزارهای جدید آن در دات‌نت ۱۱ خواهیم پرداخت.


الگوریتم Zstandard چیست؟

الگوریتم Zstandard یک مکانیزم فشرده‌سازی داده‌ی منبع‌باز (Open-source) و بدون اتلاف (Lossless) است که در سال ۲۰۱۵ توسط فیس‌بوک (متا) توسعه یافته و معرفی شد. هدف اصلی از طراحی Zstd، جایگزینی الگوریتم قدیمی اما محبوب DEFLATE (پایه و اساس ابزارهای ZIP و gzip توسعه یافته در سال ۱۹۹۱) بود.
مزیت رقابتی Zstd در این است که نسبت فشرده‌سازی (Compression Ratio) مشابه یا حتی بهتری نسبت به DEFLATE ارائه می‌دهد، اما در فرآیند باز کردن فشرده‌سازی (Decompression) سرعت به‌شدت بالاتری را به نمایش می‌گذارد. این الگوریتم به‌شدت انعطاف‌پذیر بوده و بازه گسترده‌ای از سطوح فشرده‌سازی را از 7- (سریع‌ترین حالت با کمترین نرخ فشرده‌سازی) تا 22 (کندترین حالت اما با بیشترین میزان فشرده‌سازی) پشتیبانی می‌کند. حالت پیش‌فرض این الگوریتم روی سطح 3 تنظیم شده است که توازن بهینه‌ای برای اکثر سناریوهای عمومی فراهم می‌سازد.
جایگاه صنعتی Zstandard: کارایی بالای Zstd باعث شده است که در پروژه‌های بزرگ جهانی به عنوان استاندارد فشرده‌سازی انتخاب شود؛ از جمله سیستم‌فایل‌های لینوکس (btrfs و SquashFS)، مدیریت بسته‌های توزیع‌های آرچ‌لینوکس و فدورا، پلتفرم ابری AWS Redshift، سیستم Core Dump در FreeBSD و حتی آرشیو بازی‌های کنسول نینتندو سوییچ.

رابط‌های برنامه‌نویسی جدید (API) در دات‌نت ۱۱
طراحی مکانیزم جدید Zstd در .NET 11 کاملاً از الگوی پیاده‌سازی الگوریتم Brotli پیروی می‌کند. بنابراین، اگر قبلاً با خانواده Brotli* کار کرده باشید، استفاده از ابزارهای جدید برای شما بسیار آشنا و ساده خواهد بود. فضای نام System.IO.Compression میزبان چهار تایپ (Type) اصلی جدید است:
  • ZstandardStream: یک کلاس بسته‌بندی استریم (Stream Wrapper) جهت مدیریت جریان‌های داده‌ای.
  • ZstandardEncoder / ZstandardDecoder: ساختارهایی مبتنی بر Struct، بهینه برای مدیریت حافظه و سازگار با Span.
  • ZstandardDictionary: قابلیتی منحصربه‌فرد جهت فشرده‌سازی داده‌های کوچک و مکرر با بازدهی بالا.
  • ZstandardCompressionOptions: کلاسی برای تنظیم دقیق کیفیت، اندازه پنجره (Window Size) و ویژگی‌های اعتبارسنجی.

۱. استفاده از API به صورت استریم (Streaming)
این روش برای داده‌های حجیم که به صورت جریان داده (مانند دانلود فایل یا سوکت‌های شبکه) خوانده می‌شوند، ایده‌آل است:
// Compress (فشرده‌سازی)
using var output = new MemoryStream();
using (var zstd = new ZstandardStream(output, CompressionMode.Compress))
{
    await inputStream.CopyToAsync(zstd);
}

// Decompress (باز کردن فشرده‌سازی)
using var zstdDecompress = new ZstandardStream(compressedStream, CompressionMode.Decompress);
await zstdDecompress.CopyToAsync(outputStream);

۲. استفاده از API تک‌مرحله‌ای (One-shot Span-based API)
اگر تمام داده‌ها از قبل در حافظه بارگذاری شده‌اند و نیازی به استریم پویا ندارید، استفاده از متدهای ساختارهای ZstandardEncoder و ZstandardDecoder به دلیل عدم تخصیص حافظه اضافی در بخش Heap و هماهنگی با Span، بازدهی به مراتب بالاتری دارد:
byte[] source = File.ReadAllBytes("data.bin");

// Compress
int maxLength = ZstandardEncoder.GetMaxCompressedLength(source.Length);
var compressed = new byte[maxLength];
ZstandardEncoder.TryCompress(source, compressed, out int bytesWritten);

// Decompress
int decompressedSize = ZstandardDecoder.GetMaxDecompressedLength(compressed.AsSpan(0, bytesWritten));
var decompressed = new byte[decompressedSize];
ZstandardDecoder.TryDecompress(compressed.AsSpan(0, bytesWritten), decompressed, out int bytesRead);

۳. تنظیم سطوح کیفیت فشرده‌سازی (Compression Levels)
با استفاده از کلاس تنظیمی ZstandardCompressionOptions می‌توان کیفیت فشرده‌سازی را به صورت عددی سفارشی‌سازی کرد. در دات‌نت، گزینه عمومی CompressionLevel.Fastest به کمترین مقدار عددی و CompressionLevel.SmallestSize به سقف آن یعنی ۲۲ نگاشت می‌شود:
var options = new ZstandardCompressionOptions
{
    Quality = 6 // بازه عددی بین 1 تا 22، مقدار پیش‌فرض 3 است
};

using var zstd = new ZstandardStream(output, options);

یکپارچه‌سازی با ASP.NET Core برای فشرده‌سازی پاسخ‌ها
یکی از کاربردی‌ترین مصارف این الگوریتم، فشرده‌سازی خودکار پاسخ‌های HTTP در وب‌سرویس‌ها و APIها (Response Compression) است. با اضافه کردن الگوریتم Zstd به خط لوله (Pipeline) برنامه در فایل Program.cs، دات‌نت به طور خودکار هدر درخواست‌های حاوی Accept-Encoding: zstd را شناسایی کرده و پاسخ را فشرده می‌کند:
// Program.cs
builder.Services.AddResponseCompression(x =>
{
    x.EnableForHttps = true;
    x.Providers.Add<ZstandardCompressionProvider>();
});
همچنین، برای پردازش و باز کردن درخواست‌های فشرده ورودی کلاینت به سمت سرور، رابط IDecompressionProvider به همین سادگی مکانیزم معکوس را پیاده‌سازی و مدیریت می‌کند.

فشرده‌سازی پیشرفته مبتنی بر دیکشنری (Dictionary Compression)
بزرگترین تمایز Zstd با سایر الگوریتم‌های سنتی، قابلیت Dictionary Compression است. زمانی که شما تعداد زیادی داده کوچک و مشابه (مانند پاسخ‌های JSON یک API، پیام‌های سریالایز شده در کلافکا، یا تنظیمات مکرر) دارید، الگوهای ساختاری تکراری (مثل نام کلیدها در کدهای JSON) در تک‌تک این پیام‌ها حجم بیهوده‌ای اشغال می‌کنند. در روش‌های معمولی، الگوریتم به دلیل کوچک بودن حجم داده، فرصتی برای پیدا کردن و بهینه‌سازی این الگوها ندارد. Zstd با آموزش یک دیکشنری مشترک، این مشکل را حل می‌کند.
برای استفاده از این قابلیت، ابتدا باید الگوریتم را با داده‌های نمونه واقعی آموزش داد، سپس دیکشنری تولید شده را در محیطی که هم تولیدکننده (Producer) و هم مصرف‌کننده (Consumer) به آن دسترسی دارند، ذخیره کرد:
// آموزش دیکشنری از روی نمونه‌ها
byte[] allSamples = ...; // الحاق تمام داده‌های نمونه به هم
int[] lengths = ...;     // طول تک‌تک نمونه‌ها

using ZstandardDictionary dict = ZstandardDictionary.TrainFromSamples(allSamples, lengths, maxDictionarySize: 100_000);

// فشرده‌سازی با کمک دیکشنری - هر دو سمت باید از یک دیکشنری یکسان استفاده کنند
using var encoder = new ZstandardEncoder(dict);
encoder.Compress(payload, compressed, out int consumed, out int written, isFinalBlock: true);
نکته: طبق توصیه‌های استاندارد، حجم بهینه برای دیکشنری حداکثر ۱۰۰ کیلوبایت است و برای آموزش بهینه آن بهتر است حجم داده‌های نمونه حدود ۱۰۰ برابر حجم نهایی دیکشنری (حدود ۱۰ مگابایت داده نمونه واقعی و متناوب) باشد تا بالاترین نرخ بازدهی حاصل شود.

نتیجه‌گیری
اضافه شدن بومی Zstandard به فریم‌ورک .NET 11 نقطه عطفی در مدیریت کارآمد منابع، کاهش هزینه‌های پهنای باند و افزایش سرعت سیستم‌ها به شمار می‌رود. Zstd با ارائه سرعت خارق‌العاده در باز کردن داده‌ها (Decompression) و انعطاف‌پذیری بالا در تعیین سطوح فشرده‌سازی، در کنار قابلیت انقلابی فشرده‌سازی مبتنی بر دیکشنری، گزینه‌ای بی‌نقص برای سیستم‌های مبتنی بر میکروسرویس، پلتفرم‌های ابری و وب‌سایت‌های پرترافیک است. استفاده از این ابزار جدید گامی مهم در جهت ارتقای استانداردهای کارایی (Performance) در اکوسیستم دات‌نت خواهد بود.