はじめに
.NET Core + Docker(Alpine)な環境でZStandardで圧縮したデータをAPIに投げる要件が出てきました。
この記事では、ZstdNetを利用してZStandardで圧縮したデータをHTTPでリクスエトする方法について説明します。
ZStandard(zstd)と.NET Core
ZStandardはfacebookがオープンソース化したライブラリで、高い圧縮率を実現する高速圧縮アルゴリズムだそうです。ZStandardのホームページには、.NETで利用できるライブラリとして下記3つが紹介されています。
- https://github.com/skbkontur/ZstdNet
- https://github.com/bp74/Zstandard.Net
- https://github.com/ImpromptuNinjas/ZStd
今回はgithubで最もスターが多かったZstdNetを利用していきます。
圧縮とHTTPリクエスト
コード自体はZstdNetのgithubにあるサンプルコードを参考にとりあえず次のコードで圧縮しています。CompressionOptionsクラスのコンストラクタに対する引数は圧縮レベルで、1-19の範囲で指定することができます(デフォルトは3)。
ReadOnlySpan<byte>Compress(stringtext){varoptions=newCompressionOptions(16);varbytes=Encoding.UTF8.GetBytes(text);usingvarcompressor=newCompressor();returncompressor.Wrap(bytes);}あとは圧縮したデータのcontent-typeをzstdにして送ってあげればよいです。
varrequestContent=newByteArrayContent(Compress(json).ToArray());requestContent.Headers.ContentType=newMediaTypeHeaderValue("application/json");requestContent.Headers.Add("Content-Encoding","zstd");varresponse=await_httpClient.PostAsync(uri,requestContent);ZstdNetをDockerで動くように調整する。
Visual Studioが作ってくれるDockerfileでそのまま動かそうとすると、下記のようにlibzstdが見当たらないよという例外が発生してしまいます。
zstd net Unable to load shared library 'libzstd' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: Error loading shared library liblibzstd: No such file or directory
ZstdNetはネイティブライブラリであるlibzstdのラッパーでしかないので、Windows以外の環境で実行する場合は個別にインストールする必要があります(Windows用のlibzstd.dllはnugetで一緒にインストールされます)。
Alpineの場合、zstd-libsというパッケージがmainリポジトリで公開されているのでapk addしてあげます。
また、上記のパッケージを追加した場合、/usr/lib/ディレクトリにlibzstd.so.1とlibzstd.so.1.4.5の2つのファイルが配置されるのですが、ZstdNetはlibzstd.soという名前でネイティブライブラリを探しに行くのでシンボリックリンクを作成して騙してあげます。
Dockerfileは次のようになります。
FROM mcr.microsoft.com/dotnet/core/runtime:3.1-alpine AS baseRUN apk add --update--no-cache zstd-libs &&\
ln /usr/lib/libzstd.so.1 /usr/lib/libzstd.so
WORKDIR /appFROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine AS buildWORKDIR /srcCOPY ["ZstdLibSample/ZstdLibSample.csproj", "ZstdLibSample/"]RUN dotnet restore "ZstdLibSample/ZstdLibSample.csproj"COPY . .WORKDIR "/src/ZstdLibSample"RUN dotnet build "ZstdLibSample.csproj"-c Release -o /app/build
FROM build AS publishRUN dotnet publish "ZstdLibSample.csproj"-c Release -o /app/publish
FROM base AS finalWORKDIR /appCOPY --from=publish /app/publish .ENTRYPOINT ["dotnet", "ZstdLibSample.dll"]通信電文を見た限りちゃんと圧縮されているようです。
まとめ
- .NET CoreでZStandardを使って圧縮をしたい場合、ZstdNetを使うと簡単
- ZstdNetはネイティブライブラリを使うので、別途apkでインストールしてあげよう
- ZstdNetはネイティブライブラリを/usr/lib/libzstd.soで探しに行くのでシンボリックリンクでだましてあげよう