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 () 을 호출하여 요청 된 파일을 찾을 수없는 경우이 함수를 호출합니다. drupal_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
사용자 정의 테마에 포함 된 huuge 폴더 gulp
가 스캔되었습니다. 이 파일을 테마 폴더 밖으로 옮기고 gulpfile의 일부 경로를 업데이트하면 문제가 해결 된 것으로 보입니다. 또는 해킹 할 수 있다고 생각합니다 file.inc
.
'nomask' => '/(\.\.?|CVS|node_modules)$/', // https://www.drupal.org/node/2329453#comment-9360519
는 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는 캐시되어야합니다 .