大容量サイトを分割エクスポートするLUXCMの仕組み

大容量サイトの分割エクスポート――アップロード上限とパート分割の原理

私は、分割エクスポートを単なる追加機能ではなく、コア機能として位置づけている。

サイトが少し大きくなっただけでも、この機能がなければ、インポート画面までファイルをアップロードすること自体が不可能になるケースを実際に見てきたからだ。

この記事では、なぜこのような問題が起きるのか、そして私がどのように解決したのかを、コードに実装された検証ロジックとともに説明する。

アップロード上限は気まぐれな制限ではなく、共有リソースを守るための仕組みだ

「最近のホスティングなら、大きなファイルでも普通にアップロードできるのでは」と考える人には、これまで何度も出会ってきた。

Bluehostによる共有ホスティングのアップロード上限に関する解説は、なぜその考えが正しくないのかを明確に説明している。実際の上限は「ホスティング会社や料金プランによって異なるが、通常は数MBから128MBの範囲」だという。

そして、この上限は恣意的に設定されているわけではない。複数のサイトが1台のサーバーリソースを共有する共有ホスティングでは、「無制限のアップロード1件がリソースプールを長時間占有し、同じサーバー上にある他のすべてのサイトを遅くしたり、停止させたりする可能性がある」からだ。

CPU、メモリ、ディスクI/Oを保護するためにupload_max_filesize、post_max_size、memory_limitを保守的に設定するのは、WordPressの制約ではなく、「共有環境に組み込まれたリソース保護機構」だというのが、この記事の結論である。

この説明を読んで、ユーザーに「ホスティング会社へ依頼して上限を引き上げてもらいましょう」と案内することは、根本的な解決策にはならないと改めて確認した。

デフォルト値を19MB、調整範囲を1~500MBとした理由

エクスポート画面では、1つのパートの最大サイズはデフォルトで19MBに設定されている。「詳細設定」を有効にすれば、1MBから500MBの範囲で自由に変更できる。

このデフォルト値は、恣意的に決めたものではない。Bluehostの記事にある「通常は数MBから128MB」という実際の範囲を考えると、19MBは、多くのホスティング環境で個別の設定変更なしに安全に通過できる値だ。
一方で、サーバーのアップロード上限をすでに高く設定しているユーザーや、逆に上限が非常に低い環境を利用しているユーザーに対応するため、1MBから500MBまで幅広く調整できるようにした。

これは「誰にとっても正解となる設定が1つあるわけではない」ことを認め、ユーザーが自分のホスティング環境に合わせて調整できるようにしたものだ。

ファイル名の先頭に番号を付けた理由

パートファイルの名前は、これまでのNEWS-LUX-20260825-074327.wpmpx.part1of2のように末尾へ番号を付ける形式から、part1of2-NEWS-LUX-20260825-074327.wpmpxのように先頭へ番号を付ける形式へ変更した。

些細なことに見えるが、実際の使い勝手から導いた判断だ。フォルダー内に複数のパートを並べたとき、唯一異なる部分である番号がファイル名の末尾近くに埋もれ、その前にほとんど同じ長い文字列が続いていると、ファイルブラウザーやアップロード画面で見分けにくい。

番号を先頭に移すと、複数のパートを一覧表示した際、ファイル名の最初の文字を見るだけで順番がすぐに分かる。ただし、旧バージョンが生成した「末尾に番号を付ける」形式のファイルも引き続き認識できるよう、2種類のパターンをどちらも解析する仕様にした。すでにその形式でパートファイルを作成しているユーザーがいる可能性があるからだ。

再結合は「とりあえず結合してみる」方式ではない

インポート画面でパートをまとめて選択してアップロードしても、私はすぐに結合することはしない。まず、次の検証を順番に行う。

1つ目は、パートファイルではないファイルが混ざっていないかの確認だ。ファイル名がpartN of M-パターンに一致しない場合は、「パートファイルではないファイルが混在しています」というエラーを直ちに表示する。

2つ目は、異なるエクスポート処理で作成されたパートが混ざっていないかの確認だ。すべてのパートは同じベースファイル名と同じ総パート数を持っていなければならない。これらが一致しない場合は、「異なるエクスポートセットのパートが混在しています」と通知する。これは、ユーザーが誤って昨日エクスポートしたファイルと、今日あらためてエクスポートしたファイルのパートを混ぜてアップロードする事態を防ぐためだ。

3つ目は、同じ番号のパートが重複してアップロードされていないかの確認だ。たとえばpart2of5が2つアップロードされ、part3of5が存在しない場合は、「同じ番号のパートが重複してアップロードされています」と通知する。

この3つの検証をすべて通過しても、最後に実際に集まっているパート数が総数と一致するかを確認する。不足している場合は、「パートが不足しています(アップロード済み:N個、必要:M個)。エクスポート画面で作成されたパートファイルをすべてアップロードしてください」と、正確な数値とともに通知する。

この4つの検証のうち、どれか1つでも失敗した場合、処理を黙って続行することはない。不完全または不正なファイルでインポートを試みるよりも、何が問題なのかを最初に正確に伝え、処理を止めるべきだと判断したからだ。

本当の意味での「レジューム可能なアップロード」ではないことも、正直に伝える必要がある

この分割方式は、Filestackの大容量アップロード処理ガイドが説明する「チャンクアップロード」とは明確に区別しておきたい。

このガイドは、ファイル全体を1回のリクエストでアップロードする際に生じる問題を指摘している。遅い、あるいは不安定なネットワーク環境では「サーバーの実行時間制限によってアップロードが完了しない」タイムアウトの問題、接続が切れると「最初からやり直さなければならない」再試行コストの問題、さらに「大容量ファイルをメモリ上で処理する共有サーバーが利用可能なリソースを使い果たし、最終的にサーバーが停止する」問題だ。このガイドが解決策として挙げているtusやResumable.jsのような本来のチャンクアップロードプロトコルでは、1つのファイルをバイト単位で分割して送信し、接続が途切れた場合も中断した地点から正確に再開できる。

私が実装した分割方式は、それとは異なる。

.wpmpxの各パートは、それ自体で独立して完結した1つのファイルであり、ユーザーはこれらのパートを1つずつ、完全なHTTPアップロードリクエストとして送信する。

1つのパートを小さくすることで、サーバーの実行時間制限にかかるリスクを抑えられる。また、アップロード中にパート1つの処理が失敗しても、数百MB全体を最初からアップロードし直す必要はなく、そのパートだけを再送すればよい。

その代わり、実際に何をしているのか――ファイル自体を複数の独立したパートに分割し、それらを厳密に検証したうえで、メモリに負担をかけず順番どおりに再結合すること――を正確に伝える道を選んだ。

結論として

分割エクスポートは、ホスティング会社ごとに異なるものの、そこには合理的な理由があるアップロード上限という現実を前提に設計されている。

デフォルト値と調整可能な範囲は、実際のホスティング環境の分布を考慮して決めた。ファイル名における番号の位置は、実際の使い勝手に関する問題から導いた判断だ。

そして最も重要なのは再結合の段階だ。混在したファイル、異なるセット、重複した番号、不足しているパートをそれぞれ個別に検証し、何が間違っているのかを正確に知らせる。検証を通過したパートは、メモリに負担をかけずストリーミング方式で結合する。

これが本来の意味でのレジューム可能なアップロードではないことも、隠すつもりはない。それでも、この程度の設計によって、大容量サイトを移行しようとしてアップロード上限の前で途方に暮れる状況は、確実に減らせると考えている。

参考資料