大容量ファイルのアップロードを効率的に管理する方法
なぜ大容量ファイルのアップロードを最適化すべきか
フロントエンド開発において、画像、動画、音声ファイルなどのアップロードが必要な場面に頻繁に遭遇します。しかし、大容量ファイルのアップロード時には以下のような問題が発生する可能性があります。
アップロード時間が長くなり、ユーザー体験が悪化する。
サーバー負荷が増加し、リソース消費が増える。
不安定なネットワーク環境ではアップロード失敗が起こり、再アップロードが必要になり、時間と帯域幅が浪費される。
ブラウザのメモリ使用量が高くなり、パフォーマンスや安定性に影響を与える。
これらの問題を解決するために、大容量ファイルのアップロードを最適化する必要があります。
現代のインターネットアプリケーションにおけるニーズ
現代のインターネットアプリケーションでは、ユーザーがファイルをアップロードする際に求められる要件がますます高まっています。例えば:
ソーシャルプラットフォームで高解像度の画像や動画を共有する。
教育プラットフォームで課題や教材を提出する。
企業プラットフォームでプロジェクト文書やレポートをアップロードする。
これらのシナリオでは、アップロードするファイルが数百 MB から数 GB に及ぶ場合があります。従来のアップロード方式を使用すると、前述の問題に直面することになります。
従来のファイルアップロード方式の課題
従来のファイルアップロード方式では、ファイル全体を 1 つのリクエストボディとしてサーバーに送信しますが、以下のような欠点があります。
アップロード時間が長い:大容量ファイルではデータ転送に時間がかかり、ユーザーが結果を待つ必要があります。
サーバー負荷が高い:サーバーは大量のデータを一度に処理する必要があり、メモリ、CPU、帯域幅などのリソースを過剰に消費します。
不安定なネットワークで失敗しやすい:大容量ファイルは切断、タイムアウト、パケット損失などのネットワーク問題に影響を受けやすく、再アップロードが必要になります。
ブラウザのメモリ使用量が高い:ファイル全体をメモリに読み込んで接続を維持する必要があり、他のページのパフォーマンスに影響を与える可能性があります。
これらの問題を解決するために、大容量ファイルアップロードの最適化が不可欠です。
設計アプローチ
大容量ファイルアップロードを最適化するための主なアプローチは以下の通りです。
1. チャンク化
大容量ファイルを小さなチャンク(分割部分)に分割し、それぞれを個別のリクエストとしてサーバーに送信します。これにより、1 回あたりのデータ量を削減し、アップロード時間を短縮し、サーバー負荷を軽減し、再開可能なアップロードを実現します。
function sliceFile(file, chunkSize) {
const fileSize = file.size;
const chunks = Math.ceil(fileSize / chunkSize);
const slices = Array.from({ length: chunks }, (_, index) => {
const start = index * chunkSize;
const end = start + chunkSize;
return file.slice(start, end);
});
return slices;
}
2. 並列処理
複数のチャンクリクエストをサーバーに同時に送信することで、ネットワーク帯域幅やサーバーリソースを最大限に活用し、ユーザー体験を向上させます。
async function uploadChunks(fileChunks) {
const uploadPromises = fileChunks.map((chunk) =>
fetch('/upload', { method: 'POST', body: chunk })
);
const responses = await Promise.all(uploadPromises);
return responses;
}
3. 圧縮
各チャンクを送信前に圧縮し、データサイズをさらに削減して転送効率を向上させます。
async function compressChunk(chunk) {
const compressedChunk = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event) => {
const result = pako.deflate(event.target.result);
resolve(result);
};
reader.onerror = (event) => reject(event.error);
reader.readAsArrayBuffer(chunk);
});
return compressedChunk;
}
4. 検証
データの整合性と正確性を確保するため、転送前または転送後に各チャンクを検証します。
async function verifyChunk(chunk) {
const hash = await calculateHash(chunk);
const response = await fetch(`/verify?hash=${hash}`);
const result = await response.json();
return result;
}
5. 再開可能なアップロード
ネットワーク障害が発生した場合、中断した位置からアップロードを再開することで、時間を節約し速度を向上させます。
async function resumeUpload(file, resumeByte) {
const blob = file.slice(resumeByte);
const formData = new FormData();
formData.append('file', blob);
const response = await fetch('/upload', { method: 'POST', body: formData });
const result = await response.json();
return result;
}
6. 即時アップロード
ファイルを分割する前にハッシュを計算し、サーバーに送信します。同じファイルがサーバーに存在する場合、即座に成功レスポンスを返すことで重複したアップロードを避けます。
async function checkFileExists(file) {
const hash = await calculateHash(file);
const response = await fetch(`/check?hash=${hash}`);
const result = await response.json();
return result;
}
まとめ
本記事では、大容量ファイルアップロードを最適化する必要性と主な最適化手法について説明しました。コード例を通じて、これらの最適化方法を実装する方法を示し、大容量ファイルアップロードの最適化に役立つソリューションを理解・適用できるようにしました。
私たちはLeapcell、バックエンド・プロジェクトのホスティングの最適解です——最大100MBのファイルアップロードに対応しています!
Leapcellは、Webホスティング、非同期タスク、Redis向けの次世代サーバーレスプラットフォームです:
複数言語サポート
Node.js、Python、Go、Rustで開発できます。
無制限のプロジェクトデプロイ
使用量に応じて料金を支払い、リクエストがなければ料金は発生しません。
比類のないコスト効率
使用量に応じた支払い、アイドル時間は課金されません。
例: $25で6.94Mリクエスト、平均応答時間60ms。
洗練された開発者体験
直感的なUIで簡単に設定できます。
完全自動化されたCI/CDパイプラインとGitOps統合。
実行可能なインサイトのためのリアルタイムのメトリクスとログ。
簡単なスケーラビリティと高パフォーマンス
高い同時実行性を容易に処理するためのオートスケーリング。
ゼロ運用オーバーヘッド — 構築に集中できます。
Xでフォローする:@LeapcellHQ