xhprofを使用file_scan_directory()
すると、フロントページのロード時に実行に10秒以上かかることに気付きました。なぜそんなに時間がかかるのでしょうか?
これはxhprofileの出力です:
xhprofを使用file_scan_directory()
すると、フロントページのロード時に実行に10秒以上かかることに気付きました。なぜそんなに時間がかかるのでしょうか?
これはxhprofileの出力です:
回答:
Drupal 7の既知の問題の影響を受けているようです。
おそらく、複数のモジュールが見つからない場合は、モジュールディレクトリの再スキャンを避けてください。これは、インストールに不足しているモジュールがある場合に発生します。システムテーブルを確認してください。
SELECT name, filename FROM system WHERE type = 'module' AND status = 1 ORDER BY filename
まだ有効になっているがファイルシステムにないモジュールをクリーンアップします。
全体として、Drupal 7は、Drupal 6よりもリソースに優しく、スケーラブルです。
これらの関数を見ると、モジュールまたはモジュールの単一のファイルが欠落しているように見えます。drupal_get_filename()を見てください。drupal_system_listing()が呼び出され、要求されたファイルが見つからない場合にこの関数が呼び出されます。drpal_system_listing()を呼び出す直前にdpm(func_get_args())を追加すると、どのファイルが見つからないかがわかります。
この問題が発生する理由はいくつかありますが、非常に残念なことに、私はそれらの理由についてある程度知っています。イライラして、Drupalコアを7.33+にアップグレードした後にこの問題に気付いた場合、そのモジュールをアップグレードしていなくても、これは任意のモジュールのタイプミスである可能性があります。
@Berdirが言及している既知のバグを最初に確認することをお勧めします。特に、最近「未使用」のモジュールをコードベースから削除している場合はなおさらです。有効になっているがファイルシステムから削除されているモジュールがあるかどうかを確認するには、ここに記載されているようなスクリプトを実行するか、drushを使用してシステムにマルチサイトインストール用に作成された鉱山を使用して実行します。 Drupalベースディレクトリから:
find sites -maxdepth 1 -iname '*.*' -type d | sed -rne 's:sites/(.+):echo \1; drush @\1 sqlq "select filename from system where status = 1" | grep "/" | sed -rne "s_(.+)_test -f \\1 || echo \\1_p" | bash:p' | bash
または以下:
while read -r file; do [ -f "$file" ] || echo "$file is missing."; done < <(drush sqlq "SELECT filename FROM system WHERE status = 1")
コードベースから削除されたモジュールを見つけた場合は、@ Berdirが言及した問題の指示に従ってください。
そうでない場合は、削除されたがdrupal_add_js呼び出し(問題#1082892のコメント19から)またはモジュールまたはテーマの不幸な誤植によってまだ追加されているファイルなど、コーディングエラーが原因である可能性があります。例imagecache_actions
(https://drupal.org/node/2381357を参照)。
いずれにせよ、これが発生している理由を正確に把握するには、Drupalが検出できないファイルを正確に知る必要があります。だから、Berdirさんのコメントどおり、あなたは一時的にハックすることができdrupal_get_filename
内bootstrap.inc
だけを呼び出す前に、ログやメッセージの呼び出しを追加することによってdrupal_system_listing()
。Develモジュールがインストールされている場合dpm
は機能します。そうでない場合は、drupal_set_message
またはsyslog を使用できます。例:
dpm(func_get_args());
drupal_set_message(implode(', ', func_get_args()));
syslog(LOG_WARNING, implode(', ', func_get_args()));
Drupalが何を探しているのかがわかったら、そこからどこに行くべきかを理解できるようになるでしょう。私の問題は、存在しないモジュールからのファイルを含めるための呼び出しが原因でしたimagcache_actions
(タイプミスに注意してください)。したがって、imagecache_actions
コードベース(例:)で検索したgrep -r imagcache_actions .
ところ、バージョン1.4 imagecache_canvasactions.module
は、関数呼び出しの外で、ファイルスコープ内にタイプミスがあるmodule_load_include を使用していることがわかりました。繰り返しますが、このエラーはDrupal 7.33以降にアップデートした後にのみ公開されました。の問題が既に作成されておりimagecache_actions
、パッチを適用しており、ビジネスに復帰していることがわかりました。
私は非常に類似した問題を抱えていました- file_scan_directory()
サイトを殺していました。node_modules
カスタムテーマに埋め込まれた巨大なフォルダーgulp
が、キャッシュフラッシュごとにスキャンされていたことがわかりました。これらのファイルをテーマフォルダーから移動して(そしてgulpfileのいくつかのパスを更新して)、それを修正したようです。あるいは、ハッキングできると思いますfile.inc
。
'nomask' => '/(\.\.?|CVS|node_modules)$/', // https://www.drupal.org/node/2329453#comment-9360519
file_scan_directory()
すべてのファイル指定されたディレクトリのために一致して再帰関数です。これはis_dir()
、opendir()
I / Oシステムコールの観点から最も時間がかかる可能性があるPHPコールを使用します。単純なDrupalブートストラップ(例:)time drush ev ""
はfile_scan_directory
、数千回を超える場合があります(Drupalフォルダー階層の複雑さ(モジュールとそのフォルダーの数など)によって異なります)。
私の場合は、へ〜1500回の呼び出しだったfile_scan_directory
から、2つの呼び出しからなる合計で(24秒drupal_system_listing
ではcommon.inc
、他のコールがに再帰呼び出しによって分割された、file_scan_directory
それは自己。
I / O呼び出しのパフォーマンスを向上させるには、ファイルキャッシュを実装する必要があります。これは、OPCache(opcache.enable=1
)をインストールして有効にし、その設定を調整することで実現できます(「PHP OPCacheの使用方法」を参照)。memcached / redisなどのメモリベースのキャッシュを使用することもお勧めします。
コマンドラインインターフェイス(などdrush
)を使用する場合は、も有効にする必要がありますopcache.enable_cli=1
。
変更後、利用可能なデバッガーを使用して、より多くのシステムコールをチェックできます。
例えば
Linuxの場合strace
(ヒットCtrl- C終了):
sudo strace -c -fp $(pgrep -n php)
Unixではdtrace
(PHPのDTrace静的プローブを使用して)、たとえば
sudo dtrace -n 'inline string NAME = "php"; syscall:::entry /(NAME == strstr(NAME, execname)) || (execname == strstr(execname, NAME))/ { @num[probefunc] = count(); }'
あなたはさらに最適化を検討するdrupal_system_listing()
かfile_scan_directory()
、静的キャッシュを実装することで、例えば
--- a/includes/file.inc
+++ b/includes/file.inc
@@ -2104,6 +2104,8 @@ function file_download_access($uri) {
* 'filename', and 'name' members corresponding to the matching files.
*/
function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
+ static $dirs = array();
+
// Merge in defaults.
$options += array(
'nomask' => '/(\.\.?|CVS)$/',
@@ -2120,7 +2122,12 @@ function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
if (!preg_match($options['nomask'], $filename) && $filename[0] != '.') {
$uri = "$dir/$filename";
$uri = file_stream_wrapper_uri_normalize($uri);
- if (is_dir($uri) && $options['recurse']) {
+
+ if (empty($dirs[$uri])) {
+ $dirs[$uri] = is_dir($uri);
+ }
+
+ if ($dirs[$uri] && $options['recurse']) {
// Give priority to files in this folder by merging them in after any subdirectory files.
$files = array_merge(file_scan_directory($uri, $mask, $options, $depth + 1), $files);
または、file_scan_directory
からの呼び出しをキャッシュdrupal_system_listing()
する場合は、次の場所で入手可能なパッチを確認してください。file_scan_directoryをキャッシュする必要があります。