可用性とは?稼働率の計算と高可用性の作り方をコマンドで解説

実務レシピ

可用性(かようせい)とは、システムやサービスが「使いたいときに使える」状態を保てているかどうかを表す性質です。英語ではAvailability(アベイラビリティ)といい、実務では稼働率というパーセンテージで数値化して扱います。言葉の説明だけでは自分のサーバーが高いのか低いのか判断できないので、この記事ではUbuntu 24.04(systemd 255)で実際にコマンドを実行しながら解説します。まずは、いま動いているサーバーが何日連続で稼働しているかを確認してみてください。

uptime -p
up 20 hours, 37 minutes

この記事では、可用性の定義と情報セキュリティにおける位置づけ、稼働率の計算方法、そして自分のサーバーの稼働率を実際にコマンドで測る手順可用性を上げる具体的な設定までを、すべて実行結果つきでまとめます。

  1. 可用性とは|必要なときに使える状態を保つ性質
    1. 情報セキュリティの3要素(CIA)における可用性
    2. 信頼性・保守性との違い(RASIS)
  2. 可用性は「稼働率」で数値化する
    1. 稼働率の計算式とMTBF・MTTR
    2. 「99.9%」は年間どれだけ止まってよいのか
    3. 直列と並列で稼働率はこう変わる
    4. SLA・SLOとの関係
  3. 自分のサーバーの可用性をコマンドで測る
    1. uptime|いま何時間連続で動いているか
    2. journalctl –list-boots|過去の停止時間を洗い出す
    3. 稼働率・MTBF・MTTRをまとめて算出するスクリプト
    4. 測定するときの3つの注意点
  4. サービス単位の可用性を確認する
    1. systemctl is-active|終了ステータスで判定する
    2. NRestarts|再起動を繰り返しているサービスを見つける
    3. 主要サービスをまとめて確認するスクリプト
  5. 可用性を上げる4つの方法(実行例つき)
    1. ①プロセスの自動復旧を設定する
    2. 自動復旧のテストでハマる2つの罠
    3. ②冗長化とロードバランサを組む
    4. ③冗長化の効果を実測して比較する
    5. ④MTTRを縮める(バックアップと復旧手順)
  6. 外形監視で可用性を継続的に測る
  7. 可用性を落とす典型パターンと初動
  8. よくある質問
    1. 可用性と信頼性はどう違いますか?
    2. 稼働率100%は実現できますか?
    3. 冗長化すれば必ず可用性は上がりますか?
    4. 99.9%と99.99%では何が違いますか?
    5. 自分のサーバーの稼働率はどうやって測ればよいですか?
    6. 高可用性(HA)とは何を指しますか?
  9. まとめ
  10. 関連記事
  11. 関連記事

可用性とは|必要なときに使える状態を保つ性質

情報セキュリティの国際規格ISO/IEC 27000(JIS Q 27000)では、可用性を「認可されたエンティティが要求したときに、アクセス及び使用が可能である特性」と定義しています。かみくだくと「使う権利のある人が、使いたいと思ったときに、実際に使える」ということです。

ポイントは、可用性が利用者から見た結果で判断されることです。サーバーが1台壊れていても、利用者が普通にサイトを見られていれば可用性は保たれています。逆にサーバーが全台起動していても、アプリケーションが応答を返せなければ可用性は失われています。「機械が動いているか」ではなく「サービスが提供できているか」で測る、と覚えてください。

情報セキュリティの3要素(CIA)における可用性

可用性は、情報セキュリティの3要素のひとつです。3つの頭文字を取ってCIAと呼ばれます。

要素英語意味失われるとどうなるか
機密性Confidentiality権限のない人に情報を見せない情報漏えい
完全性Integrity情報が正確で改ざんされていないデータ改ざん、内容の破損
可用性Availability必要なときに使えるサービス停止、業務が止まる

この3つはしばしば互いに衝突します。たとえばセキュリティを理由にサーバーを止めてしまえば機密性は守られますが、可用性はゼロになります。逆に、可用性を優先してファイアウォールを緩めれば機密性が下がります。実務で可用性を語るときは「どこまで止まってよいか」を先に決め、そのうえで他の要素とのバランスを取ることになります。

信頼性・保守性との違い(RASIS)

可用性と混同されやすいのが信頼性です。両者を含めた5つの評価軸をRASISと呼びます。

頭文字評価軸意味代表的な指標
RReliability(信頼性)そもそも壊れにくいかMTBF(平均故障間隔)
AAvailability(可用性)使いたいときに使えるか稼働率(%)
SServiceability(保守性)壊れたとき早く直せるかMTTR(平均修復時間)
IIntegrity(完全性)データが壊れず正確かチェックサム、整合性検査
SSecurity(機密性)不正アクセスを防げるか権限設定、暗号化

違いをひとことで言うと、信頼性は「壊れにくさ」、保守性は「直しやすさ」、可用性はその2つの結果として得られる「使える割合」です。だから可用性を上げる道は2本あります。壊れにくくする(信頼性を上げる)か、壊れてもすぐ復旧する(保守性を上げる)か。壊れにくい高価な機器を1台買うより、そこそこの機器を2台並べて自動で切り替えるほうが可用性が高くなるのは、この関係のためです。

可用性は「稼働率」で数値化する

可用性は感覚ではなく数値で管理します。使う指標が稼働率(アベイラビリティ)で、「使えるべき時間のうち、実際に使えていた時間の割合」を表します。

稼働率の計算式とMTBF・MTTR

稼働率 = 稼働していた時間 / (稼働していた時間 + 停止していた時間)

別の書き方(信頼性・保守性から求める場合)
稼働率 = MTBF / (MTBF + MTTR)
  • MTBF(Mean Time Between Failures/平均故障間隔)= 障害が起きてから次に起きるまでの平均時間。長いほど壊れにくい
  • MTTR(Mean Time To Repair/平均修復時間)= 障害発生から復旧までにかかる平均時間。短いほど直しやすい

実際に計算してみます。30日(720時間)に1回止まり、毎回1時間で復旧するサーバーの稼働率は次のとおりです。

awk 'BEGIN{ m=720; r=1; printf "稼働率 %.4f%%\n", m/(m+r)*100 }'
稼働率 99.8613%

ここで重要なのは、MTTRを短くするだけでも稼働率は上がるという点です。同じ「30日に1回止まる」サーバーでも、復旧が1時間なら99.86%、10分なら99.977%になります。壊れる回数を減らすのが難しくても、復旧手順を整えるだけで可用性は改善できます。

「99.9%」は年間どれだけ止まってよいのか

クラウドの契約書などで見かける「99.9%」「99.99%」といった数値は、ナイン(9の数)と呼ばれます。この数値が許容する停止時間を計算してみましょう。

awk 'BEGIN{
  n=split("99,99.5,99.9,99.95,99.99,99.999",a,",")
  for(i=1;i<=n;i++){
    f=(100-a[i])/100
    printf "%-8s 年間 %-10s 月間 %-9s 週間 %s\n", a[i]"%", \
      fmt(365*86400*f), fmt(30*86400*f), fmt(7*86400*f)
  }
}
function fmt(s){
  if(s>=86400) return sprintf("%.2f日",s/86400)
  if(s>=3600)  return sprintf("%.2f時間",s/3600)
  if(s>=60)    return sprintf("%.1f分",s/60)
  return sprintf("%.1f秒",s)
}'
99%      年間 3.65日      月間 7.20時間   週間 1.68時間
99.5%    年間 1.82日      月間 3.60時間   週間 50.4分
99.9%    年間 8.76時間    月間 43.2分     週間 10.1分
99.95%   年間 4.38時間    月間 21.6分     週間 5.0分
99.99%   年間 52.6分      月間 4.3分      週間 1.0分
99.999%  年間 5.3分       月間 25.9秒     週間 6.0秒

この表を見ると感覚がつかめます。99.9%は「月に1回、40分ほどのメンテナンス停止が許される」水準で、一般的なWebサービスの現実的な目標です。一方99.99%になると月4分しか止められません。OSのセキュリティアップデートで再起動すれば、それだけで月間の予算を使い切ります。9をひとつ増やすたびに許容停止時間は10分の1になり、必要な設備と手間は跳ね上がる、という関係を押さえておいてください。

直列と並列で稼働率はこう変わる

システムは複数の部品でできています。「全部が動かないとサービスが成立しない」構成を直列、「どれか1つ動けば成立する」構成を並列(冗長構成)と呼び、全体の稼働率の計算方法が変わります。

直列(両方必要): 全体 = A1 × A2
並列(冗長化)  : 全体 = 1 - (1 - A1) × (1 - A2)
awk 'BEGIN{
  a=0.99
  printf "直列 99%% × 99%%   = %.4f%%\n", a*a*100
  printf "並列 99%% × 99%%   = %.4f%%\n", (1-(1-a)*(1-a))*100
  c=0.999
  printf "直列 99.9%% を5段 = %.4f%%\n", (c^5)*100
  printf "並列 99.9%% × 2   = %.6f%%\n", (1-(1-c)*(1-c))*100
}'
直列 99% × 99%   = 98.0100%
並列 99% × 99%   = 99.9900%
直列 99.9% を5段 = 99.5010%
並列 99.9% × 2   = 99.999900%

ここに可用性設計の本質が出ています。直列に部品を増やすと稼働率は下がり、並列に増やすと上がるのです。99.9%の部品でも5つ直列に並べれば全体は99.5%まで落ちます。「Webサーバー、DB、DNS、ロードバランサ、ネットワーク回線」のように依存が積み上がるほど不利になるので、止まると全体が死ぬ箇所(単一障害点/SPOF)を見つけて、そこだけ並列にするのが基本方針になります。

SLA・SLOとの関係

クラウドやレンタルサーバーの契約に出てくるSLA(Service Level Agreement/サービス品質保証)は、事業者が利用者に対して「この水準を保証します」と約束する文書で、その中身の中心が可用性(稼働率)です。似た用語との違いは次のとおりです。

用語正式名性格下回ったとき
SLAService Level Agreement事業者と利用者の契約上の約束返金や利用料減額などのペナルティ
SLOService Level Objective運用チームが内部で置く目標値改善アクションのトリガー
SLIService Level Indicator実際に測る指標そのもの(測定値なので該当なし)

注意したいのは、SLAの稼働率は「事業者が用意したインフラの稼働率」であって、あなたのサービス全体の稼働率ではない点です。SLA 99.99%のクラウドを使っていても、その上のアプリケーションが落ちれば利用者から見た可用性は落ちます。また、SLA違反時の補償は「その月の利用料の数%返金」といった規模が一般的で、機会損失を埋めるものではありません。自分で測る指標(SLI)を持つことが結局は必要になります。

自分のサーバーの可用性をコマンドで測る

ここからが本題です。可用性の説明はどこにでもありますが、「自分のサーバーの稼働率は今いくつなのか」は自分で測らないと分かりません。Linuxには測定に使える情報が最初から入っています。

uptime|いま何時間連続で動いているか

まずは現在の連続稼働時間です。

uptime
 05:53:01 up 20:37,  3 users,  load average: 0.04, 0.01, 0.00

左から現在時刻、連続稼働時間(20時間37分)、ログイン中のユーザー数、直近1分・5分・15分の平均負荷です。読みやすい形式や、起動した時刻そのものを見たい場合はオプションを使います。

uptime -p    # pretty形式
uptime -s    # 起動した日時
who -b       # 同じく起動時刻(whoコマンド版)
up 20 hours, 37 minutes
2026-08-01 09:15:32
         system boot  2026-08-01 09:15

ただしuptimeで分かるのは「今回の起動から今まで」だけです。稼働率を出すには、過去に何回・何時間止まったかが必要になります。

journalctl –list-boots|過去の停止時間を洗い出す

systemdを使っているディストリビューションなら、過去の起動履歴が記録されています。

journalctl --list-boots
IDX BOOT ID                          FIRST ENTRY                 LAST ENTRY
 -3 68b9ec2e617b40ccba7103479febaf75 Tue 2026-06-23 09:04:38 UTC Sun 2026-07-19 05:04:21 UTC
 -2 86b924ab32fd4055a692cad4ffd22484 Sun 2026-07-19 05:04:44 UTC Tue 2026-07-21 06:47:19 UTC
 -1 f81921b444f94e6e977803901280355f Tue 2026-07-21 06:47:42 UTC Sat 2026-08-01 09:11:32 UTC
  0 a1b05afde1e549908068415be4cc935d Sat 2026-08-01 09:15:36 UTC Sun 2026-08-02 05:53:01 UTC

IDXが起動の通し番号(0が現在)、FIRST ENTRYがその起動でログを書き始めた時刻、LAST ENTRYが最後にログを書いた時刻です。ある行のLAST ENTRYと次の行のFIRST ENTRYの差が、そのときのダウンタイムになります。上の例なら、IDX -1の終了(08-01 09:11:32)からIDX 0の開始(08-01 09:15:36)まで244秒=約4分停止していたと読み取れます。

全期間ぶんをまとめて出すには、次のように差分を計算します。

journalctl --list-boots --no-pager | awk '$1 ~ /^-?[0-9]+$/ {
  cmd = "date -u -d \"" $4" "$5 "\" +%s"; cmd | getline s; close(cmd)
  if (prev != "") printf "停止 %6d 秒  (%s → %s)\n", s-prev, prev_s, $4" "$5
  cmd2 = "date -u -d \"" $8" "$9 "\" +%s"; cmd2 | getline prev; close(cmd2)
  prev_s = $8" "$9
}'
停止     22 秒  (2026-05-12 06:02:07 → 2026-05-12 06:02:29)
停止     22 秒  (2026-05-30 08:27:27 → 2026-05-30 08:27:49)
停止     22 秒  (2026-06-14 08:51:01 → 2026-06-14 08:51:23)
停止     22 秒  (2026-06-23 09:04:16 → 2026-06-23 09:04:38)
停止     23 秒  (2026-07-19 05:04:21 → 2026-07-19 05:04:44)
停止     23 秒  (2026-07-21 06:47:19 → 2026-07-21 06:47:42)
停止    244 秒  (2026-08-01 09:11:32 → 2026-08-01 09:15:36)

通常の再起動は22〜23秒で終わっているのに、最後の1回だけ244秒かかっています。こうした「いつもより長い停止」がそのまま調査対象になります。カーネル更新なのか、fsckが走ったのか、電源断だったのか、その時間帯のjournalctl -b -1 -eを見れば追跡できます。

稼働率・MTBF・MTTRをまとめて算出するスクリプト

ここまでを1本にまとめると、サーバー本体の稼働率がそのまま出せます。

#!/bin/bash
# uptime-rate.sh - journalctlの起動記録から稼働率・MTBF・MTTRを算出する
journalctl --list-boots --no-pager | awk '
$1 ~ /^-?[0-9]+$/ {
  cmd1 = "date -u -d \"" $4" "$5 "\" +%s"; cmd1 | getline s; close(cmd1)
  cmd2 = "date -u -d \"" $8" "$9 "\" +%s"; cmd2 | getline e; close(cmd2)
  up += e - s
  if (prev_end != "") { down += s - prev_end; n++ }
  prev_end = e
}
END {
  total = up + down
  printf "起動していた合計   : %.2f 時間\n", up/3600
  printf "停止していた合計   : %.2f 時間\n", down/3600
  printf "停止回数           : %d 回\n", n
  printf "稼働率             : %.4f %%\n", up*100/total
  printf "MTBF(平均故障間隔) : %.2f 時間\n", up/n/3600
  printf "MTTR(平均復旧時間) : %.2f 分\n", down/n/60
}'
bash uptime-rate.sh
起動していた合計   : 2099.13 時間
停止していた合計   : 233.26 時間
停止回数           : 15 回
稼働率             : 89.9992 %
MTBF(平均故障間隔) : 139.94 時間
MTTR(平均復旧時間) : 933.03 分

実行したのは毎晩電源を切る開発マシンなので、稼働率は89.99%。24時間動かすサーバーなら99%台が出ます。数値そのものより、MTTRが933分(約15.5時間)=「夜落として翌朝つける」という運用が可用性を決めていると読めることが重要です。自分の環境で走らせて、MTBFとMTTRのどちらが足を引っ張っているかを確認してみてください。

測定するときの3つの注意点

この方法には、知らないと数値を読み違える落とし穴があります。

  1. LAST ENTRYはシャットダウン完了時刻ではない。journalが最後にログを書いた時刻なので、実際の電源断はもう少し後です。つまりこの計算のダウンタイムはわずかに長めに出ます。傾向を見るには十分ですが、SLA報告にそのまま使う数値ではありません。
  2. 永続journalが有効でないと過去の起動が残らない/var/log/journalディレクトリが存在するか確認してください。無い場合はログがメモリ上(/run/log/journal)に置かれ、再起動で消えるため--list-bootsに現在の起動しか出ません。/etc/systemd/journald.confStorage=persistentを設定しsudo systemctl restart systemd-journaldで有効化します。
  3. last rebootは当てにならない場合がある。異常終了だと終了記録(wtmp)が書かれず、下のように過去の起動までstill runningと表示されます。停止時間の算出にはjournalctl --list-bootsを使ってください。
last reboot | head -3
reboot   system boot  6.8.0-136-generi Sat Aug  1 09:15   still running
reboot   system boot  6.8.0-136-generi Tue Jul 21 06:47   still running
reboot   system boot  6.8.0-136-generi Sun Jul 19 05:04 - 06:47 (2+01:42)

2行目はすでに終了している起動なのにstill runningのままです。この行だけを信じると停止時間を見落とします。

サービス単位の可用性を確認する

サーバーが起動していても、Webサーバーやデータベースが落ちていれば利用者から見た可用性はゼロです。サービス単位の状態も押さえておきます。

systemctl is-active|終了ステータスで判定する

systemctl is-active cron; echo "exit=$?"
systemctl is-active apt-daily.service; echo "exit=$?"
systemctl is-active no-such.service; echo "exit=$?"
active
exit=0
inactive
exit=3
inactive
exit=4

注目したいのは3番目のケースです。存在しないサービス名を渡しても表示はinactiveで、目視では停止中と区別がつきません。区別できるのは終了ステータスだけで、停止中は3、ユニット自体が無い場合は4が返ります。監視スクリプトでサービス名を打ち間違えると「ずっとinactiveだが異常なし」という見落としが起きるので、終了ステータスで判定するのが安全です。終了ステータスの扱いは終了コード設計|失敗の定義と伝播でまとめています。

NRestarts|再起動を繰り返しているサービスを見つける

「動いている」ように見えて、実は落ちては再起動を繰り返している(フラッピング)ケースがあります。systemdは再起動回数を数えているので、これを見れば分かります。

for u in $(systemctl list-units --type=service --state=running --no-legend --plain | awk '{print $1}'); do
  printf '%-32s %s\n' "$u" "$(systemctl show "$u" -p NRestarts --value)"
done | sort -k2 -rn | head
avahi-daemon.service             0
containerd.service               0
cron.service                     0
dbus.service                     0
docker.service                   0
mariadb.service                  0

すべて0なら健全です。ここに大きな数字が出ているサービスは、自動復旧の陰で障害が隠れている状態です。あわせて失敗したユニットも確認しておきます。

systemctl list-units --failed
  UNIT LOAD ACTIVE SUB DESCRIPTION

0 loaded units listed.

systemctlの基本操作はsystemctlコマンドの使い方|起動・停止・自動起動を今すぐ確認を参照してください。

主要サービスをまとめて確認するスクリプト

#!/bin/bash
# check-services.sh - 監視対象サービスが動いているかまとめて確認する
services="ssh cron docker nginx postgresql"
ng=0
for s in $services; do
  if systemctl is-active --quiet "$s"; then
    printf '[OK]   %s\n' "$s"
  else
    printf '[DOWN] %s (%s)\n' "$s" "$(systemctl is-active "$s")"
    ng=$((ng+1))
  fi
done
echo "----"
echo "停止中: ${ng} 件"
exit $(( ng > 0 ))
bash check-services.sh; echo "終了ステータス=$?"
[OK]   ssh
[OK]   cron
[OK]   docker
[OK]   nginx
[DOWN] postgresql (inactive)
----
停止中: 1 件
終了ステータス=1

停止が1件でもあれば終了ステータス1を返すので、そのままcronに登録して失敗時だけメール通知させられます。cronの設定はcronの設定方法|crontabの書き方・オプション・実行例を解説にまとめています。

可用性を上げる4つの方法(実行例つき)

現状が測れたら、次は改善です。可用性を上げる手段は大きく4つあります。

①プロセスの自動復旧を設定する

もっとも費用がかからず効果が大きいのが自動復旧です。落ちたら勝手に起き上がるようにするだけで、MTTRが「人が気づいて対応するまでの時間」から「数秒」に縮みます。

systemdなら、ユニットファイルにRestart=を書きます。実際にDockerのユニットがどう設定されているか見てみましょう。

systemctl cat docker.service | grep -E 'Restart|StartLimit'
StartLimitBurst=3
StartLimitIntervalSec=60
RestartSec=2
Restart=always
設定意味
Restart=always正常終了・異常終了を問わず常に再起動する
Restart=on-failure異常終了(終了ステータスが0以外)のときだけ再起動する
RestartSec=2再起動までの待ち時間(秒)
StartLimitBurst=3 / StartLimitIntervalSec=6060秒間に3回失敗したら諦める。無限ループ防止の安全弁

StartLimitに引っかかると自動復旧は止まります。「Restart=alwaysにしたのに復旧していない」ときは、まずここを疑ってsystemctl reset-failed サービス名でカウンタをクリアしてください。

Dockerコンテナなら--restartで同じことができます。5秒後に異常終了するコンテナで動きを確認します。

docker run -d --name crash-demo --restart=always alpine sh -c 'sleep 5; exit 1'
sleep 25
docker inspect -f 'RestartCount={{.RestartCount}} Status={{.State.Status}}' crash-demo
RestartCount=4 Status=running

25秒の間に4回復旧しています。RestartCountは、systemdのNRestartsと同じく障害が隠れていないかを確認する指標として使えます。Docker全般の基礎はDockerとは?初心者向け完全ガイドにまとめています。

自動復旧のテストでハマる2つの罠

「自動復旧を設定したので動作確認しよう」としてつまずくパターンが2つあります。どちらも実際に試して確認しました。

罠1:docker killでは再起動しない。 手動での停止操作は「意図した停止」として扱われ、再起動ポリシーの対象外になります。

docker run -d --name kill-test --restart=always alpine sleep 600
docker kill kill-test
sleep 12
docker inspect -f 'RestartCount={{.RestartCount}} Status={{.State.Status}}' kill-test
RestartCount=0 Status=exited

12秒待ってもexitedのままです(Docker 29.6.2で確認)。設定は正しいのに「復旧しない」と誤診しがちなので、テストはコンテナ内のプロセス自身が落ちる状況で行ってください。

罠2:コンテナの中からkill -9 1しても死なない。 PID名前空間の中のPID 1は特別扱いで、同じ名前空間内から送られたシグナルは、そのプロセスがハンドラを持っていない限り無視されます。

docker exec ha-demo sh -c 'kill -9 1'
docker inspect -f 'RestartCount={{.RestartCount}} Status={{.State.Status}}' ha-demo
RestartCount=0 Status=running

SIGKILLを送ったのにrunningのままです。これはLinuxの仕様であって障害ではありません。

②冗長化とロードバランサを組む

自動復旧は「落ちてから戻るまで」を短くする対策で、その間はやはり止まっています。止まった瞬間も利用者に見せないためには、同じ役割のサーバーを複数用意して振り分ける必要があります。これが冗長化です。

Dockerで2台構成を作ります。バックエンド2台と、その前段のnginxロードバランサです。

docker network create hanet
docker run -d --name web1 --network hanet nginx:alpine
docker run -d --name web2 --network hanet nginx:alpine
docker exec web1 sh -c 'echo web1 > /usr/share/nginx/html/index.html'
docker exec web2 sh -c 'echo web2 > /usr/share/nginx/html/index.html'

ロードバランサ側の設定です。max_failsfail_timeoutで「失敗したバックエンドを一時的に外す」動きを、proxy_next_upstreamで「失敗したら別のバックエンドに投げ直す」動きを指定します。

upstream backend {
    server web1:80 max_fails=1 fail_timeout=5s;
    server web2:80 max_fails=1 fail_timeout=5s;
}
server {
    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_next_upstream error timeout http_502 http_503 http_504;
        proxy_connect_timeout 1s;
    }
}
docker run -d --name lb --network hanet -p 18080:80 \
  -v /tmp/hademo/lb.conf:/etc/nginx/conf.d/default.conf:ro nginx:alpine
for i in $(seq 8); do curl -s http://localhost:18080/; done
web1
web1
web2
web1
web2
web1
web2
web1

2台に振り分けられています。この状態で片方を落とすとどうなるかが本番です。

③冗長化の効果を実測して比較する

1秒おきにアクセスして稼働率を測るスクリプトを用意します。

#!/bin/bash
# measure.sh - URLを1秒間隔でN回叩き、稼働率と最長連続失敗を出す
url=$1; n=${2:-30}
ok=0; ng=0; run=0; maxrun=0
for i in $(seq "$n"); do
  if curl -s -o /dev/null -m 2 -w '%{http_code}' "$url" | grep -q '^2'; then
    ok=$((ok+1)); run=0
  else
    ng=$((ng+1)); run=$((run+1)); [ "$run" -gt "$maxrun" ] && maxrun=$run
  fi
  sleep 1
done
awk -v ok="$ok" -v ng="$ng" -v m="$maxrun" 'BEGIN{
  t=ok+ng
  printf "成功 %d / 失敗 %d / 計 %d\n稼働率 %.2f%%\n最長連続失敗 %d 秒\n", ok, ng, t, ok*100/t, m
}'

まず冗長化あり(2台構成)で測りながら、途中でweb1を停止します。

( ./measure.sh http://localhost:18080/ 20 > result.txt ) &
sleep 5; docker stop web1     # 測定開始5秒後に1台落とす
wait; cat result.txt
成功 20 / 失敗 0 / 計 20
稼働率 100.00%
最長連続失敗 0 秒

サーバーが1台落ちたにもかかわらず、利用者から見た稼働率は100%です。次に、まったく同じ障害を冗長化なし(web1のみを見る構成)で起こしてみます。

( ./measure.sh http://localhost:18081/ 20 > result2.txt ) &
sleep 5;  docker stop web1    # 5秒後に停止
sleep 8;  docker start web1   # 13秒後に復旧
wait; cat result2.txt
成功 15 / 失敗 5 / 計 20
稼働率 75.00%
最長連続失敗 5 秒

同じ「web1が停止する」という障害でも、構成次第で稼働率は100%と75%に分かれます。 これが可用性の正体です。可用性とは機器の丈夫さではなく、障害が起きたときに利用者に届く影響をどれだけ小さくできるかという設計の話だと分かります。

ただし忘れてはいけない点があります。この構成ではロードバランサ自体が単一障害点(SPOF)です。lbコンテナを落とせば、バックエンドが何台生きていても稼働率は0%になります。本番ではロードバランサもVRRP(keepalived)などで冗長化するか、クラウドのマネージドなロードバランサを使うことになります。冗長化は「一番弱い1点」を潰す作業で、そこを外すと台数を増やしても効果が出ません。

④MTTRを縮める(バックアップと復旧手順)

冗長化してもデータが壊れれば全台が同時に壊れます。レプリケーションは「削除」も正しく複製してしまうため、バックアップの代わりにはなりません。実際にMySQLで測ると、誤って実行したDELETE8ミリ秒でレプリカ側にも伝わります(レプリケーションとは?バックアップとの違いをMySQLの実測で解説)。可用性の観点でバックアップを見るときに大事なのは、次の2点です。

  • 復元にかかる時間がそのままMTTRになる。バックアップの取得時間ではなく、戻す時間を測っておく
  • 復元テストをしていないバックアップは存在しないのと同じ。取れているつもりで中身が空、という事故が最も多い

起動そのものが遅ければ復旧も遅くなるので、起動時間も測っておくと改善点が見えます。

systemd-analyze
systemd-analyze blame | head -5
Startup finished in 10.325s (firmware) + 6.792s (loader) + 2.841s (kernel) + 15.301s (userspace) = 35.261s
graphical.target reached after 15.273s in userspace.

41.195s apt-daily.service
 7.837s systemd-networkd-wait-online.service
 5.675s docker.service
 2.110s valet-dns.service
 1.639s fwupd.service

systemd-networkd-wait-online.serviceが7.8秒かかっています。ネットワーク待ちで起動が伸びるのはよくあるパターンで、必要のない環境では無効化することで復旧が数秒早くなります。世代管理つきのバックアップと復元テストの手順は定期バックアップ講座|rsync×世代管理×復元テストにまとめています。

外形監視で可用性を継続的に測る

可用性は一度測って終わりではなく、継続して記録しないと意味がありません。利用者と同じ経路でアクセスして結果を残す「外形監視」を、シェルスクリプトだけで始められます。

#!/bin/bash
# watch.sh - URLを5秒おきに叩いてHTTPステータスをログに残す
url=$1
while :; do
  code=$(curl -s -o /dev/null -m 3 -w '%{http_code}' "$url")
  printf '%s %s %s\n' "$(date '+%F %T')" "$url" "$code"
  sleep 5
done
./watch.sh http://localhost:18080/ | tee -a uptime.log
2026-08-02 05:59:45 http://localhost:18080/ 200
2026-08-02 05:59:50 http://localhost:18080/ 200
2026-08-02 05:59:55 http://localhost:18080/ 200

ログが溜まったら、そのまま稼働率として集計できます。

awk '{t++; if($NF ~ /^2/) ok++} END{printf "%d/%d 稼働率 %.2f%%\n", ok, t, ok*100/t}' uptime.log
3/3 稼働率 100.00%

ポイントはcurlに必ず-m(タイムアウト)を付けることです。指定しないとサーバーが応答を返さないときにcurlが延々と待ち続け、測定間隔が崩れてダウンタイムを正しく数えられません。また、監視対象と同じサーバーで動かすと、そのサーバーごと落ちたときに監視も止まります。可能なら別のマシンから実行してください。

可用性を落とす典型パターンと初動

実際にサービスが止まる原因は、派手なハードウェア故障よりも地味な運用ミスが大半です。よくあるパターンと、最初に打つ手をまとめます。

原因症状最初に確認するコマンド
ディスク満杯書き込みエラー、DBが起動しない、ログが止まるdf -h / du -sh /var/log/*
メモリ不足(OOM)プロセスが突然消えるjournalctl -k | grep -i oom
証明書の期限切れある日突然HTTPSだけ繋がらないopenssl s_client -connect ホスト:443 2>/dev/null | openssl x509 -noout -dates
DNSの障害・設定ミスサーバーは生きているが名前解決できないdig ドメイン名 / getent hosts ドメイン名
単一障害点(SPOF)1台の障害で全体が停止構成図で「1つしかない箇所」を洗い出す
設定変更の反映漏れ再起動した瞬間に落ちるnginx -t などの構文チェック、systemctl is-enabled

特に多いのがディスク満杯です。ログが肥大してディスクを食い潰すと、データベースもアプリケーションも一斉に書き込みに失敗します。しかも削除したのにディスクが空かない(deletedハンドル)という罠があり、対処法はディスク逼迫の初動対応|ログ肥大と「deletedハンドル」を最短で片づける実務手順にまとめています。DNSが疑わしい場合はDNSサーバーとは?仕組み・種類・確認方法をコマンドで解説を参照してください。

また、可用性を落とす最大の要因がデプロイ作業であることも珍しくありません。リリース直後の確認手順はデプロイ後の初動チェック|Bashで5分で回す安全確認リストにまとめています。

よくある質問

可用性と信頼性はどう違いますか?

信頼性は「壊れにくさ」、可用性は「使える割合」です。指標でいうと信頼性はMTBF、可用性は稼働率で表します。年に1回しか壊れないが直すのに1週間かかるサーバー(信頼性は高いが可用性は低い)と、月に1回落ちるが10秒で自動復旧するサーバー(信頼性は低いが可用性は高い)を比べると、稼働率は後者のほうが上になります。

稼働率100%は実現できますか?

測定期間を区切れば100%になることはありますが、恒久的な保証はできません。OSやミドルウェアのアップデート、ハードウェアの寿命、電源や回線といった自分の管理外の要素が必ず存在するためです。事業者のSLAが「100%」ではなく「99.9%」「99.99%」で書かれているのはこのためです。目指すべきは100%ではなく、業務上どこまでの停止なら許容できるかを決め、その水準を安定して満たすことです。

冗長化すれば必ず可用性は上がりますか?

上がらないことがあります。理由は3つです。第一に、単一障害点が別の場所に残っていれば効果が出ません。この記事の例でもロードバランサ自体はSPOFのままでした。第二に、切り替え(フェイルオーバー)が正しく動かなければ、冗長機がある意味がありません。定期的に切り替えテストが必要です。第三に、構成が複雑になるぶん設定ミスや運用ミスの余地が増え、かえって障害の原因になることがあります。

99.9%と99.99%では何が違いますか?

許容される停止時間が月43分から月4分へと10分の1になります。実務上の差は大きく、99.9%なら「深夜に人がメンテナンスして再起動する」運用が成り立ちますが、99.99%では人が気づいて対応する時間がないため、自動フェイルオーバーが前提になります。監視・自動化・冗長機のコストが跳ね上がるので、業務上の必要性から逆算して決めてください。

自分のサーバーの稼働率はどうやって測ればよいですか?

2つの視点があります。サーバー本体の稼働率はjournalctl --list-bootsの起動履歴から算出できます(この記事のuptime-rate.sh)。利用者から見た可用性は、外部からHTTPアクセスして成否を記録する外形監視で測ります。両方測ると「サーバーは動いているのにサービスは落ちていた」時間が見えるようになり、そこが最も改善効果の大きい領域になります。

高可用性(HA)とは何を指しますか?

High Availabilityの略で、障害が起きてもサービスを継続できるよう設計された構成を指します。明確な数値基準はありませんが、一般には99.99%以上を目標にする構成を指すことが多いです。実装としては、同じ役割のサーバーを複数用意し(冗長化)、死活監視で異常を検知し、自動的に待機系へ切り替える(フェイルオーバー)という3点セットで構成されます。Linuxではkeepalived(VRRP)やPacemakerが代表的です。

まとめ

  • 可用性とは「必要なときに使える」性質で、情報セキュリティの3要素(CIA)のひとつ
  • 数値化には稼働率を使い、MTBF / (MTBF + MTTR)で求める。MTTRを縮めるだけでも稼働率は上がる
  • 99.9%=月43分、99.99%=月4分。9をひとつ増やすと許容停止時間は10分の1になる
  • 部品を直列に増やすと稼働率は下がり、並列(冗長化)に増やすと上がる
  • 自分のサーバーの稼働率はjournalctl --list-bootsから算出できる。last rebootは異常終了時に信用できない
  • サービス単位はsystemctl is-active終了ステータスで判定する(停止は3、ユニット無しは4)
  • 実測では、同じ障害でも冗長化ありで100%、なしで75%と結果が分かれた。可用性は設計で決まる
  • 自動復旧のテストでdocker killやコンテナ内のkill -9 1を使うと、正しく設定していても「復旧しない」と誤診する

まずは自分のサーバーでjournalctl --list-bootsを実行し、過去にどれだけ止まっていたかを確認するところから始めてみてください。数字が出ると、どこに手を入れるべきかがはっきりします。

関連記事

Bash玄

はじめまして!Bash玄です。

エンジニアとしてシステム運用に携わる中で、手作業の多さに限界を感じ、Bashスクリプトを活用して業務を効率化したのがきっかけで、この道に入りました。「手作業は負け」「スクリプトはシンプルに」をモットーに、誰でも実践できるBashスクリプトの書き方を発信しています。

このサイトでは、Bashの基礎から実践的なスクリプト作成まで、初心者でもわかりやすく解説しています。少しでも「Bashって便利だな」と思ってもらえたら嬉しいです!

# 好きなこと
- シンプルなコードを書くこと
- コマンドラインを快適にカスタマイズすること
- 自動化で時間を生み出すこと

# このサイトを読んでほしい人
- Bashに興味があるけど、何から始めればいいかわからない人
- 定型業務を自動化したい人
- 効率よくターミナルを使いこなしたい人

Bashの世界に一歩踏み出して、一緒に「Bash道」を極めていきましょう!

Bash玄をフォローする

コメント