file_scan_directory ()를 실행하는 데 약 10 초가 걸립니다.


10

xhprof를 사용 file_scan_directory()하면 프론트 페이지가로드 될 때 10 초 이상 걸리는 것으로 나타났습니다 . 왜 그렇게 오래 걸립니까?

이것은 xhprofile의 출력입니다.

스크린 샷


프론트 페이지는 파일 시스템 경로가 아니라 데이터베이스 테이블의 항목이므로 "file_scan_directory" "프론트 페이지"는 수행 할 수 없습니다.
Letharion

@ 레타 리온 나는 당신이 내 질문을 오해했다고 생각합니다. 프론트 페이지가로드 될 때이 함수가 걸리는 시간을 의미합니다. 질문을 편집했습니다.
hknik 2016 년

프론트 페이지는 실제로 특정 시간이 걸리는 기능과 관련이 있습니까? 실제로 어떤 디렉토리를 스캔하고 있습니까? 디렉토리에 무엇입니까?
Letharion

아하! 나는 당신이 함수를 직접 호출했다고 생각하고 왜 더 자세한 정보를 제공하지 않았는지 궁금합니다. Berdir의 답변은 매우 합리적입니다. :)
Letharion

답변:


14

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 () 을 호출하여 요청 된 파일을 찾을 수없는 경우이 함수를 호출합니다. drupal_system_listing ()을 호출하기 직전에 dpm (func_get_args ())를 추가하면 찾을 수없는 파일을 알려줍니다.


안타깝게도 (!) 파일 시스템에 모듈이 없습니다
hknik

그런 다음 전화가 어디에서 왔는지 추적해야합니다. 맞춤형 또는 Contrib 모듈이 잘못하고있을 수 있습니다. file_scan_directory ()의 상위 함수를 클릭하고 초기 함수를 상위 함수 목록으로 업데이트하십시오.
Berdir

이러한 기능을 보면, 그것은 않는 이 모듈 또는 어쩌면 모듈의 단일 파일을 누락처럼 보인다. drupal_get_filename : api.drupal.org/api/drupal/includes!bootstrap.inc/function/…을 살펴보십시오 . 요청 된 파일을 찾을 수 없으면 함수를 호출합니다. drupal_system_listing ()을 호출하기 직전에 dpm (func_get_args ())를 추가하면 찾을 수없는 함수를 알려줍니다.
Berdir

@Berdir 마지막 ​​코멘트는 관련이 있으므로 답에 있어야합니다.
kiamlaluno

"Drupal 7의 알려진 문제"및 "재 탐색 모듈 디렉토리 피하기"링크가 끊어졌습니다. 둘 다 이전 스택 교환 답변입니다. 다른 참조가 있습니까?
rfay

4

이 문제가 발생하는 데는 몇 가지 이유가 있으며, 큰 실망으로, 나는 그 이유에 대해 어느 정도 지식이 있습니다. 실망스럽게도 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_filenamebootstrap.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.modulemodule_load_include 를 사용 한다는 것을 알았습니다 . 이 오류는 Drupal 7.33+로 업데이트 한 후에 만 ​​노출되었습니다. 에 대한 문제가 이미 생성 imagecache_actions되어 패치를 적용했으며 비즈니스에 복귀 한 것으로 나타났습니다.


2

나는 매우 비슷한 문제가 있었다- file_scan_directory()사이트를 죽이고 있었다. 캐시가 플러시 될 때마다 node_modules사용자 정의 테마에 포함 된 huuge 폴더 gulp가 스캔되었습니다. 이 파일을 테마 폴더 밖으로 옮기고 gulpfile의 일부 경로를 업데이트하면 문제가 해결 된 것으로 보입니다. 또는 해킹 할 수 있다고 생각합니다 file.inc.

'nomask' => '/(\.\.?|CVS|node_modules)$/', // https://www.drupal.org/node/2329453#comment-9360519


0

file_scan_directory()모든 파일을 지정된 디렉토리와 일치 재귀 함수입니다. 그것은 사용의 is_dir()opendir()/ O 시스템 호출 I의 측면에서 대부분의 시간 비용이있을 수 있습니다 PHP 호출. 간단한 Drupal 부트 스트랩 (예 :)은 Drupal 폴더 계층 구조의 복잡성 (예 : 모듈 및 폴더 수)에 따라 수천 번 이상 time drush ev ""호출 할 수 있습니다 file_scan_directory.

내 경우에는 내가에 ~ 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.

변경 후 사용 가능한 일부 디버거를 사용하여 더 많은 소비가있는 syscall을 확인할 수 있습니다.

예 :

  • Linux를 사용하는 경우 strace(히트 Ctrl- C완료) :

    sudo strace -c -fp $(pgrep -n php)
  • 유닉스에서 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는 캐시되어야합니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.