Використовуючи 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 (), який викликає цю функцію, якщо він не може знайти потрібний файл. Додайте dpm (func_get_args ()) прямо перед тим, як він викличе drupal_system_listing (), який повинен повідомити, який файл ви не знайдете.
Є декілька причин, через які може виникнути це питання, і на превеликий жаль, я зараз знаю себе з цих причин. Розчаровуючи, якщо ви щойно помітили цю проблему після оновлення ядра Drupal до 7,33+, це може бути помилковим помилкою в будь-якому модулі, навіть якщо ви не оновили цей модуль.
Ви можете спочатку перевірити відому помилку, яку згадує @Berdir, особливо якщо ви нещодавно видаляли "невикористані" модулі з кодової бази. Щоб дізнатись, чи є у вас модулі, які увімкнено, але вилучені з файлової системи, ви можете запустити такий сценарій, як зазначений тут, - або використовувати шахту, написану для встановлення на декількох сайтах із системою друку. з базового каталогу 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 (з коментаря 19 у випуску № 1082892) або невдалим друком у модулі чи темі , наприклад 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()
PHP-дзвінки, що може бути найдорожчим у зв'язку з системними дзвінками вводу-виводу. Простий завантажувальний пристрій Drupal (наприклад time drush ev ""
) може викликати file_scan_directory
кілька тисяч разів (залежно від складності вашої ієрархії папок Drupal, наприклад, кількості модулів та його папок).
У моєму випадку я мав ~ 1500 дзвінків в file_scan_directory
(24 секунд в цілому , що складаються з 2 -х викликів drupal_system_listing
в common.inc
, то інші виклики були розділені рекурсивними викликами file_scan_directory
Іт-я.
Щоб підвищити продуктивність дзвінків вводу-виводу, вам потрібно здійснити кешування файлів. Цього можна досягти, встановивши та включивши 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 слід кешувати .