WordPress под микроскопом
Monstrosa Inside™
Навеяло комментариями к статье "Трудности веб-разработки" и недавним копанием во внутренностях WordPress…
Да, WordPress сама по себе хорошая система (особенно с точки зрения конечного пользователя): в ней можно настроить абсолютно всё (особенно, когда есть деньги и парочка толковых программистов). Но есть одно большое "но": если Вы — опытный программист и волею Фортуны Вам пришлось копаться во внутренностях этого чуда, то неизбужно в скором времени начинаете ощущать себя проктологом-патологоанатомом.
Если хочется кучу всякой гадости, вроде плагинов, редактирования страниц, темплейтов, интегрирования чего попало куда попало — естественно, за это приходится платить. Платить очень дорого.А какое можно сделать «элегантное решение»? Чтобы оно обладало тем же функционалом? Можно только повторить монстра.
Доля истины в этом высказывании, разумеется, есть: чем универсальнее решение, тем оно монстроидальнее. Задача состоит в том, как этого монстра оптимизировать и минимизировать. Есть программисты, а есть быдлокодеры (у меня сегодня два цвета: чёрный и белый). Разница между первыми и вторыми заключается только лишь в умении использовать ресурсы серого вещества, именуемого мозгом. В результате у первых получается элегантное решение, а у вторых — Некрософт Виндовс Нерабочий Труп.
Это я всё к чему? Берём WordPress и смотрим:
MySQL: 45 запросов / 0.550 Потребление памяти: 10.1MB…
У меня немного другая статистика (наверное, сервер мощнее): 50 запросов, 0.05 сек.
Пятьдесят плюс-минус пять запросов: много ли это? Фиг его знает, может и не много, ибо всё познаётся в сравнении. Ну так давайте сравним. Я "надругался" над несчастным WordPress и просто отрубил ему кэш. Готовы?
1462 запроса и 2.02 секунды (лог запросов превышает мегабайт). Те, кто знаком с оптимизацией запросов в MySQL, ужасайтесь вместе со мной.
Можно долго спорить о том, что кэш нельзя выключать, разработчики его не зря включили и всё в том же духе. Ответ: а почему нельзя было сразу спроектировать нормально, чтобы не требовались костыли в виде кэша? По-хорошему, кэш должен использоваться как средство, дающее дополнительное ускорение приложению, но не как средство, обеспечивающее нормальную жизнедеятельность приложения. Скажем так: стимуляторы при умеренном применении могут оказать положительный эффект на человека. Но когда стимуляторы используются только для поддержания жизнидеятельности человека — это уже другая песня.
Вот так.
Но, возможно, в следующей версии…
я бы сказал по другому - используют совсем разные плагины и различные фичи в “теме”. кстати после того теста я ставил разные новые бетаверсии 2ю7 и с каждой немного менялось - то было 37 запросов на главной, теперь стало 43. - имхо это более достоверные цифры, а с файловым кэшем (твой хак не пробовал, а другие аналогичного действия снижали запросы раз в 5, но реально было только хуже
кстати откуда такая огромная цифра 1462? и как ПОЛНОСТЬЮ был отрублен кэш в современных версиях? а то что то уж много сверхподозрительных ОДИНАКОВЫХ строк в приведенном логе? например таких:
SELECT option_name, option_value FROM wp_options WHERE autoload = 'yes
PS понравилась информация по ВП, занесу урл к себе в закладки.
Ответить на данный комментарий
Есть два способа:
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 раз!
Ответить на данный комментарий
[...] плагин хранит свои настройки непосредственно в коде (в файле wp-content/object-cache.php). Это связано с проблемой курицы и яйца, а также с архитектурными особенностями WordPress. [...]
Ответить на данный комментарий