[{"content":"さくらのVPS 2Gプランで、自作の業務システムを3本動かしています。9日間連続稼働、ロードアベレージ0.20、メモリは7割が空いたままです。\n測ってみて、想定外だったことがあります。アプリ3本が使っているのは約166MB。一方で、このサーバーでは働きようがないOSのデーモンが、合計50〜100MBを占めていました。\n自分のアプリより、使う予定のない仕組みのほうが目立つ。プラン変更を考える前に、見るべき場所がありました。\n測定条件 数字を出す記事なので、どういう状態で測ったかを先に書きます。\nサーバー：さくらのVPS 2Gプラン / Ubuntu 24.04 LTS 測定時刻：平日15:57、業務時間内だがアクセスはほぼない状態 稼働日数：9日15時間（無停止） サンプル数：1回（vmstat のみ5秒間） したがって以下の数字はアイドルに近い状態のものです。ピーク時の値ではありません。負荷時の測定は別途行い、追記します。\n動かしている3本 すべて自作の業務システムです。フロントには Caddy を置いています。\nシステム 構成 常駐メモリ(RSS) 反応計測システム FastAPI 0.141.1 / uvicorn 0.52.4 / SQLite 約66MB 基幹システム Python + gunicorn（-w 1 --threads 8 -t 120） 約65MB 仮想待合室 Go（静的リンクの単一バイナリ）/ 設定はJSON 約35MB 3本合計 約166MB Caddy リバースプロキシ / HTTPS 約23MB 3本とも 127.0.0.1 のポートで待ち受けていて、外部に直接は晒していません。Caddyが受けて振り分けています。\n基幹システムは自社の業務用なので、フレームワークやデータ構造の詳細は伏せます。この記事で必要なのはメモリの数字だけなので、そこは支障ありません。\n3本で166MBに収まっている理由 DBサーバーを1台も動かしていないからです。\nsystemctl list-units --type=service --state=running \\ | grep -iE \u0026#34;postgres|mysql|maria|redis|mongo\u0026#34; # → 何も返らない PostgreSQLもMySQLもRedisも入っていません。反応計測システムはSQLiteのファイル1つ（data/dareyomi.db）で動いています。\nMySQLやPostgreSQLを1つ立てるだけで、デフォルト設定なら100〜300MBは持っていかれます。 アプリ3本の合計より重い。「2GBで足りるか」は、アプリの本数ではなくDBサーバーを立てるかどうかで決まる面が大きい、というのが実測から見えたことです。\nもうひとつ効いているのが、gunicornの -w 1 --threads 8 です。ワーカーを増やすとプロセスがまるごと複製されてメモリを食うので、限られたメモリではスレッドで捌く構成が有利になります。\n仮想待合室のGoバイナリが34.7MBでマルチテナントを捌いているのも、数字としては効いています。ランタイムを持たない単一バイナリなので、Pythonの2本と比べて素直に軽い。\nメモリ実測 total used free shared buff/cache available Mem: 1.9Gi 504Mi 362Mi 1.0Mi 1.3Gi 1.4Gi Swap: 0B 0B 0B 15:57:45 up 9 days, 15:58, 1 user, load average: 0.20, 0.34, 0.17 項目 値 意味 total 1.9Gi 2GBプランで実際に使える量 used 504Mi 使用中。全体の約1/4 available 1.4Gi これから使える量。見るべきはここ buff/cache 1.3Gi ディスクキャッシュ。必要になれば解放される free でつまずきやすいところ buff/cache の1.3GiBは「奪われている」わけではありません。Linuxは空きメモリをディスクキャッシュに回し、アプリが必要とすれば解放します。無駄ではなく、働いている状態です。\n見るべきは available。これが「これから何かを載せられる余地」で、今回は1.4GiB。全体の約7割が空いています。\nfree の数字が小さいことを理由に上位プランへ変える前に、まず available を見てください。\nプロセス別の内訳 ps aux --sort=-%mem の上位を、役割ごとに分けました。\n自分のアプリ：約166MB プロセス RSS 反応計測 / uvicorn 66.5MB 基幹システム / gunicorn worker 38.8MB 基幹システム / gunicorn master 25.9MB 仮想待合室 / Goバイナリ 34.7MB 動いていて当然のもの：約74MB プロセス RSS 役割 systemd-journald 24.5MB ログ caddy 23.0MB Webサーバー systemd 13.5MB init systemd-resolved 12.9MB DNS このサーバーでは働きようがないもの ここが今回の発見です。\nプロセス RSS 本来の用途 fwupd 44.0MB 物理デバイスのファームウェア更新 multipathd 26.7MB ストレージへの複数I/Oパスの管理 unattended-upgrade-shutdown 22.2MB 自動更新中のシャットダウン待機 udisksd 13.4MB ディスク・リムーバブルメディアの管理 ModemManager 12.8MB モバイル通信モデムの管理 VPSに物理ファームウェアはありません。モバイル通信のモデムも刺さっていません。USBメモリを挿すこともありません。\n常駐している3つ（multipathd + ModemManager + udisksd）だけで 約53MB。ここに fwupd が起動していると 約97MB になります。\n自作アプリ3本が166MBなので、使う予定のない仕組みが、その3割から6割に相当する量を占めていたことになります。\nmultipathd は本当に何もしていないのか 「不要そう」で終わらせず、確認しました。\nmultipathd の役割について、Ubuntu公式ドキュメントはこう説明しています。マルチパスは「複数の物理的なSAN接続（別々のケーブル、スイッチ、コントローラを含む）を通じて、複数のI/Oパスを集約する仮想デバイスを作成する」ための機能で、冗長性やI/O分散を目的としています。\nつまりストレージへの経路が複数ある環境のための仕組みです。では、このVPSに経路は何本あるのか。\n$ systemctl is-active multipathd active $ ls /dev/mapper/ control $ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sr0 11:0 1 1024M 1 rom vda 253:0 0 100G 0 disk ├─vda1 253:1 0 1M 0 part └─vda2 253:2 0 100G 0 part / multipathd は動いています。しかし /dev/mapper/ にあるのは control だけ ── これはdevice-mapperの制御ノードで、マルチパスの管理対象ではありません。mpath で始まるデバイスは1つもない。\nlsblk を見ても、ディスクは vda が1本だけです。束ねるべき2本目の経路が、そもそも存在しない。\n管理対象ゼロで常駐している、ということが確認できました。\n補足：上記3コマンドは、同じさくらのVPS・Ubuntu 24.04の別の1台で実行したものです。構成は同じですが、厳密には測定対象のサーバーとは別の機体です。\n止める前に、自分の環境で確認してください 「不要だから止めろ」と書くつもりはありません。 環境によって前提が変わります。上の3コマンドを自分のサーバーで叩いて、同じ結果になることを確かめてから判断してください。\nsudo multipath -ll # 何も出なければ、束ねる経路はない systemctl status multipathd ModemManager udisks2 fwupd 止める場合も、1つずつ、間隔を空けて。本番サーバーなら、まず検証用の環境で試してください。\nsudo systemctl disable --now ModemManager # しばらく様子を見る sudo systemctl disable --now udisks2 # しばらく様子を見る sudo systemctl disable --now multipathd fwupd は測定の2分前（15:55）に起動していました。常時この44MBを消費し続けているとは限りません。この記事では「観測時点で起動していた」という事実のみを書いています。\nまた RSS は共有ライブラリを重複して数えるため、各プロセスの単純合計は used と一致しません。プロセス間の大小を比べるための目安として見てください。\nSwapが0だった ── 4台とも SwapTotal: 0 kB SwapFree: 0 kB スワップ領域がありませんでした。そして、これはこのサーバーだけの話ではありません。\nさくらのVPSを4台運用していますが、4台すべてがスワップ0でした。 ログイン時のバナーに出る Swap usage: 0% が、全台で並びます。\nこれは設定漏れではなく、提供側の仕様として説明されています。さくらのVPS公式マニュアル「swapfileの追加」には「一部、スワップパーティションを含まないイメージの提供を行っております」と明記されており、スワップファイルを後から追加する手順も公式に用意されています。\n危険なのか スワップがないということは、メモリを使い切った瞬間にOOM Killerが走り、プロセスが選ばれて強制終了されるということです。緩衝材がない。\nただし、実際に起きているかは別の話です。確認しました。\njournalctl -k | grep -i \u0026#34;killed process\u0026#34; # → 3台とも何も返らない OOM Killerの発動履歴は、どのサーバーにもありませんでした。 メモリ使用率が26〜31%で安定している以上、当然といえば当然です。\nつまり現状は「危険な構成だが、余裕があるので問題が表面化していない」状態です。ディスクは99GB中81GBが空いているので、スワップを置かない理由も特にありません。何かを追加で載せる前には作っておくべきだと考えています。\n2GBで足りる人・足りない人 実測から言えることを整理します。\n足りる 少人数が使う業務システム。今回は3本載せてメモリ使用は約1/4 DBサーバーを立てない（SQLiteやファイルベースで足りる） アクセス数が読める。急なスパイクがない 画像・動画・PDFの重い生成処理がない ワーカーを増やさず、スレッドで捌く構成にできる 足りない可能性が高い 不特定多数が使う公開サービス PostgreSQLやMySQLを立てる サーバー上でビルドやCIを回す（一瞬でメモリが跳ねる） AI系のツールを載せたい 最後の項目が、このサイトの本題です。\nこのサーバーは available 1.4GiB、ロードアベレージ0.20。数字の上では、まだ何かを載せる余地があります。 ただし n8n や Dify のような自動化ツールは、Docker・データベース・ワーカーがセットで付いてきます。166MBで動いている自作アプリとは要求される桁が違うはずですが、それは実際に載せてみないとわかりません。\n次の記事で、実際に測ります。\nまとめ さくらVPS 2Gで自作システム3本：使用504MB / 空き1.4GiB / ロードアベレージ0.20、9日間無停止 アプリ3本の実使用は約166MB。2GBは思ったより余裕がある 収まっている最大の理由はDBサーバーを立てていないこと このサーバーでは働きようがないデーモンが53〜97MBを占めていた。プラン変更の前に、まずここを見る multipathd は動いているが、管理対象はlsblkと/dev/mapper/で確認する限りゼロ free は used ではなく available を見る 4台すべてスワップ0。さくらのVPSではスワップなしのイメージが提供される場合があり、公式に追加手順が用意されている スワップなしだが、OOM Killerの発動履歴は3台とも無し 参考 さくらのVPS マニュアル「swapfileの追加」 Ubuntu Server Documentation「Introduction to device mapper multipathing」 ","permalink":"https://jimae-ai.com/sakura-vps-2gb-memory/","summary":"\u003cp\u003eさくらのVPS 2Gプランで、自作の業務システムを3本動かしています。9日間連続稼働、ロードアベレージ0.20、メモリは\u003cstrong\u003e7割が空いたまま\u003c/strong\u003eです。\u003c/p\u003e\n\u003cp\u003e測ってみて、想定外だったことがあります。\u003cstrong\u003eアプリ3本が使っているのは約166MB。一方で、このサーバーでは働きようがないOSのデーモンが、合計50〜100MBを占めていました。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e自分のアプリより、使う予定のない仕組みのほうが目立つ。プラン変更を考える前に、見るべき場所がありました。\u003c/p\u003e\n\u003ch2 id=\"測定条件\"\u003e測定条件\u003c/h2\u003e\n\u003cp\u003e数字を出す記事なので、どういう状態で測ったかを先に書きます。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eサーバー\u003c/strong\u003e：さくらのVPS 2Gプラン / Ubuntu 24.04 LTS\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e測定時刻\u003c/strong\u003e：平日15:57、業務時間内だがアクセスはほぼない状態\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e稼働日数\u003c/strong\u003e：9日15時間（無停止）\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eサンプル数\u003c/strong\u003e：1回（\u003ccode\u003evmstat\u003c/code\u003e のみ5秒間）\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eしたがって以下の数字は\u003cstrong\u003eアイドルに近い状態のもの\u003c/strong\u003eです。ピーク時の値ではありません。負荷時の測定は別途行い、追記します。\u003c/p\u003e\n\u003ch2 id=\"動かしている3本\"\u003e動かしている3本\u003c/h2\u003e\n\u003cp\u003eすべて自作の業務システムです。フロントには Caddy を置いています。\u003c/p\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003eシステム\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e構成\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e常駐メモリ(RSS)\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e反応計測システム\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eFastAPI 0.141.1 / uvicorn 0.52.4 / \u003cstrong\u003eSQLite\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e約66MB\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e基幹システム\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003ePython + gunicorn（\u003ccode\u003e-w 1 --threads 8 -t 120\u003c/code\u003e）\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e約65MB\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e仮想待合室\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eGo\u003c/strong\u003e（静的リンクの単一バイナリ）/ 設定はJSON\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e約35MB\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003e3本合計\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003e約166MB\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eCaddy\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eリバースプロキシ / HTTPS\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e約23MB\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003e3本とも \u003ccode\u003e127.0.0.1\u003c/code\u003e のポートで待ち受けていて、外部に直接は晒していません。Caddyが受けて振り分けています。\u003c/p\u003e\n\u003cp\u003e基幹システムは自社の業務用なので、フレームワークやデータ構造の詳細は伏せます。\u003cstrong\u003eこの記事で必要なのはメモリの数字だけ\u003c/strong\u003eなので、そこは支障ありません。\u003c/p\u003e\n\u003ch3 id=\"3本で166mbに収まっている理由\"\u003e3本で166MBに収まっている理由\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003eDBサーバーを1台も動かしていないから\u003c/strong\u003eです。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esystemctl list-units --type\u003cspan class=\"o\"\u003e=\u003c/span\u003eservice --state\u003cspan class=\"o\"\u003e=\u003c/span\u003erunning \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e|\u003c/span\u003e grep -iE \u003cspan class=\"s2\"\u003e\u0026#34;postgres|mysql|maria|redis|mongo\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# → 何も返らない\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003ePostgreSQLもMySQLもRedisも入っていません。反応計測システムはSQLiteのファイル1つ（\u003ccode\u003edata/dareyomi.db\u003c/code\u003e）で動いています。\u003c/p\u003e","title":"さくらのVPS 2GBで自作システムを3本動かしている｜実測したら、要らないプロセスがアプリより食っていた"}]