ティックとスレッドの仕組み

Minecraft のサーバーが重くなる理由の多くは、ワールドの計算がメインのスレッド 1 つで動くことにあります。
この資料では、1 回のティックで何を計算しているのか、なぜ CPU のコアを増やしても速くならないのかを、図で説明します。

対象は Java 版のサーバー (バニラと Paper) です。処理の順番は Minecraft Wiki と Paper のソースコード、設定の名前と既定の値は 2026 年 10 月時点の PaperMC のドキュメントによります。

1 秒に 20 回のティック

Minecraft のサーバーは、ワールドの中の出来事を、1 秒に 20 回、まとめて計算しています。この 1 回の計算を「ティック」と呼びます。作物が育つのも、モブが動くのも、レッドストーン回路が動くのも、すべてティックごとに進みます。

1 秒に 20 回を保つには、1 回のティックを 50 ミリ秒以内に終える必要があります。計算が早く終わったときは、次のティックの時刻まで待ちます。

ティックは 1 秒に 20 回。1 回は 50 ミリ秒以内。

0 秒1 秒

1 回のティック (50 ミリ秒) の中身の例

上の 20 個のマスは、実際の速さ (50 ミリ秒ごと) で順に点灯します。下の図は、1 回のティックを引き伸ばして、処理が進む順に表示しています (画面に入ったときに 1 回)。割合は説明のための例です。実際の割合は、ワールドとプレイヤーの数、レッドストーン回路やモブの数によって大きく変わります。

サーバーの状態は、次の 2 つの数字で表します。

指標意味目安
TPS1 秒あたりのティックの回数 (Ticks Per Second)20 が上限。下回るとワールド全体の動きが遅れる
MSPT1 回のティックにかかった時間 (Milliseconds Per Tick)50 ミリ秒以下を保つ。平均だけでなく、最大と上位の値も見る

TPS が 20 のままでも、MSPT が 45 ミリ秒であれば、余裕はほとんどありません。人数が少し増えたり、大きなレッドストーン回路が動いたりしただけで、TPS が下がります。サーバーの余裕は、TPS ではなく MSPT で見ます。

1 回のティックで計算すること

Minecraft Wiki がまとめている処理の順番を、要点に絞って示します。ディメンション (オーバーワールド、ネザー、ジ・エンド) は、1 つずつ順番に計算します。

  1. 遅れの確認と、tick・load の関数の実行 (データパックの処理)
  2. ディメンションごとの計算 (オーバーワールド、ネザー、ジ・エンド、追加のディメンションの順)
    • ワールドボーダー、天候、時間、睡眠
    • 予約されたブロックの更新 (レッドストーン回路など) と、液体の流れ
    • 襲撃
    • チャンクごとの処理 (モブのスポーン、雪と氷、作物の成長などのランダムティック)
    • ブロックイベント (ピストン、音符ブロックなど)、エンダードラゴンの戦い
    • エンティティ (モブ、アイテム、トロッコなど)
    • ブロックエンティティ (ホッパー、かまど、チェストなど)
  3. プレイヤーとの通信の処理 (届いた操作の反映、変化の送信)
  4. 6,000 ティック (5 分) ごとの自動保存

このうち、プレイヤーの数に比例して増えやすいのは、読み込まれるチャンクと、その中のモブ、エンティティ、ブロックエンティティです。プレイヤーが散らばるほど読み込むチャンクは増え、1 か所に集まるほど、その場所のモブやエンティティの計算が重くなります。

チャンクと読み込まれる範囲

Minecraft のワールドは、「チャンク」という区画に分けて保存し、計算しています。1 つのチャンクは、横が 16×16 ブロックで、縦はワールドの底から高さの上限までです。オーバーワールドでは Y -64 から 319 までの 384 ブロック、ネザーとジ・エンドでは Y 0 から 255 までの 256 ブロックです。

サーバーは、ワールド全体を計算しているのではありません。計算するのは、読み込まれているチャンクだけです。読み込まれたチャンクにも段階があり、モブまで動かすチャンク、ブロックだけを動かすチャンク、読み込んでおくだけのチャンクに分かれます。

view-distance が 7、simulation-distance が 3 のときの、1 人のプレイヤーのまわり (上から見た図)見えている範囲のすべてを、計算しているわけではない。

モブやエンティティまで計算するブロックだけ計算する (レッドストーン回路、液体など)読み込んで送るだけ読み込まない

1 マスが 1 チャンク (16×16 ブロック) です。中央の白い点が、プレイヤーのいるチャンクです。読み込む範囲は円に近い形、計算する範囲は正方形です。既定の値は、どちらも 10 です。つまみを動かすと、範囲とチャンクの数が変わります。この図では、simulation-distance を view-distance 以下の範囲で動かせます。

プレイヤーのまわりの 2 つの距離

設定 (server.properties)意味既定
view-distanceプレイヤーに送るチャンクの範囲 (半径、チャンクの数)。この範囲を読み込む10 (3〜32)
simulation-distanceモブやエンティティを動かす範囲。その外側の 1 チャンクの幅では、レッドストーン回路や液体など、ブロックの処理だけが進む10 (3〜32)

view-distance を広げると、遠くまで見えるようになりますが、読み込むチャンクと、プレイヤーに送る通信が増えます。simulation-distance を狭くすると、見えていても動かない範囲が増えるかわりに、計算は減ります。Paper では、ワールドごとの値を spigot.yml の world-settings で変えられます。

モブが自然にスポーンするのは、プレイヤーから 8 チャンク (128 ブロック) 以内のチャンクだけです。

プレイヤーがいなくても読み込まれるチャンク

きっかけ読み込まれる範囲と期間
/forceload指定したチャンク。サーバーを再起動しても残る。1 回のコマンドで指定できるのは 256 チャンクまで
ポータルネザーポータル、エンドポータル、エンドゲートウェイを、プレイヤー、モブ、アイテムが通ると、移動先のまわりを 15 秒間
投げたエンダーパール飛んでいる間、まわりの 3×3 チャンク (1.21.2 から)
エンダードラゴンとの戦い戦いの間、ジ・エンドの中央のまわり

スポーン地点のまわりを常に読み込む仕組み (スポーンチャンク) は、1.21.9 で廃止されました。それまでスポーンチャンクで動かし続けていた装置は、プレイヤーが近くにいるか、/forceload で読み込まない限り、止まります。

1.21.5 からは、/forceload やエンダーパールで読み込んだチャンクでも、作物の成長などのランダムティックが進みます。ポータルにアイテムを通し続ける装置 (チャンクローダー) を使うと、プレイヤーがいない場所を読み込み続けられます。サーバーの負荷になるため、公開のサーバーでは、こうした装置の扱いをルールで決めておきます。

読み込みの解除と、新しいチャンクの生成

チャンクを読み込んでおく理由 (プレイヤー、/forceload、ポータルなど) がなくなると、チャンクは保存されて、読み込みが解除されます。Paper は、プレイヤーが離れたチャンクの解除を 10 秒遅らせます (paper-world-defaults.yml の chunks.delay-chunk-unloads-by)。すぐに戻ったときに、読み込み直さずに済みます。

読み込まれるチャンクの数は、プレイヤーが 1 か所に集まっていれば重なって少なく、散らばるほど増えます。view-distance が 10 なら、1 人のまわりだけで、直径 21 チャンクほどの円の範囲 (300 チャンクを超える) を読み込みます。

まだ誰も行っていない場所のチャンクは、保存したデータを読み込むのではなく、地形から生成します。プレイヤーが散らばって新しい場所を探索すると、生成の負荷が大きくなります。大人数のサーバーでは、公開の前にワールドボーダーで範囲を決め、Chunky などのプラグインで、その範囲のチャンクをあらかじめ生成しておきます。Folia のドキュメントも、事前の生成を勧めています。

Paper の設定 (paper-global.yml)意味既定
chunk-loading-basic.player-max-chunk-send-rate1 人に送るチャンクの数の上限 (1 秒あたり)75
chunk-loading-basic.player-max-chunk-load-rate1 人のために読み込むチャンクの数の上限 (1 秒あたり)100
chunk-loading-basic.player-max-chunk-generate-rate1 人のために生成するチャンクの数の上限 (1 秒あたり)-1 (制限なし)

メインのスレッドが 1 つであること

上の処理は、ほぼすべて「Server thread」という 1 つのスレッドで、順番に行われます。オーバーワールドとネザーとジ・エンドも、別々のコアで同時に計算されるのではなく、同じスレッドで 1 つずつ計算されます。Paper も、この基本の仕組みは同じです。

8 コアの CPU でも、Paper のワールドの計算は 1 つのコアに集中する。
Server threadワールドの計算 (すべてのディメンション)
Netty Server IOプレイヤーとの通信
Paper Common Workerチャンクの生成など
Paper I/O Workerチャンクの読み書き
Async Chat Threadチャット
Craft Scheduler Threadプラグインの非同期の処理
GCJava のメモリの回収
(空き)OS、ほかのプロセス

スレッドの名前は Paper のソースコードによります。使用率は説明のための例です。実際には、OS が各スレッドを空いているコアに割り振ります。

ワールドの中の出来事は、互いに影響し合います。ピストンがブロックを押せば、その先のレッドストーン回路が変わり、モブの動きも変わります。こうした処理を複数のスレッドで同時に計算すると、順番が入れ替わって結果が変わったり、同じデータを奪い合ったりします。順番どおりに 1 つのスレッドで計算するのは、ゲームの動きを保つための作りです。

そのため、CPU のコアの数を増やしても、ワールドの計算そのものは速くなりません。速くするには、1 コアあたりの性能が高い CPU を選ぶか、計算の量を減らすか、サーバーを分けるかのどれかです。

ほかのスレッドで動く処理

メインのスレッドの負担を減らすため、ワールドの状態を直接変えない処理は、別のスレッドで動きます。

スレッドの名前処理設定
Netty Epoll Server IOプレイヤーとの通信の送受信spigot.yml の netty-threads(既定 4)
Paper Common Workerチャンクの生成などpaper-global.yml の chunk-system.worker-threads(既定は自動。物理コアの半分まで)
Paper I/O Workerチャンクの読み込みと保存chunk-system.io-threads(既定は自動で 1)
Async Chat Threadチャットの処理chat-executor-core-size など
Craft Scheduler Threadプラグインが非同期で行う処理プラグインの作りによる
Paper Watchdog Threadメインのスレッドの停止の監視spigot.yml の timeout-time

Paper の起動のときのログには、「Paper is using X worker threads, Y I/O threads」と、チャンクの処理に使うスレッドの数が表示されます。

50 ミリ秒を超えたとき

1 回のティックが 50 ミリ秒を超えると、次のティックは待たずにすぐ始まります。重いティックが続くと、1 秒に 20 回を保てなくなり、TPS が下がります。プレイヤーからは、モブやブロックの動きが遅れ、壊したブロックが戻るように見えます。

1 回の重いティックが、後ろのティックを押し出す。

通常

重いティック

050100150200250 ミリ秒
ティック50 ミリ秒を超えたティック待たずに続けて行うティック (遅れを取り戻す)

縦の線は 50 ミリ秒ごとの区切りです。遅れが小さいうちは、待ち時間なしでティックを続けて、遅れを取り戻します。

遅れが大きくなったときの動きは、バニラと Paper で異なります。

  • バニラ: 遅れが約 2 秒を超えると、ログに「Can't keep up! Is the server overloaded?」と表示し (15 秒に 1 回まで)、遅れた分のティックを取り戻さずに飛ばします
  • Paper: この処理を置き換え、遅れを取り戻すために続けて行うティックの数を、misc.catchup-ticks(既定 5) までに限ります。一時的な重さのあとに、ワールドが急に早送りされるのを防ぎます

ティックが止まったまま進まない場合は、Watchdog がサーバーを止めます。spigot.yml の timeout-time(既定 60 秒) のあいだティックが終わらないと、応答がないと判断して停止し、設定があれば再起動します。Paper は、その前の 10 秒後から、メインのスレッドが何をしているかをログに出力します。

メインのスレッドを止めてしまう処理

メインのスレッドの上で、時間のかかる処理を待つと、その間ワールド全体が止まります。よくある原因は、プラグインがメインのスレッドでデータベースや外部の Web のサービスに問い合わせることです。応答に 200 ミリ秒かかれば、その間に 4 回分のティックが失われます。

Paper のドキュメントは、Web のリクエスト、ファイルの読み書き、データベースなど時間のかかる処理は、非同期のタスクで行うよう案内しています。一方で、Bukkit の API の多くは非同期のタスクから安全に使えないため、ワールドを変える処理だけをメインのスレッドに戻す作りが必要です。

Paper の Watchdog のメッセージも、メインのスレッドの状態に HTTP や MySQL の処理が含まれていれば、そのプラグインの作者に報告するよう案内しています。データベースとの連動の作り方は、MySQL との連動で説明しています。

計測にもとづいて判断する

性能の改善は、計測から始めます。サーバーが重いと感じると、原因の見当を付けて設定を変えたくなります。しかし、見当が外れていれば、効果のない変更を重ねるだけでなく、別の不具合を生み、元の原因を見えにくくします。重さの原因は、プレイヤーの行動、ワールドの状態、プラグインの組み合わせで変わるため、経験や一般論だけでは特定できません。

KEY SELECT は、Minecraft に限らず、Web のシステム、データベース、ネットワーク、クラウドのどの技術でも、憶測ではなく計測にもとづいて判断します。進め方は次のとおりです。

  1. 基準を測る: 変更の前に、TPS、MSPT、CPU、メモリなどを、同じ条件で記録する
  2. 原因を特定する: プロファイラーで、どの処理に時間がかかっているかを数字で確かめる
  3. 1 つずつ変える: 変更は 1 度に 1 つにし、何が効いたかを分かるようにする
  4. 同じ条件で測り直す: 変更の前後を同じ人数と内容で比べ、効果を数字で確かめる
  5. 記録する: 測った値、変えた内容、結果を残し、次の判断と、障害のときの調査に使う

/tick query

Java 版 1.20.3 で追加された /tick コマンドでは、/tick query で、目標のティックの頻度、1 回のティックの平均の時間と、P50・P95・P99 (遅いほうから 50%・5%・1% の境目) を確認できます。平均が低くても P99 が高い場合は、時々起きる重さがあります。

spark

Paper には、1.21 から計測のプラグイン spark が組み込まれています (以前の Timings は非推奨になり、既定で無効)。

# TPS と MSPT を確認する
/spark tps

# 300 秒間、メインのスレッドの処理を記録する
/spark profiler start --timeout 300

# 100 ミリ秒を超えたティックだけを記録して、時々起きる重さの原因を探す
/spark profiler start --only-ticks-over 100 --timeout 300

# すべてのスレッドを記録する
/spark profiler start --thread * --timeout 300

結果は Web の画面で、処理の呼び出しの流れ、プラグインごとの時間、フレームグラフで確認できます。結果は既定で spark の外部のサーバーにアップロードされ、URL を知っている人なら見られるため、共有する相手に注意します (アップロード先は設定で変えられます)。

Folia: ワールドを分けて並列に計算する

PaperMC の Folia は、メインのスレッドが 1 つという前提そのものを変えたサーバーです。近くの読み込まれたチャンクを「リージョン」にまとめ、リージョンごとに 20 TPS のティックを、複数のスレッドで並列に計算します。Folia のドキュメントは「メインのスレッドはもうない」と説明しています。

Folia は、離れた場所を別々のスレッドで計算する。

Paper読み込まれたチャンクを、すべて 1 つのスレッドで計算

Server thread 1 つ

Folia近くのチャンクをリージョンにまとめ、リージョンごとに並列に計算

リージョンごとのスレッド (図では 3 つ)

色の付いたマスは、プレイヤーのまわりで読み込まれたチャンクです。Folia では、リージョンが近づくとまとまり、離れると分かれます。

1 つのリージョンが重くなっても、ほかのリージョンは遅れません。プレイヤーが広く散らばるサバイバルのサーバーなどに向いています。一方で、次の制約があります。

  • ハードウェア: Folia のドキュメントは、物理コアが 16 以上あることを理想としています
  • プラグイン: plugin.yml に folia-supported: true があるプラグインだけを読み込みます。Folia のドキュメントは、互換性には「期待しないでほしい」と書いています
  • 作りの違い: Bukkit のスケジューラーはメインのスレッドが 1 つという前提のため、リージョン用の専用のスケジューラー (RegionScheduler、EntityScheduler など) に書き換える必要があります
  • 向かない場面: 全員が 1 か所に集まる企画では、1 つのリージョンにまとまるため、並列にならない

Folia の設定の考え方

Folia の README は、ワールドを事前に生成したうえで、スレッドを次のように割り振る目安を示しています。約 330 人が参加したテストのサーバーをもとにした目安で、実際の使われ方を見て調整する必要があるとしています。

  • 通信 (Netty): 200〜300 人あたり約 4 スレッド
  • チャンクの読み書き: 200〜300 人あたり約 3 スレッド
  • チャンクの処理 (事前生成した場合): 200〜300 人あたり約 2 スレッド
  • 残りを、80% を上限にリージョンの計算 (threaded-regions.threads) に割り当てる。プラグインやサーバーが、設定できないスレッドを使うため

導入の前に、最新の情報を確認する

Folia は開発が続いていて、入手の方法や推奨の設定も変わってきました。導入するときは、次の点を、その時点の公式の情報で確認します (2026 年 10 月時点の内容)。

  • 入手の方法: PaperMC の公式サイトで、完成したファイルが配布されている (1.19.4 から 26.3 まで)。以前はソースコードから組み立てる必要があったが、今は公式の配布を使える
  • 向いている規模: プレイヤーが散らばるサーバー (サバイバルや skyblock) で、人数がある程度多い場合に向く。物理コア 16 以上が理想
  • 起動の設定: Java の起動のオプションは、PaperMC の Script Generator で作る。スレッドの割り当ては、上の目安をもとに別に調整する
  • プラグイン: 使うプラグインが Folia に対応しているかを、Modrinth や Hangar の対応の一覧で確かめる。ViaVersion、BlueMap、Chunky、LuckPerms などは対応が示されている (2026 年 10 月 25 日に確認)。Geyser は Folia ではなく Velocity に入れる
  • 効果: Paper との性能の差は、構成とプレイの内容で大きく変わる。自分の企画と同じ条件で計測してから決める

Folia を含めて、サーバーをどう分けるかは、サーバーを分ける構成で説明しています。

参考にした資料

サーバーの重さの原因の調査は、KEY SELECT に

spark での計測と結果の読み解き、メインのスレッドを止めているプラグインや設定の特定、改善の提案まで、KEY SELECT がお引き受けできます。

  • 記事や技術資料の内容についてのご質問とサポートは、保守・サポートのご契約、またはスポットでのご契約をいただいたうえでお受けしています。無償でのサポートは行っておりません。
  • 記事や技術資料の内容は、公開の時点の情報にもとづいて作成しています。内容の正確性、完全性、最新性を保証するものではなく、内容にもとづいて行った作業の結果について、弊社は責任を負いかねます。設定や変更は、ご自身の責任で、検証用の環境で確かめてから行ってください。
  • 記事や技術資料の内容について、ご指摘や誤りにお気づきの点がありましたら、その他のお問い合わせからお知らせください。
  • 技術資料の内容は、引用元として資料の名前と URL を明記していただければ、ご自身の動画や資料としてご利用いただけます。全文の Web サイトでの引用はご遠慮ください。

ご相談・お問い合わせ

内容が固まっていない段階からご相談いただけます。各分野のプロフェッショナルがご対応いたします。ご相談・お見積もりは無料です。