ApacheのScoreboardをモニタリングする
はじめに
私事ですが、昨年末に運用しているWEBサービスにて、Apacheの同時接続数が上限に達し一時的にサービス提供できなくなる経験をしました。 その際に、エラーログにScoreboardという文字列を含む下記のエラーログが頻発していました。
AH00286: server reached MaxRequestWorkers setting, consider raising the MaxRequestWorkers setting AH00287: server is within MinSpareThreads of MaxRequestWorkers, consider raising the MaxRequestWorkers setting AH00288: scoreboard is full, not at MaxRequestWorkers
対応の一環で、Scoreboadのモニタリング設定などをしたので、その際の内容をまとめておきたいと思います。 また、私の理解不足で不正確な内容を記載している箇所もあるかと思いますが、自分の外部記憶装置代わり的な意味でも記載していますのでご了承下さい。
検証環境
用語
Slot
ApacheがHTTPリクエストを処理する実体のことで、MPMがPreforkであればプロセスのことであり、Worker, Eventであればスレッドのこと。
Scoreboard
Apacheが親プロセスと子プロセスとの間で共有するメモリ領域のこと。各Slot毎にさまざまな情報を保持しているらしい。
下記あたりのコードを見れば、Scoreboardについて詳細にわかりそう。
- https://github.com/apache/httpd/blob/trunk/include/scoreboard.h
- https://github.com/apache/httpd/blob/trunk/server/scoreboard.c
Scoreboardの状態確認方法
調査すると、mod_statusモジュールでステータスページを通じて確認する方法と、共有メモリ上のScoreboardに直接アクセスして情報を取得する方法があるようです。 今回は、前者のmod_statusモジュールを使った方法を記載します。
後者の共有メモリに直接アクセスする方法は情報があまり多くなく、Scoreboardについて実装レベルで把握していないと難しいようだったので、今回は断念しました。 ただ、mod_statusモジュールを使う場合と比較して、モニタリングのためにApacheにアクセスする必要がないため、接続数が飽和している状態でもScoreboardの状態が確認できるという点でメリットがありそうです。
参考までに、下記に記事を紹介しておきます。
mod_statusの有効化とステータスページからのデータ取得
下記の内容をApacheの設定ファイルに追記します。これにより、Apacheの状態がステータスページで確認できるようになります。
LoadModule status_module modules/mod_status.so ExtendedStatus On Listen 81 <VirtualHost *:81> <Location /server-status> SetHandler server-status Require all granted </Location> </VirtualHost>
ここでは、ステータスページのURIがサービスに干渉することを防ぐために、VirtualHostで未使用のポートに対してステータスページを表示させるよう設定しています。 モニタリングや通信制限の運用次第ではありますが、接続元をlocalhostなどに絞るなどのセキュリティ対策は実際の環境に応じて検討したほうが良いと思います。
また、.htaccessなどの設定ファイル内でもステータスページの表示設定ができるようになるため、.htaccessを有効している環境では意図せずステータスページを外部に公開してしまう恐れもあるため注意が必要です。回避策としては、AllowOverrideやAllowOverrideListなどでSetHandlerの使用を許可しないよう設定すれば良さそうです。
https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride
設定ファイルを編集後、Apacheを再起動します。
$ apachectl -t Syntax OK $ sudo systemctl restart httpd
ローカルからステータスページにアクセスしてみます。先のVirtualHostで定義したURLに対して?auto
パラメタをつけてアクセスすることで、下記のようなkey-value形式でデータを取得できます。
$ curl localhost:81/server-status?auto localhost ServerVersion: Apache/2.4.28 (CentOS) OpenSSL/1.0.2k-fips ServerMPM: worker Server Built: Oct 9 2017 12:34:18 CurrentTime: Monday, 01-Jan-2018 16:11:40 JST RestartTime: Monday, 01-Jan-2018 16:08:56 JST ParentServerConfigGeneration: 1 ParentServerMPMGeneration: 0 ServerUptimeSeconds: 163 ServerUptime: 2 minutes 43 seconds Load1: 0.04 Load5: 0.12 Load15: 0.22 Total Accesses: 305 Total kBytes: 361 CPUUser: .39 CPUSystem: .18 CPUChildrenUser: 0 CPUChildrenSystem: 0 CPULoad: .349693 Uptime: 163 ReqPerSec: 1.87117 BytesPerSec: 2267.88 BytesPerReq: 1212.01 BusyWorkers: 1 IdleWorkers: 49 Scoreboard: __________________W_______________________________ TLSSessionCacheStatus CacheType: SHMCB CacheSharedMemory: 512000 CacheCurrentEntries: 76 CacheSubcaches: 32 CacheIndexesPerSubcaches: 88 CacheTimeLeftOldestAvg: 183 CacheTimeLeftOldestMin: 136 CacheTimeLeftOldestMax: 288 CacheIndexUsage: 2% CacheUsage: 3% CacheStoreCount: 76 CacheReplaceCount: 0 CacheExpireCount: 0 CacheDiscardCount: 0 CacheRetrieveHitCount: 0 CacheRetrieveMissCount: 0 CacheRemoveHitCount: 0 CacheRemoveMissCount: 0
ここで、目的のScoreboardは下記のような文字列として表示されており、1文字が1つのSlotの状態を表現しています。
Scoreboard: __________________W_______________________________
各文字とSlotの状態の意味は下記の通りです。
文字 | 状態名 | 意味 |
---|---|---|
_ | Waiting for Connection | プロセス/スレッド起動し、アクセス待ちの状態 |
S | Starting up | プロセス/スレッドが起動中の状態 |
R | Reading Request | クライアントからのアクセスを受け付けて、リクエストを読み込んでいる状態 |
W | Sending Reply | クライアントにレスポンスを返している状態 |
K | Keepalive (read) | KeepAliveによりリクエストを待機している状態 |
D | DNS Lookup | クライアントのIPの名前解決している状態 |
C | Closing connection | 接続を終了している状態 |
L | Logging | ログ出力している状態 |
G | Gracefully finishing | スレッドのgracefulな停止処理中またはそこからの起動中 ? |
I | Idle cleanup of worker | スレッドが終了中な状態 |
. | Open slot with no current process | 空きSlot状態 |
何度かステータスページにアクセスしていると気づきますが、アクセスが全くない状態でもScoreboardには必ず1つW
が表示されます。これはステータスページへのアクセスを処理しているSlotの状態を示しており、そのレスポンス中のScoreboardの状態が取得されステータスページが生成されているためだと思います。
Scorboardの数値化
ステータスページに表示されていたScoreboardは1文字が1つのSlotの状態を表現した文字列として表示されるため、その意味に従って状態毎にカウントして数値化することでモニタリングできるようになります。
ここでは、下記のPythonスクリプトでステータスページのScoreboardの文字列を数値化してみます。
#!/bin/env python import requests import argparse scoreboard_lookup = { '_': 'WaitingForConnection', 'S': 'StartingUp', 'R': 'ReadingRequest', 'W': 'SendingReply', 'K': 'KeepAlive', 'D': 'DNSLookup', 'C': 'ClosingConnection', 'L': 'Logging', 'G': 'GracefullyFinishing', 'I': 'IdleCleanupOfWorker', '.': 'OpenSlotWithNoCurrentProcess', } def main(url): r = requests.get(url) for key, value in [ tuple(x) for x in [ line.split(': ') for line in r.text.splitlines() ] if len(x) == 2]: key = key.replace(' ', '') if key == 'Scoreboard': print('apache.scoreboard.{},{}'.format('TotalSlot', len(value))) for scoreboard_char,scoreboard_label in scoreboard_lookup.items(): print('apache.scoreboard.{},{}'.format(scoreboard_label, value.count(scoreboard_char))) else: print('apache.{},{}'.format(key, value)) if __name__ == '__main__': argparser = argparse.ArgumentParser() argparser.add_argument('-u', '--url', type=str, required=True) args = argparser.parse_args() main(args.url)
上記のスクリプトは、ステータスページの内容を取得して下記の処理をしています。
- csv形式のkey-value(key,value)形式に整形
- keyのprefixに
apache.
を追加 - keyに含まれていた半角スペースを削除
- ScoreboardをSlotの状態毎にカウントし、apache.scoreboard.状態名というkeyのvalueに追加
- Scoreboardの総Slot数(apache.scoreboard.TotalSlot)を追加
適当にファイル名でスクリプトを作成し、実行権限を付与して実行します。
$ vi apache.py $ chmod 755 apache.py $ apache.py -u http://pxy01.private:81/server-status?auto apache.ServerVersion,Apache/2.4.28 (CentOS) OpenSSL/1.0.2k-fips apache.ServerMPM,worker apache.ServerBuilt,Oct 9 2017 12:34:18 apache.CurrentTime,Monday, 01-Jan-2018 17:53:38 JST apache.RestartTime,Monday, 01-Jan-2018 16:08:56 JST apache.ParentServerConfigGeneration,1 apache.ParentServerMPMGeneration,0 apache.ServerUptimeSeconds,6282 apache.ServerUptime,1 hour 44 minutes 42 seconds apache.Load1,0.00 apache.Load5,0.01 apache.Load15,0.05 apache.TotalAccesses,11589 apache.TotalkBytes,13357 apache.CPUUser,16.41 apache.CPUSystem,6.45 apache.CPUChildrenUser,0 apache.CPUChildrenSystem,0 apache.CPULoad,.363897 apache.Uptime,6282 apache.ReqPerSec,1.84479 apache.BytesPerSec,2177.26 apache.BytesPerReq,1180.22 apache.BusyWorkers,1 apache.IdleWorkers,49 apache.scoreboard.TotalSlot,50 apache.scoreboard.ClosingConnection,0 apache.scoreboard.DNSLookup,0 apache.scoreboard.GracefullyFinishing,0 apache.scoreboard.IdleCleanupOfWorker,0 apache.scoreboard.KeepAlive,0 apache.scoreboard.Logging,0 apache.scoreboard.StartingUp,0 apache.scoreboard.ReadingRequest,0 apache.scoreboard.SendingReply,1 apache.scoreboard.WaitingForConnection,49 apache.scoreboard.OpenSlotWithNoCurrentProcess,0 apache.CacheType,SHMCB apache.CacheSharedMemory,512000 apache.CacheCurrentEntries,137 apache.CacheSubcaches,32 apache.CacheIndexesPerSubcaches,88 apache.CacheTimeLeftOldestAvg,65 apache.CacheTimeLeftOldestMin,0 apache.CacheTimeLeftOldestMax,222 apache.CacheIndexUsage,4% apache.CacheUsage,5% apache.CacheStoreCount,2883 apache.CacheReplaceCount,0 apache.CacheExpireCount,2746 apache.CacheDiscardCount,0 apache.CacheRetrieveHitCount,0 apache.CacheRetrieveMissCount,0 apache.CacheRemoveHitCount,0 apache.CacheRemoveMissCount,0
上記のapache.scoreboard.
あたりがScoreboardの状態が数値化したものになります。
私の場合は、上記のkey-valueのデータをZabbix SenderでZabbixサーバに送ることでグラフ化したりしています。
モニタリングツールでScoreboardをモニタリングする参考リンク
私自身ですべて試したことがあるわけではありませんが、有名どころのモニタリングツールを使ってScoreboardをモニタリングする方法の関連リンクを紹介しておきます。
Zabbix
- Docs/howto/apache monitoring script - Zabbix.org
- GitHub - lorf/zapache: Zabbix Apache Monitoring Script (from https://www.zabbix.org/wiki/Docs/howto/apache_monitoring_script#Method_3, originally from https://www.zabbix.com/forum/showthread.php?p=62457)