cronメンテナンスタスクの実行

先日の記事でふれたDrupalのcronメンテナンスタスク(cron.php)の実行についてです。

設定自体は、Drupal導入時に済ませていましたが、実際に動作しているかどうかが不安でした。
というのも、Drupalの管理セクション⇒リポート⇒現状報告画面で確認するとcronメンテナンスタスクの項目が"実行されていない"といった表示にいつもなっていたためでした。
スケジュールを1日1回の設定にしていた事、複数サイトで構築したにもかかわらず1つのエントリしか設定していなかった事が原因かもしれません。

いろいろ関連ドキュメントを読んでいると、1時間に1回くらいは起動するようにしたほうが良いということでした。
ただこれは、一般的な目安であってハードウェアのスペック、サイトの混雑度やcronメンテナンス自体の実行負荷などから考慮して、適切な時間にすることが望まれます。

結局は、いいあんばいな設定を自分で見つけてくださいということです。

私のサイトの場合は、複数ドメイン構成にしていますので、それぞれでcronメンテナンスタスクを実行しなくてはいけません。
仮に1時間ごとに設定した場合、レンタルサーバ上では1時間に2回cronプロセスが起動されることになります。
また起動時間が重複すると、どちらかが起動できない可能性がありますので、時間をずらして設定する必要があります。

それではどれくらいの時間に設定すればよいのか悩まされます。
まず、cronメンテナンスタスクで何をやっているのか?をある程度把握しておかなければ、1回の起動が何分くらいで終わり、どれくらいの負荷があるのか検討がつきません。

私のサイトをもとに、わかる範囲でリストアップしてみました。
①コアモジュールや拡張モジュールの更新の確認
②イベントログの削除
③アグリゲータの更新(アグレゲータ有効時、3サイト:100件+5件+49件)
④FeedノードのFeed更新(FeedAPI使用時、1サイト25件x3サイト分、Feedノード内では更新を1時間に設定)
⑤検索用の索引付け(Searchモジュール有効時?:未使用)
⑥タクソノミメニューの更新(メニュー増減時?:ほぼ固定のため増減なし)
⑦Pingの送信(Pingモジュール有効時:未使用)
⑧コメントの更新
⑨メールの送信?
⑩その他のモジュールに個別の更新

項目をあげていくときりがないので、⑩でまとめておきます。
Drupalシステムの健全度を維持するための処理①と②はどのサイトも共通箇所になると思います。
それとは別に、各モジュールのノード情報を最新の状態に維持するための処理③~⑩は、サイトごとに異る部分だと思います。
私が設置した2つのサイトでも、項目は大きく異なっています。その結果、実行時間は全く違っています。

あと、cronメンテナンスタスクの実行間隔によって、1回の処理時間は違ってきます。
例えば同じサイトで、10分間隔と24時間間隔でcronメンテナンスタスクを実行した場合の処理時間を比較すると、
更新するかどうか、削除するかどうかをチェックする項目数は毎回同じなので、これによる処理時間の増減はほとんどないでしょうが、実際に削除するまたはデータを更新する数は異なってくるので、間隔が長くなればなるほどアクションが増える可能性があります。これは、アクセスの多いサイト、更新頻度が高いサイトから情報を受けているサイトで顕著に差が現れると思います。
そのため、間隔が長いと1回のcronメンテナンスタスクの実行時間が長くなり、結果、サーバに負荷をかける時間が増加します。

レンタルサーバですと共有でサーバを利用していますので、サーバ管理側からすれば1ユーザが長期間サーバのリソースを占有することを嫌います。
特に、ユーザごとにCPU使用率やメモリ使用率などは常時監視しているはずです。
しきい値を超えてしまうと、最悪cron設定を削除されてしまいますので、そうならないよう注意してください。

とはいっても、こればっかりは実際に運用してみないとわかりませんので、実行間隔がベストになるように様子をみながら変えていこうと思います。
とりあえず、30分間隔で実行するように設定してみました。

cronメンテナンスタスクの実行方法については、
さくらインターネットのレンタルサーバでは、管理画面からGUIによりcronの設定が可能です。
また、リモートログインすれば、CLIからでも設定が可能です。

ただ、crontabに記載したプログラムは、通常ログインした際に設定されるユーザ環境変数が読み込まれていませんので、ユーザ環境変数を使用するのであればユーザ環境変数が使用できるよう設定が必要です。その1つが、管理画面にある環境変数設定機能を利用する方法、もう1つが別途シェルスクリプトファイルを作成してそれを起動する方法です。
ユーザ環境変数を使っていないのであれば、直接絶対パスで指定して設定すれば実行されるはずです。

以下、Drupal導入時に登録したcronの設定

30 5 * * * cd /home/[ユーザ名]/www/[drupalホーム] ; /usr/local/bin/php ./cron.php 1> /dev/null

通常、Drupal管理画面でcron.phpの手動実行をすると、リポート⇒最近のログ項目に"cronの実行が完了しました"とメッセージが出力されます。
しかし、上記の場合は、時間になっても何もメッセージが出力されていませんしアグリゲータの更新もしていない感じで、cron.phpが実行されていないと思える状態でした。
※B-Shellのスクリプトファイルを別途作成して、それを起動するようにもしましたが結果は同じでした。

そこで、現在は以下の様に設定を変更しています。
私は2つのサイトを設置しているので、それぞれ設定しています。
0,30 * * * * /usr/local/bin/GET http://[DrupalサイトAのURL]/cron.php 1> /dev/null
15,45 * * * * /usr/local/bin/GET http://[DrupalサイトBのURL]/cron.php 1> /dev/null

これで、ログメッセージにも記載されましたし、アグリゲータの更新を行ったメッセージも記載されています。
※Feedノードの更新もされていますが、このログには出力されません。コアモジュールと拡張モジュールの違いといったところでしょうか。

安全のために
cron.phpを実行されないようにアクセス制限を設定しておきました。これをしておかないと、ローカルサーバ以外から"http://DrupalサイトURL/cron.php"で簡単に実行できてしまいます。※上のGETを試行している時にいまさらですが気が付いてしまいました。設定は、.htaccessに追記するだけです。

<files ~ "cron\.php$">
order deny,allow
deny from all
allow from [サーバのIPアドレス]
</files>

サーバのIPアドレスですと、メンテナンスで変更になることも考えられますので、サーバ名(uname -nの結果)のほうが良いかもしれませんが正常に動くか不明です。

2009.08.29追記
/etc/hostsにホスト名が登録してあるのでサーバ名でも正常に動きそうです。