WordPress под микроскопом
Monstrosa Inside™
Навеяло комментариями к статье «Трудности веб-разработки» и недавним копанием во внутренностях WordPress…
Да, WordPress сама по себе хорошая система (особенно с точки зрения конечного пользователя): в ней можно настроить абсолютно всё (особенно, когда есть деньги и парочка толковых программистов). Но есть одно большое «но»: если вы — опытный программист и волею Фортуны вам пришлось копаться во внутренностях этого чуда, то неизбежно в скором времени начинаете ощущать себя проктологом-патологоанатомом.
Если хочется кучу всякой гадости, вроде плагинов, редактирования страниц, темплейтов, интегрирования чего попало куда попало — естественно, за это приходится платить. Платить очень дорого.А какое можно сделать «элегантное решение»? Чтобы оно обладало тем же функционалом? Можно только повторить монстра.
Доля истины в этом высказывании, разумеется, есть: чем универсальнее решение, тем оно монстроидальнее. Задача состоит в том, как этого монстра оптимизировать и минимизировать. Есть программисты, а есть быдлокодеры (у меня сегодня два цвета: чёрный и белый). Разница между первыми и вторыми заключается только лишь в умении использовать ресурсы серого вещества, именуемого мозгом. В результате у первых получается элегантное решение, а у вторых — Некрософт Виндовс Нерабочий Труп.
Это я всё к чему? Берём WordPress и смотрим:
MySQL: 45 запросов / 0.550 Потребление памяти: 10.1MB…
У меня немного другая статистика (наверное, сервер мощнее): 50 запросов, 0.05 сек.
Пятьдесят плюс-минус пять запросов: много ли это? Фиг его знает, может и не много, ибо всё познаётся в сравнении. Ну так давайте сравним. Я «надругался» над несчастным WordPress и просто отрубил ему кэш. Готовы?
1462 запроса и 2.02 секунды (лог запросов превышает мегабайт). Те, кто знаком с оптимизацией запросов в MySQL, ужасайтесь вместе со мной.
Можно долго спорить о том, что кэш нельзя выключать, разработчики его не зря включили и всё в том же духе. Ответ: а почему нельзя было сразу спроектировать нормально, чтобы не требовались костыли в виде кэша? По-хорошему, кэш должен использоваться как средство, дающее дополнительное ускорение приложению, но не как средство, обеспечивающее нормальную жизнедеятельность приложения. Скажем так: стимуляторы при умеренном применении могут оказать положительный эффект на человека. Но когда стимуляторы используются только для поддержания жизнедеятельности человека — это уже другая песня.
Вот так.
Но, возможно, в следующей версии…
Вложения:
- Monstrosa Horribilis (text/html)
Ноя
2008
Комментарии к статье «WordPress под микроскопом» (20) »
Пожалуйста, не используйте эту форму для комментирования! Данная форма предназначена исключительно для ботов.
Оставить комментарий к записи «WordPress под микроскопом»
गते गते पारगते पारसंगते बोधि स्वाहा
Меня зовут Владимир, я программист-фрилансер, специализирующийся на Web-программировании и програмировании под Linux.
По совместительству занимаюсь администрированием LAMP/LNMP-серверов и техническим переводом.


я бы сказал по другому – используют совсем разные плагины и различные фичи в «теме». кстати после того теста я ставил разные новые бетаверсии 2ю7 и с каждой немного менялось – то было 37 запросов на главной, теперь стало 43. – имхо это более достоверные цифры, а с файловым кэшем (твой хак не пробовал, а другие аналогичного действия снижали запросы раз в 5, но реально было только хуже
кстати откуда такая огромная цифра 1462? и как ПОЛНОСТЬЮ был отрублен кэш в современных версиях? а то что то уж много сверхподозрительных ОДИНАКОВЫХ строк в приведенном логе? например таких:
SELECT option_name, option_value FROM wp_options WHERE autoload = 'yesPS понравилась информация по ВП, занесу урл к себе в закладки.
Есть два способа:
wp-includes/cache.phpи добавитьreturn false;в процедуруwp_cache_get():Это к разработчикам
Если серьёзно, это самый большой недостаток в архитектуре проекта. В WordPress кэш занимает ключевую роль — разработчики не предполагали, что кому-то прийдёт в голову его отключать.
Так
get_option()устроен:global $wpdb;
//...пропущено
// prevent non-existent options from triggering multiple queries
$notoptions = wp_cache_get( 'notoptions', 'options' );
if ( isset( $notoptions[$setting] ) )
return $default;
$alloptions = wp_load_alloptions();
if ( isset( $alloptions[$setting] ) ) {
$value = $alloptions[$setting];
} else {
//...пропущено
}
}
function wp_load_alloptions() {
global $wpdb;
$alloptions = wp_cache_get( 'alloptions', 'options' );
if ( !$alloptions ) {
$suppress = $wpdb->suppress_errors();
if ( !$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'" ) )
$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
$wpdb->suppress_errors($suppress);
//...пропущено
}
return $alloptions;
}
То есть при выключенном кэше для каждого вызова
get_option()будут загружаться все опции из БД.Так как кэш никто не выключает, в повседневной жизни это уродство незаметно. Но при реализации persistent caching с сохранением данных в разделяемой (shared) памяти (в PHP есть соответствующее расширение, по-моему,
shm) оно может появиться: размер отводимой памяти ограничен (у меня кэш довольно быстро перешагивает черту 10 мегабайт) и при определённых обстоятельствах кэширующий модуль может просто отказывать в помещении объекта в кэш (плагины имеют тенденцию не подчищать настройки в таблицеwp_optionsпри сносе; так в таблице скапливается мусор, а WP его добросовестно грузит, хотя он не нужен).Если движок универсальный, да еще расширяемый, то приходится жертвовать в пользу оптимизации «сверху», к сожалению. Тем более, что он отдается на растерзание разработчикам, которые, например, забывают подчищать таблицу (которая и так забита – теми же рсс из дашборда) – хотя это простое действие.
Те же RSS из dashboard было бы разумнее хранить в файле — не вижу смысла захламлять базу данных. Одна лента весит где-то 50К, 4 ленты будут весить порядка 200К. Плюс излишки на сериализацию. Как часто среднестатистический блоггер посещает dashboard? Не получается ли так, что закэшированный RSS в таблице успевает состариться? Ну грохнет его WordPress, но и создаст лишнюю фрагментацию в таблице. Часто ли блоггеры делают
OPTIMIZE TABLE? Сомневаюсь.В любом случае, обращение к файлу (в случае RSS) займёт меньше времени, чем обращение к базе.
Но при грамотном проектировании жертв меньше! Взять тот же кэш: на самом деле, очень тяжело написать кэширующий движок с высокой производительностью, учитывая архитектуру WordPress. WP всё время что-то кэширует, но ведь память-то не резиновая! У меня за одно обращение к главной странице в кэш почти 6 мегабайт попадает! Если использовать
shmи хранить кэш в разделяемой памяти, рано или поздно (скорее, рано) встанет вопрос о том, что память нужно освобождать. Я уже не говорю о фрагментации и т.п. Для освобождения памяти будет использоваться какой-нибудь простенький алгоритм, и тут получается такая вещь: выпнул из памяти какой-нибудь блок, а WordPress он понадобился! А при использовании хорошего алгоритма приходится идти на дополнительные издержки, что выливается в ту же производительность: проверять в цикле тысяч по десять элементов с целью нахождения кандидата на вылет будет не всегда быстро. Да, это быстрее, чем лезть в БД при хорошей нагрузке, но медленнее, чем стандартный кэш WordPress (!) при низкой нагрузке. Я не тестировал акселераторы, может быть, там что-то изменится.А что мешало разработчикам спроектировать нормальную систему классов и использовать несколько уровней кэширования? Те же опции: читаем их в локальный protected array один раз и используем в течение всей сессии. Нужно — отдаём кэширующему модулю, если он не возьмёт данные — а и хрен с ними, у нас есть их локальная копия, и в базу мы не полезем. Вот тогда можно было бы использовать более простой алгоритм в кэширующем движке, не переживая, что WordPress полезет несколько раз в базу за одними и теми же данными. С опциями это простой пример, но идея понятна.
Или еще пример: когда я разбирал запросы в
get_calendar(), я нашел способ оптимизировать запрос: если бы мы убралиORDER BY, MySQL не пришлось бы делать файловую сортировку.GROUP BYотсортировал данные в одном порядке, аORDER BYсортировал их в другом. Не помню деталей, ноEXPLAINпоказывал, что безORDER BYне было быUsing filesort. Просто WordPress пришлось бы просматривать массив в обратном порядке. Мелочь, согласен. Но когда таких мелочей много, то на их исправлении можно выиграть существенный прирост в производительности.Я вводил избыточность в тестовую БД и переписывал запросы; в результате на большой базе производительность поднялась в 10 раз!
У меня дошли руки до очень простого доказательства
Я за 20-30 минут переписал один из модулей WordPress, а именно, Options. Переписал в «нашем родном, мудром, объектно-ориентированном, офигительном» стиле.
Код не production-ready (ближе к бете, я бы сказал), но результат на лицо: с выключенным кэшем имеем 382 запроса и 0.6354 секунды. Это гораздо более вменяемый результат, нежели «1462 запроса и 2.02 секунды».
Кому интересно потестировать локально (что очень приветствуется, ибо это, я надеюсь, потом пойдет патчем к WordPress), файл
wp-includes/functions.phpприаттачен к комментарию.functions.zip
при попытке скачать файлик выдает 403
Забыл, что я запретил nginx’у отдавать PHP-файлы (на всякий случай).
Поправил ссылку, теперь там zip.
Клево. Посмотрим.
[...] плагин хранит свои настройки непосредственно в коде (в файле wp-content/object-cache.php). Это связано с проблемой курицы и яйца, а также с архитектурными особенностями WordPress. [...]
Vladimir а вы пытались донести о своих находках, изысканиях до разработчиков WordPress, думаю что если всё так замечательно, то в новых версиях мы бы могли это увидеть. Было бы всем хорошо.
Блин начал читать ваш блог с конца, углубившись увидел что вы сотрудничаете с разработчиками. Прошу прощения за беспокойство. Если даже разработчики не поправят, то можно самостоятельно с вашей помощью облегчить, улучшить себе жизнь.
Пытался… Кое-что должно появиться в 2.7.1. Проблемы производительности уже неоднократно обсуждались в рассылке wp-hackers. Проблема вся в архитектуре WordPress. Для того, чтобы устранить многие недостатки, нужно переписывать большое количество кода.
Владимир, добрый день!
Спасибо за прекраное исследование и дотошную работу.
Так добавили разработчики это решение в WP или нет ?
Сергей, раньше, чем в 2.9 оно вряд ли появится.
PS — если письмо было от Вас, я ответил.
Если речь про письмо о плагине аттача к комментам, то это я
. Плагин свой написал, все равно задача усложненная.
Супер, долго искал, большое спасибо автору!
[...] мусора. За кадром осталась очистка инсулинового кэша WordPress, но идея понятна. Вот только жаль, что оно увидит свет [...]
да, ужасы.
я как-то написал к одному сайту функционал работы сайта без вордпресс, а чисто своим кодом, так у меня свой код просто «летал». админку использовал WordPress. вообще я думаю, что Wordpress надо уходить на другие движки, где есть встроенный функционал форума, блога, новостей, статей, опросов, галерее и прочее, такая CMS, которая даже без кеша «летает».
Владимир, я хотел бы связаться с вами удобным для вас способом, чтобы обсудить возможность и стоимость работы над моим ресурсом.
Сейчас использую WP 3.01, стоит форум SMF 2.0 RC1.2
Хочу превратить в мультисайт, решить вопрос с единой регистрацией на сайте (дочерних блогах) и форуме (есть желание перенести дамп SMF с пользователями в таблицы встроенного в страницы WP форума Simple:Press), сделать человеческую систему интерактивного заполнения форм каталога НКО на основном сайте, возможность фильтрации каталога по разным параметрам.
Ну и оптимизировать все это хозяйство для быстродействия. Выслушать практические советы по редизайну и поисковой оптимизации.
Более детальное тз могу сформулировать конкретнее письмом. К сожалению, не нашел на вашем сайте контактных данных для связи, решил воспользоваться письмом через комментарии.
Организация у нас некоммерческая, свободных денег на услуги пока нет, однако если озадачите стоимостью, то поищем силами своих активистов.
С уважением, Олег
Олег, боюсь, что помочь ничем не могу.