はじめに
SENSYN ROBOTICS(センシンロボティクス)の中山です。開発組織全体を見る技術統括という組織でディレクターをやっています。
前々回、前回に続いて、性能を担保するための基礎力を向上させたいと思って記事を書いています。今回は応答時間を短縮するためのストリーム編です。
ストリーム
ストリーム(Stream)は流れという意味で、IT文脈だと連続的にデータを流すための仕組みを意味します。ストリームを使ってデータを溜めずに処理したらすぐに流していく手法がストリーミングで、映像や音楽をストリーミングするサービス(YouTubeやSpotify等)が身近ですね。
ストリーミングを使うと、一度に使用するリソースを減らして、応答時間を改善できるというメリットがあります。
ストリーミングサービス以外で身近なストリーミングは、Dockerでコンテナのログをフィルタしながら見るようなケースです。
docker logs -f any-container | grep error
この場合、連続するログを標準出力から得て、それを1行毎にフィルタしていくのが、ストリーミング処理です。
例: 画像のダウンロード機能
AWS S3やAzure Blob Storageのようなクラウドストレージ上に保存されている画像ファイルを、ZIPファイルにまとめてダウンロードする機能を例に、ストリームをどう適用するかを考えてみます。
初期設計
ストリームを使わない設計だと、このような処理になると思います。ZIPファイルをまず作って、それを返すというやり方です。
- 空のZIPファイルを作成する
- クラウドストレージから一つずつファイルをダウンロードして、ZIPファイルに追加する
- ダウンロードしたファイルを削除する
- 2〜3をファイル数だけ繰り返す
- すべてのファイルをZIPファイルに追加したら、ZIPファイルをHTTP response bodyとして送信する
初期設計の問題点
この設計には以下のような問題点があります。
- ファイル数が多いと、ZIPを作成する場所のディスク使用量が大きくなる
- 複数のユーザーがダウンロードすると、Disk fullになることがあり得る (コンテナ環境で起きがち)
- 応答を送り始めるまでが遅く、ファイル数が多いと2〜3の繰り返しに時間が掛かりすぎてタイムアウトする
ストリームを使って改善した設計
初期設計の問題を、ストリームを使って解決すると、以下のような処理になります。
- 出力先をHTTP response bodyとするZIPストリームを作成する
- クラウドストレージから一つずつファイルをダウンロードして、ZIPストリームに追加する
- ダウンロードしたファイルを削除する
- 2〜3をファイル数だけ繰り返す
- すべてのファイルをZIPストリームに追加したら、ストリームを閉じて応答を完了する
改善した結果
ストリームを使うことで、以下の改善を行えました。
- ディスクの使用量は各ファイルのサイズだけになった
- 1つ目のファイルをダウンロードしたらすぐに応答を返せるので、タイムアウトしにくい
より改善する方法
クラウドストレージからダウンロードするときにファイルを作成するのではなく、ダウンロードのストリームをZIPストリームに連結すると、ディスクを使用せずにZIPファイルを生成して返せます。
ストリーミングの欠点
ただし、ストリーミングは万能ではなく、以下のような欠点があります。
- 通常のファイルアクセスやメモリ上のオブジェクトと異なり、random accessができない
- そのため、溜めたデータにrandom accessする必要がある場合は、ストリーミングは適用できない
適用できるのはsequentialな処理だけです。
まとめ
- ストリームを使うと、一度に使用するリソースを減らして、応答時間を改善できる
- ストリームを利用できるのはsequentialな処理だけ