Webサーバー キャッシュの【HIT】率向上に資する コマンドとシェルスクリプト

Nginx + PHP + WordPress サーバーの管理
proxy_cache + fastcgi_cache
キャッシュの 【HIT】率向上 コマンドとシェルスクリプト
 
リバースプロキシをフロントエンドに配置し、バックエンドのWebサーバーへリクエストを中継する構成では、各サーバーが保持するキャッシュを活用することで、Webサーバーの処理負荷を軽減し、且つ、ユーザーへの応答速度が向上できる。
但し、システム全体のパフォーマンスを最大化するためには、キャッシュのヒット率を高めることが重要となる。
 
proxy と fastcgi の「パターン別」ヒット率
proxy と fastcgi の「パターン別」ヒット率。(ヒット率を改善する前の状態)
 
以下、キャッシュの状態を調査/分析するための「コマンド と シェルスクリプトを、使用する局面に合わせ、事例と共に記載した。
 
 

 

スポンサー リンク

 

 
 
 
 
 
1. 環境情報
 
サーバーは全て Raspberry Pi 4 Model B で、システムドライブにはSSDを使用している。
フロントエンドに Reverse Proxy Server を立て、バックエンドにWebサーバーを配置する構成にしている
 
ミドルウェアは Nginx + PHP で、バックエンドのWebサーバーでは「WordPress」が稼働している。
 
フロントエンドの リバースプロキシサーバーで proxy_cache を設定し、バックエンドのWebサーバーでは fastcgi_cache が使われる設定となっている。
 
SSDの状態を確認するコマンド。
# SSDの状態確認コマンド
sudo smartctl -a /dev/sda
sudo smartctl -a /dev/sda 2>/dev/null | grep -E "Device Model|Rotation Rate|SSD"

$ sudo smartctl -a /dev/sda 2>/dev/null | grep -E "Device Model|Rotation Rate|SSD"
Model Family:     Samsung based SSDs
Device Model:     Samsung SSD 860 EVO 250GB
Rotation Rate:    Solid State Device
 
 
✅ proxy_cache:SSDに作成
 
元は tmpfs にしていたが、容量不足が判明した為 SSD に変更。
# SSDにキャッシュディレクトリを作成
sudo mkdir -p /var/cache/nginx_disk/arakoki70

# オーナー設定
sudo chown -R www-data:www-data /var/cache/nginx_disk/

# nginx.conf の設定を変更(SSDなのでmax_sizeを大きく取れる)
proxy_cache_path /var/cache/nginx_disk/arakoki70 levels=1:2 keys_zone=arakoki70:10m max_size=10g inactive=30d use_temp_path=off;
 
 
✅ fastcgi_cache:SSDに作成
 
# SSDにキャッシュディレクトリを作成
sudo mkdir -p /var/cache/nginx_disk/farakoki70

# オーナー設定
sudo chown -R www-data:www-data /var/cache/nginx_disk/

# nginx.conf のキャッシュパスを変更
fastcgi_cache_path /var/cache/nginx_disk/farakoki70 levels=1:2 keys_zone=farakoki70:10m max_size=10g inactive=30d use_temp_path=off;
 
 
 
2. URLからキャッシュの状態を確認するコマンド
 
キャッシュが有効になっているかどうかは、URLから簡単に確認することが出来る。
以下、URLから確認するコマンドのサンプルを列挙。
 
# ヘッダー全体を見る
# 実行結果サンプル
$ curl -I https://arakoki70.com/
HTTP/2 200 
server: nginx
date: Sat, 23 May 2026 11:53:22 GMT
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
vary: Accept-Encoding
link: <https://arakoki70.com/index.php?rest_route=/>; rel="https://api.w.org/"
x-fastcgi-cache: HIT
x-proxy-cache: HIT

# キャッシュの状態を確認するコマンド
# 実行結果サンプル
$ curl -I https://arakoki70.com/ | grep -i "cache"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
x-fastcgi-cache: HIT
x-proxy-cache: HIT

# 特定ページのキャッシュ状況を確認するコマンド
curl -I https://arakoki70.com/ | grep -i "cache"
curl -I https://arakoki70.com/ | grep x-proxy-cache
curl -I https://arakoki70.com/ | grep x-fastcgi-cache

# 実行結果サンプル
$ curl -I https://arakoki70.com/?p=12022
HTTP/2 200 
server: nginx
date: Sat, 23 May 2026 11:59:18 GMT
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
vary: Accept-Encoding
link: <https://arakoki70.com/index.php?rest_route=/>; rel="https://api.w.org/"
link: <https://arakoki70.com/index.php?rest_route=/wp/v2/posts/12022>; rel="alternate"; title="JSON"; type="application/json"
link: <https://arakoki70.com/?p=12022>; rel=shortlink
x-fastcgi-cache: HIT
x-proxy-cache: HIT

# 画像ファイルへのアクセスがキャッシュされているか確認
curl -I https://arakoki70.com/wp-content/uploads/2019/10/clicksuu_0012.jpg \
  | grep -i cache

# 実行結果サンプル
$ curl -I https://arakoki70.com/wp-content/uploads/2019/10/clicksuu_0012.jpg   | grep -i cache
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0 36779    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
cache-control: max-age=2592000
cache-control: public, max-age=2592000, no-transform
x-proxy-cache: HIT
 
 
 
3. キャッシュのファイル数とディスクの使用量を確認するスクリプト
 
どの程度キャッシュされているか、キャッシュのファイル件数とディスクの使用量を確認するスクリプト。
 
🔹 proxy_cache のファイル数とディスクの使用量を表示するスクリプト。
#!/bin/bash
# 変数に日時を代入
CURRENT_TIME=$(date "+%Y-%m-%d %H:%M:%S")
echo "${CURRENT_TIME}:proxy_cache のファイル数と使用量"
for site in arakan60 arakoki70 treksite; do
    count=$(sudo find /var/cache/nginx_disk/$site -type f | wc -l)
    size=$(sudo du -sh /var/cache/nginx_disk/$site | cut -f1)
    echo "$site : ${count}ファイル / ${size}"
done

# スクリプトの登録
sudo nano proxy-usage.sh

# スクリプトに実行権限を付与
sudo chmod +x proxy-usage.sh

# スクリプトの実行
./proxy-usage.sh

# 実行結果サンプル
$ ./proxy-usage.sh 
2026-05-23 21:08:08:proxy_cache のファイル数と使用量
arakan60 : 23483ファイル / 1.9G
arakoki70 : 30864ファイル / 1.7G
treksite : 1015ファイル / 38M
 
 
 
4. キャッシュのヒット率を集計するためのアクセスログ
 
キャッシュのヒット率を調べるために、アクセスログにキャッシュステータスを出力する。
# nginx アクセスログフォーマット
log_format cache_log '$remote_addr "$request" $status '
                 'proxy=$upstream_cache_status '
                 'fastcgi=$sent_http_x_fastcgi_cache '
                 '$time_local';

# 最新アクセスログを3行表示コマンド
tail -n 3 /var/log/nginx/cache_access.log

# アクセスログの例
162.120.184.20 "GET /?p=10158 HTTP/2.0" 200 proxy=HIT fastcgi=HIT 23/May/2026:17:58:11 +0900
 
アクセスログのフォーマットと出力されたログの内容についての相関。
アクセスログのフォーマットと出力されたログの内容についての相関
 
アクセスログのフォーマット変数と実際のログ出力との対応表。
フォーマットと実際のログの対応表
 
アクセスログの項目は「フィールド」と呼ばれ、先頭から番号が付され「$n」で参照できる(awkコマンド)。
 
 
 
5. キャッシュヒット率を proxyとfastcgiの組合せで集計するスクリプト
 
キャッシュステータスが出力されたアクセスログを使用し、proxy と fastcgi の組合せパターンでキャッシュのヒット率を集計するスクリプト。集計する過去の「時間範囲」を指定可能(デフォルトは 1時間)。
#!/bin/bash
LOG=${1}
HOURS=${2:-1}  # 第2引数で時間指定、デフォルト1時間

# 引数チェック
if [ -z "$LOG" ]; then
    echo "使い方: bash cache-hitrate_2.sh /var/log/nginx/cache_access.log [時間数]"
    echo "例: bash cache-hitrate_2.sh /var/log/nginx/cache_access.log 1   # 過去1時間"
    echo "例: bash cache-hitrate_2.sh /var/log/nginx/cache_access.log 24  # 過去24時間"
    echo "例: bash cache-hitrate_2.sh /var/log/nginx/cache_access.log 0   # 全件"
    exit 1
fi
if [ ! -f "$LOG" ]; then
    echo "エラー: ファイルが見つかりません: $LOG"
    exit 1
fi

# 集計対象の開始時刻を算出
if [ "$HOURS" -eq 0 ]; then
    SINCE=""
    echo "集計範囲: 全件"
else
    SINCE=$(LC_ALL=C date -d "${HOURS} hours ago" "+%d/%b/%Y:%H:%M:%S")
    echo "集計範囲: 過去 ${HOURS} 時間 (${SINCE} JST 以降)"
fi

awk -v since="$SINCE" '
function parse_time(ts,    months, a) {
    # "17/May/2026:14:53:12" → "20260517145312" に変換して文字列比較
    months["Jan"]="01"; months["Feb"]="02"; months["Mar"]="03"
    months["Apr"]="04"; months["May"]="05"; months["Jun"]="06"
    months["Jul"]="07"; months["Aug"]="08"; months["Sep"]="09"
    months["Oct"]="10"; months["Nov"]="11"; months["Dec"]="12"
    split(ts, a, "[/:]")
    return a[3] months[a[2]] sprintf("%02d", a[1]) a[4] a[5] a[6]
}
{
    # 時間フィルタリング
    if (since != "") {
        ts = ""
        for (i=1; i<=NF; i++) {
            # "17/May/2026:14:53:12" 形式を検出(+0900 の手前のフィールド)
            if ($i ~ /^[0-9]{2}\/[A-Za-z]{3}\/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2}$/) {
                ts = $i
                break
            }
        }
        if (ts == "") next
        if (parse_time(ts) < parse_time(since)) next
    }

    proxy = "-"
    fastcgi = "-"
    for (i=1; i<=NF; i++) {
        if ($i ~ /^proxy=/)   proxy   = substr($i, 7)
        if ($i ~ /^fastcgi=/) fastcgi = substr($i, 9)
    }
    combo[proxy "|" fastcgi]++
    total++
}
END {
    if (total == 0) {
        print "\n該当するログが見つかりませんでした。\n"
        exit
    }
    printf "\n=== 総アクセス数: %d ===\n\n", total
    printf "%-12s  %-12s  %8s  %8s\n", "proxy_cache", "fastcgi_cache", "件数", "割合"
    printf "%-12s  %-12s  %8s  %8s\n", "------------", "-------------", "--------", "--------"
    n = asorti(combo, sorted)
    for (i=1; i<=n; i++) {
        split(sorted[i], parts, "|")
        printf "%-12s  %-13s  %8d  %7.1f%%\n",
            parts[1], parts[2], combo[sorted[i]], combo[sorted[i]]/total*100
    }
    printf "\n"
}
' "$LOG"

# スクリプトの登録
sudo nano cache-hitrate.sh

# スクリプトに実行権限を付与
sudo chmod +x cache-hitrate.sh

# スクリプトの実行(デフォルト過去1時間)
./cache-hitrate.sh /var/log/nginx/cache_access.log

# 過去3時間
./cache-hitrate.sh /var/log/nginx/cache_access.log 3

# アクセスログ全件を対象
./cache-hitrate.sh /var/log/nginx/cache_access.log 0

# 過去1時間での集計サンプル
$ ./cache-hitrate_3.sh /var/log/nginx/cache_access.log 1
集計範囲: 過去 1 時間 (24/May/2026:12:08:48 JST 以降)

=== 総アクセス数: 2088 ===

proxy_cache   fastcgi_cache        件数        割合
------------  -------------  --------  --------
-             -                   280     13.4%
BYPASS        -                     9      0.4%
BYPASS        BYPASS                1      0.0%
EXPIRED       EXPIRED               1      0.0%
EXPIRED       HIT                   3      0.1%
HIT           -                  1474     70.6%
HIT           BYPASS                1      0.0%
HIT           EXPIRED               2      0.1%
HIT           HIT                 118      5.7%
HIT           MISS                 14      0.7%
MISS          -                   100      4.8%
MISS          BYPASS               14      0.7%
MISS          EXPIRED               4      0.2%
MISS          HIT                  21      1.0%
MISS          MISS                 45      2.2%
STALE         MISS                  1      0.0%
 
✅ 活用ポイント。
proxyfastcgi件数割合コメント
--9238.8% 
BYPASS -90.1%ログイン中ユーザー等:正常なので問題なし
BYPASS BYPASS 20.0% 
HIT -4,29140.8%最も効率的な状態:このパターンが多いほど理想
HIT BYPASS 40.0% 
HIT EXPIRED 90.1% 
HIT HIT 2862.7% 
HIT MISS  110.1% 
MISS  -3,84336.5% 
MISS  BYPASS 360.3% 
MISS  EXPIRED 260.2% 
MISS  HIT 8758.3%proxy_cacheが機能していない
MISS  MISS  2082.0%両方ミス・PHP実行:サーバー負荷が高い・要注意
  10,52399.9% 
 
😊 HIT / - の割合が高い状態を維持できていれば、キャッシュが順調に機能している証拠となる。
 
 
 
6. 「ヒット率パターン」でアクセスログを抽出するスクリプト
 
🔎 上記の表から問題となるパターンを見つけて、該当のURLを抽出して対策を講じて行く。
 
➡️ - / - パターン:proxyもfastcgiもキャッシュ対象外になっているURLを確認。
awk '{
  proxy="-"; fastcgi="-"
  for(i=1;i<=NF;i++){
    if($i~/^proxy=/) proxy=substr($i,7)
    if($i~/^fastcgi=/) fastcgi=substr($i,9)
  }
  if(proxy=="-" && fastcgi=="-") print $3, $5
}' /var/log/nginx/cache_access.log | sort | uniq -c | sort -rn | head -20

# スクリプトの登録
sudo nano pat--url.sh

# スクリプトに実行権限を付与
sudo chmod +x  pat--url.sh

# スクリプトの実行
./pat--url.sh

$ ./pat--url.sh # 実行結果サンプル
    221 /wp-login.php 403
    173 /trek/wp-admin/admin-ajax.php 403
    110 / 301
     59 /robots.txt 301
     31 400 fastcgi=-
     28 /wp-comments-post.php 302
     24 / 200
     22 /.well-known/traffic-advice 404
     18 /xmlrpc.php 301
     18 /wp-content/plugins/hellopress/wp_filemanager.php 301
     18 /ads.txt 301
     18 / 400
     14 /wp-login.php 301
     14 /wp-content/plugins/hellopress/wp_filemanager.php 404
     13 /robots.txt 403
     11 /wp-good.php 301
     11 /administrator/ 301
     10 /favicon.ico 301
     10 /edit.php 404
      9 /wp-json/wp/v2/posts 301
 
➡️ MISS / - パターン:proxyがMISSでfastcgiがキャッシュ対象外になっているURLを確認。
awk '{
  proxy="MISS"; fastcgi="-"
  for(i=1;i<=NF;i++){
    if($i~/^proxy=/) proxy=substr($i,7)
    if($i~/^fastcgi=/) fastcgi=substr($i,9)
  }
  if(proxy=="MISS" && fastcgi=="-") print $3, $5
}' /var/log/nginx/cache_access.log | sort | uniq -c | sort -rn | head -20

sudo nano patmiss-url.sh
sudo chmod +x  patmiss-url.sh
./patmiss-url.sh

$ ./patmiss-url.sh
     12 /webfonts/fa-solid-900.woff2 404
     12 /webfonts/fa-solid-900.woff 404
     12 /webfonts/fa-solid-900.ttf 404
     10 /apple-touch-icon.png 404
     10 /apple-touch-icon-precomposed.png 404
      7 /.env 403
      6 /wp-content/cache/autoptimize/js/autoptimize_c2914f7cc11a5688a2f11c63f03ad776.js 200
      4 /apple-touch-icon-120x120.png 404
      4 /apple-touch-icon-120x120-precomposed.png 404
      4 /.git/config 403
      3 /wp-content/uploads/2025/07/pix_3993.png 200
      3 /backend/.env 403
      3 /api/.env 403
      3 /.env.production 403
      3 /.env.local 403
      2 /xxl.php 404
      2 /xmlrpc.php?rsd 403
      2 /xmlrpc.php 403
      2 /wpm.php 404
      2 /wp-logout.php 404
 
🔹 MISS/- のパターンでリクエストURLを抽出して集計するコマンド。
grep "proxy=MISS" /var/log/nginx/cache_access.log | grep "fastcgi=-" \
  | awk '{print $3}' | sort | uniq -c | sort -rn | head -20
 
🔹 MISS/- のパターンでリクエストURLを抽出して集計するコマンド。
grep "proxy=MISS" /var/log/nginx/cache_access.log | grep "fastcgi=-" \
  | awk '{print $3}' | grep -oE '\.[a-zA-Z0-9]+$' | sort | uniq -c | sort -rn

# 実行結果サンプル
$ grep "proxy=MISS" /var/log/nginx/cache_access.log | grep "fastcgi=-" \
  | awk '{print $3}' | grep -oE '\.[a-zA-Z0-9]+$' | sort | uniq -c | sort -rn
    972 .jpg
    876 .png
    379 .webp
    294 .php
    185 .env
     39 .js
     38 .css
     12 .woff2
     12 .woff
     12 .ttf
      5 .txt
      3 .production
 
 
 
7. キャッシュの【HIT】率向上対策-事例
 
💎 MISS/- のパターンでアクセスしてきたIPアドレスを抽出して集計するコマンドを実行したところ・・・。
 $ grep "proxy=MISS" /var/log/nginx/cache_access.log | grep "fastcgi=-" \
  | awk '{print $1}' | sort | uniq -c | sort -rn | head -20

# 実行結果
IPアドレス				正体
66.249.73.xx 66.249.74.xx		Googlebot
216.244.66.250				DotBot(SEOクローラー)
51.15.xx 51.158.xx 51.159.xx		Scaleway系クローラー
126.xx.xx.xx 153.xx.xx.xx 118.xx.xx.xx	日本国内の一般ユーザー
 
🧰 クローラーが大量にアクセスしているのが明確だったので、問題のクローラーをブロックする。
if ($http_user_agent ~* "DotBot|MJ12bot|AhrefsBot|SemrushBot") {
    return 403;
}
 
💎 tmpfs(RAM)にキャッシュを配置→ SSDに移行。
 → キャッシュの容量拡大でHIT率が大幅に向上。
 
💎 キャッシュ対象外URLの調査から .txt をキャッシュ対象に追加。
# 既存の静的ファイルブロックの拡張子に txt を追加
location ~* \.(jpg|jpeg|png|gif|webp|css|js|ico|svg|woff|woff2|ttf|txt)$ {
 
💎 大量の404リクエストがバックエンドに到達している。
# 404をキャッシュ
proxy_cache_valid 404 1h; 
 
💎 fastcgi_cache_valid のリダイレクト期間短縮。
fastcgi_cache_valid のリダイレクト期間短縮
fastcgi_cache_valid 200 7d;
fastcgi_cache_valid 301 302 1h;   # 7d → 1h
fastcgi_cache_valid 404 10m;
 
🔴 末尾に wp-login.php が付いたアクセスをブロック。
    # ----------------------------------
    # 危険Query遮断 y2026.05.21
    # ----------------------------------
    if ($query_string ~* "wp-login\.php") {
        return 444;
 
 
その他細かい設定の修正を行い、キャッシュのヒット率を大幅に改善❗❗。 
 
 
以上。
(2026.05.24)
 

 

スポンサー リンク

 

             

 

 

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください