вторник, 26 июля 2011 г.

Drupal & Ajax - как динамически обновить представление View

За основу статьи взят текст для Drupal 6 на английском (http://viziontech.co.il/tutorial2),
который был переведен на русский и адаптирован для Drupal 7.
(Примечание переводчика: Объект "View" оставлен без перевода для упрощения восприятия. Понятие "Display" в контексте View переведено как "Представление".)
Это руководство продолжает серию материалов о "Drupal & Ajax". Предыдущая часть Drupal & Ajax - базовое руководство описывает пошаговую реализацию основ Ajax в Drupal. В этом руководстве мы реализуем динамическое обновление Вашей страницы с результатами View. Так что если Вы не читали предыдущую статью, самое время сделать это сейчас, т.к. здесь мы будем усовершенствовать код предыдущего руководства.
Что мы попытаемся добавить в этом руководстве:
  1. Загрузку существующего view.
  2. Настройку параметров view для выполнения.
  3. Выполнение view.
  4. Загрузку темизированного view в объект JSON и выдачу его.
Как Вы увидите, нет больших различий между выдачей простого статического списка категорий (как это было в базовом руководстве) и выдачей результатов view. В конечном счете, и тот и другой являются HTML потоком, который загружается в объект JSON, возвращаемый клиенту.
Замечание: Если у Вас уже есть view, который Вы хотите искользовать, то можете пропустить шаги с 1 по 3 и использовать свой собственный view (перейти к Шагу 4).

Шаг 1 - Создание типа материала "Simple Product"

Давайте определим новый тип материала. Он будет использоваться для создания материалов, с которыми мы будем работать в этом руководстве.
Назовем наш новый тип материала "Simple Product". Определим для него следующие поля:
  • Description
  • Price
  • Category
Для простоты этого примера ограничимся таким набором полей. Тип для всех полей задайте "simple text".

Шаг 2 - Создаем материал

Сейчас самое время создать несколько материалов типа "Simple Product" для формирования списка продуктов (по меньшей мере 6 штук).
Значение поля "Category" для каждого продукта задайте "books" или "movies" (по 3 продукта на категорию). Эти значения помогут нам позднее формировать список продуктов по категориям.

Шаг3 - Создаем view

Теперь нам нужно создать view. Обучение созданию View выходит за рамки данного руководства, так что если Вы не знакомы с модулем Views, настоятельно рекомендую почитать об этом прежде чем продолжить.
Итак, создаем новый View следующим образом:
  • Имя нового view - "products_by_category".
  • Определяем поля, которые Вы хотите видеть в результате.
  • Определяем аргументы view (тип должен быть Content:Category).
  • Тестируем Ваш View для проверки, выдаются ли продукты в соответствии с заданной в аргументах категорией.

Шаг 4 - Выполнение view

Если Вы помните, в оригинальном коде .module, создан статический список, который загружался в объект JSON и возвращался в качестве результата работы функции:
function dynamic_products_get_by_category_id($cat_id){
$items = '';
switch(
$cat_id){
case
12:
$items = '

  • Product 1
  • Product 2
';
break;
case
20:
$items = '
  • Product 3
  • Product 4
'
;
break;
}
// создание объекта JSON. Объект будет содержать свойство с именем “products” которое задается переменной $items.
return drupal_json_output(array('products'=>$items));
exit;
}
?>
Следующий же код вызывает View, который мы хотим загрузить и в возвращает результат:
function dynamic_products_get_by_category_id($category){ $viewName = 'products_by_category'; // Имя нашего view $args = array($category); // Массив аргументов для view. В данном примере только один аргумент. Ваш реальный View может требовать дополнительных аргументов, которые Вам тогда необходимо будет задать
$displayId = 'page'; // ID представления для view.

//Вызов функции views_embed_view для возврата темизированной выдачи view

$res = views_embed_view($viewName, $displayId, $args); // Создаем объект JSON. Этот объект будет содержать свойство по имени “products”, которое будет задаваться с помощью темизированного результата, выполненного view.
return drupal_json_output(array('products'=>$res));
exit;
}
?>
Несколько замечаний по коду:
Эта строка задает аргументы, которые должны быть переданы во view. В нашем случае view принимает один аргумент, который содержит категорию.
= array($category); ?>
= views_embed_view($viewName, $displayId, $args);
return
drupal_json_output(array('products'=>$res)); ?>
Функция views_embed_view, подробнее о которой можно посмотреть здесь, вызывается для возврата темизированного результата.
Во входных параметрах функция принимает имя view, id представления (т.е. default, page, block, etc.) и массив аргументов для view.
На выходе функции html, содержащий результирующий view. Этот view любой темой по вашему желанию, если она была загружена динамически.
После того, как view получен, мы загружаем его в объект JSON, который будет возвращаться в качестве ответа на запрос AJAX.

Шаг 5 - Код обновленной страницы

Последнее изменение, которое необходимо сделать, - обновить код страницы. В прошлом руководстве наш HTML выглядел так:
Мы должны изменить его так, чтобы передать корректную категорию, которую определили на шаге 2 ("books" или "movies"):

среда, 13 июля 2011 г.

Способы повышения производительности высоконагруженных проектов на CMS Drupal - LVEE

Способы повышения производительности высоконагруженных проектов на CMS Drupal - LVEE: "350.org

Способы повышения производительности высоконагруженных проектов на CMS Drupal

Виталий Иоскевич, Минск, Беларусь

Drupal is a popular CMS/CMF used to power the different types of web-projects worldwide. The desire of developers to make their system competitive in terms of functionality and flexibility sooner or later leads to increase of server load and reduced performance. Extensive functionality, flexibility in configuration and extensibility through third-party modules are undoubtedly a huge advantage, enabling to carry out projects of varying complexity and purpose, but the price often is a poor performance of high loaded Drupal-powered sites. In our review we are going to revise existing standard methods of Drupal performance optimization (both server- and client-side) and demonstrate custom solutions that can be applied to some of the critical areas of Drupal-powered high-loaded website. In our real life example we are going to show how to build Google Map page, capable to show thousands of markers based on Drupal content nodes.

Drupal (7-ая, текущая версия) является достаточно развитой системой управления контентом. Стремление разработчиков сделать свою систему универсальной и более функциональной, чем у конкурентов, рано или поздно приводит к тому, что возрастают нагрузки на сервер, снижается быстродействие. Обширный функционал, гибкость в конфигурировании и расширяемость посредством сторонних модулей несомненно являются огромным преимуществом, благодаря которому позволяет выполнять проекты различной сложности и назначения, но плата за него — низкая производительность готового решения.

Чем больше число использованных на сайте сторонних модулей (в т. ч. собственной разработки), тем ниже производительность сайта при больших нагрузках (большом количестве посетителей), а именно при построении сайтов с предполагаемым большим числом посетителей никак не обойтись стандартным функционалом CMS. Таким образом, данная CMS оказывается весьма требовательной к ресурсам сервера, и в большинстве случаев проблема решается выбором специализированных дорогих хостингов — выделенный сервер или несколько серверов.

Но и при ограниченных возможностях сервера есть способы улучшения производительности сайта. Стандартной системы кэширования Drupal достаточно для нормальной работы среднего сайта при неинтенсивной посещаемости, однако для случая высокой нагрузки на сайт этой системы недостаточно.
Основные методы повышения производительности Drupal:

* включить кэш в модулях, позволяющих кэширование (таких как Views, Panels, Feeds, SWF Tools и т.п.);
* увеличить время жизни кэша для стандартной системы кэширования Drupal. При этом надо иметь ввиду, что посетители будут видеть обновления содержимого значительно позже;
* если нет большой необходимости в статистике, можно выключить стандартные модули statistics и database logging. Они используют дополнительные запросы к БД при загрузке страницы. Кроме того, можно найти альтернативу данным модулям;
* использовать модуль CSS Gzip. Уменьшает размер файлов и количество http-запросов;
* использовать модуль Global Redirect. Предотвращает кэширование дубликатов содержимого сайта по ссылкам псевдонимам (синонимам) в случае использования «Clean URL»;
* использовать модуль Javascript Aggregator. Настройки Drupal позволяют объединить js-файлы, однако этот модуль позволяет еще и уменьшить конечный размер передаваемого файла;
* заменить системный cron на более функциональный модуль Elysia Cron. В отличие от системного, Elysia Cron позволяет распределить задачи по времени одна за одной, а не все вместе, при этом снижая пиковую нагрузку на сервер;
* перенести вызов javascript вниз станицы;
* помещать сторонние библиотеки вне каталога модулей /sites/all/modules – например, в /sites/all/libraries. В таком случае Drupal не будет просматривать ненужные ему файлы;
* конвертировать таблицы MySQL в UTF8 InnoDB;
* создать индексы для медленных запросов Views. Желательно проанализировать такие запросы и увеличить производительность созданием индексов для полей;
* использовать ImageMagick вместо стандартной GD image
* library, т. к. он лучше использует ресурсы сервера и дает лучшее качество изображений;
* использовать модуль Content Delivery Network integration. Он позволяет распределить файлы на множество разделенных серверов. При этом снижается динамическая нагрузка на сервер, но требуется дополнительная плата за каждый сервер;

Наиболее продуктивный способ увеличения производительности – отдельная эффективная система кэширования.

Boost. Одна из лучших систем кэширования для shared hosts. Cоздает копии html-станиц, которые генерирует Drupal, и хранит их в каталоге cache. Используя правила «.htaccess», Boost проверяет, существует ли необходимый файл. Если да, то загружает статичный html, полностью избегая Drupal/PHP/MySQL. Если нет, генерирует файл. Старые файлы удаляются по cron для того, чтобы выводимое содержимое сайта оставалось свежим (актуальным).

Memcache. Серверная система кэширования, сохраняющая
страницы сайта в оперативной памяти сервера. Все что необходимо для эффективной работы в данном случае — быстрое ОЗУ большого объема. Его можно успешно использовать как для кэширования анонимных пользователей, так и для зарегистрированных. Но возможен и вариант, когда Memcache кэширует зарегистрированных пользователей, а Boost используется для кэширования анонимов. К преимуществам варианта можно отнести возможность кэширования анонимов и зарегистрированных пользователей, а к недостаткам — то, что нужен хотя бы VPS, c достаточной оперативной памятью и невозможность работы на shared hosting.

APC (Alternate PHP Cache). Система кэширования op-code для серверов Apache. Подход весьма эффективен при большом числе активных модулей на сайте. Суть системы заключается в кэшировании компилированного байт-кода PHP-скрипта для того, чтобы избежать расходов ресурсов сервера на разбор и компиляцию исходного кода при каждом запросе. Для дальнейшего повышения производительности кэшированный код хранится в общей памяти и непосредственно выполняется оттуда, тем самым сводя к минимуму количество медленных операций чтения файлов и копирования в памяти во время выполнения. К преимуществам относится ускорение компиляции скриптов Drupal и уменьшение использования ресурсов сервера, к недостаткам — необходимость произвести специальное конфигурирование сервера.

Varnish (reverse proxy http-accelerator). Данная система выступает на первом плане над сервером Apache, PHP и Drupal.
Varnish сохраняет кэшированное содержимое в оперативной памяти, и таким образом экономит ресурсы на загрузке Apache и Drupal. В результате этого Varnish предоставляет высокую производительность для кэшированных страниц для анонимных пользователей и является предпочтительным вариантом для сложных ресурсоемких сайтов, требующих значительной масштабируемости. Для работы с Drupal 6 необходима была отдельная «оптимизированная» сборка дистрибутива под названием PressFlow и установка модуля интеграции Varnish HTTP Accelerator Integration. Для текущей версии Drupal достаточно установки модуля.
Пример проекта с высокой нагрузкой — 350.org (Drupal 6)

К характеристикам проекта можно отнести следующие:

* 150 000+ уникальных посетителей в день
* 6000+ ивентов, созданных пользователями
* ок. 500 авторизованных пользователей постоянно на сайте
* самая посещаемая страница: карта ивентов (/map)

Кэширование критично как для анонимов, так и для авторизованных пользователей. Используется Pressflow/Varnish и специальные меры для повышения производительности:

* Отказ от Views для генерации больших массивов данных
* XML-файл на диск вместо DB-кэша (плюсы/минусы)
* Кэширование на диск всех RSS-фидов
* Ajax-запросы информации для маркеров на карте.

вторник, 12 июля 2011 г.

Чистые ссылки. Что это? Реализация. Проблемы и решения

"Чистыми" URL (или "чистыми" ссылками, в английском написании "clean URLs") называют URL вида: http://mysite.com/node/1. Т.е. в теле ссылки нет никаких знаков "?" или "&". Обычно ссылка в Drupal выглядит как: http://mysite.com/index.php?q=node/1, что согласитесь намного менее приятно. Именно поэтому придуман механизм "чистых" URL, которые более удобочитаемы и понятны.

Хотя в Drupal 5 "чистые" URL включались в админке Drupal, а в Drupal 6 предлагается включить "чистые" URL прямо при установке (если это возможно, конечно), сам Drupal к реализации "чистых" URL не имеет никакого отношения. Единственное, что делает Drupal, если включены чистые ссылки - это при формировании страницы учитывает это и показывает ссылки в "чистом" виде. А всю работу по корректному отображению страниц, адресованых по "чистым" URL, делает веб-сервер. Поскольку в большинстве случаев в качестве веб-севрера всё-таки работает Apache, то можно говорить, что всю необходимую для "чистых" URL работу проделывает модуль Apache mod_rewrite, а Drupal лишь предоставляет этому модулю необходимые настройки.

Где же хранятся эти настройки и что они из себя представляют? Настройки для модуля mod_rewrite находятся в файле .htaccess, который находится в корневом каталоге Drupal (т.е. там где лежит index.php). После установки Drupal со включенными "чистыми" URL они выглядят так:


RewriteEngine on

# RewriteBase /

# Rewrite URLs of the form 'x' to the form 'index.php?q=x'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]


Я показал только интересующие нас строки из файла .htaccess, на самом деле их там намного больше!

Итак, поясняю, что же здесь написано. Как можно заметить весь блок находится между строками:


...


Эти строки служат для того, чтобы содержимое блока обрабатывалось веб-сервером только если установлен и включен модуль mod_rewrite. Вообще-то, поскольку этот модуль почти всегда установлен и включен, их можно было бы опустить. Однако, если по какой-то причине модуль не установлен или не включен, то без этих строк веб-сервер будет выдавать ошибку 500, потому что не знает, что делать с директивами внутри блока.

Далее, директива

RewriteEngine On

говорит о том, что для данного каталога (и всех его подкаталогов, если в них самих не указано отдельно) включена обработка URL с помощью модуля mod_rewrite. Если вам в каком-либо подкаталоге захочется выключить эту обработку или даже вообще захочется отказаться от "чистых" URL, то всё что вам нужно сделать это указать "Off" вместо "On", не удаляя собственно никаких правил преобразования URL.

Далее, обратите внимание на строку

# RewriteBase /

Вообще-то, строки, которые начинаются на "#" считаются комментариями и не рассматриваются как правила для модуля mod_rewrite. Но данная строка приведена мной, потому что она может играть важную роль, если ваш Drupal установлен не в корневой каталог вашего сайта, а является лишь его разделом (например, если он установлен в подкаталог drupal (http://mysite.com/drupal)). Об этом я расскажу ниже в разделе решения возможных проблем.

И вот, наконец, мы добрались до нужного нам правила, состоящего из нескольких строк:

# Rewrite URLs of the form 'x' to the form 'index.php?q=x'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

Как видите, правило снабжено английским комментарием "Rewrite URLs of the form 'x' to the form 'index.php?q=x'" (Преобразовать URL 'x' в конструкциях типа 'index.php?q=x'). Разьясняю подробно каждую строчку. Для начала обратите внимание, что сперва идёт три строки RewriteCond и только одна строка RewriteRule. Строки RewriteCond описывают условия срабатывания правила преобразования URL, а строка RewriteCond описывает собственно само правило. Последовательно следующие друг за другом строки RewriteCond обьединяются с уловием логического "И". Итак, первые три строки с RewriteCond говорят следующее: если указанное в URL имя не является существующим файлом И, при этом, указанное в URL имя не является существующим каталогом, И, при этом не совпадает с 'favicon.ico', то применить нижеследующее правило.... Т.е. если вы, например создадите на своём сайте файл или каталог с именем "node/1" и при этом наберёте в браузере http://mysite.com/node/1, то даже при включенных "чистых" URL правило не сработает и вам будет отдан существующий файл node/1 (если это файл) или индексный файл каталога node/1 (если это каталог и в нём есть индексный файл).

И в заключении, разберём собственно строку правила с преобразованием URL. Правило преобразования URL в строке RewriteRule говорит: заменить ВСЁ что указанно в пути URL, подставив вначале "index.php?q=", а затем весь путь.. Конструкция "^(.*)$" в первой части (части поиска) означает шаблон, который совпадает с полным путём в URL (т.е. всем, что находится за http://имя_сайта), а конструкция во второй (подстановочной части) "$1" означает первое найденное совпадение с шаблоном (т.е. в нашем случае весь путь). После выполнения данного правила, например над URL http://mysite.com/node/1, веб-серверу будет передан другой URL: http://mysite.com/index.php?q=node/1. И именно в таком виде данный URL будет обработан самим Drupal.

Вот, собственно, и весь секрет "чистых" URL и того как они работают
Возможные проблемы и пути их решения

Новички часто сталкиваются с тем, что у них не работают "чистые" URL. Начинаются судорожные поиски решения в самом Drupal, насилование админки и т.д. Но как вы уже поняли после прочтения данной статьи, сам Drupal не имеет к правильной работе "чистых" URL почти никакого отношения. Поэтому, для настройки "чистых" URL необходимо корректно настроить веб-севрер. Когда Drupal увидит, что веб-сервер настроен корректно, то легко начнёт работать с "чистыми" URL..

Итак не работают "чистые" ссылки:

1. Проверьте возможно ли их включить в административном разделе: /admin/settings/clean-urls (здесь и далее путь указан без указания: http://имя_сайта). Если они включаются значит и проблемы больше нет, работайте!
2. Проверьте наличие в файле .htaccess в корневом каталоге вашего Drupal строк, которые были описаны в статье. Если файла .htaccess нет или в нём нет означеных строк, то создайте файл и добавьте строки. Затем вновь переходите к п.1
3. Если есть .htaccess и в нём необходимые строки, а всё-равно ничего не работает, то убедитесь, что у вашего хостинг-провайдера в настройках вашего хостинга разрешено использовать файлы .htaccess. Некоторые хостинг-провайдеры отключают такую возможность по-умолчанию! Убедитесь также, что модуль mod_rewrite у вашего веб-сервера установлен и включен. Вы можете это выяснить также у вашего хостинг-провайдера (хостера).
4. Убедитесь, что в настройках вашего сайта, для каталога сайта, в директиве AllowOverride стоит как минимум значение Limit FileInfo Options Indexes, а лучше All. Если вам недоступен даже на чтение ваш файл с настройками сайта, обратитесь с этим вопросом к хостеру. Поскольку FileInfo контрлирует работоспособность директив mod_rewrite, то без включения этой опции чистые ссылки работать не будут.
5. Если вы прошли пукнты 2,3,4 и не работает, то убедитесь, что перед означеными строками нет других правил для mod_rewrite, которые могут конфликтовать с описанными в данной статье правилами.
6. Если и конфликтующих правил нет и не помогает, попробуйте заменить строчку

RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]

на

RewriteRule ^(.*)$ /index.php?q=$1 [L,QSA]

7. Если не помогает и это, попробуйте поиграться с директивой RewriteBase. Возможно вам поможет установка в этой директиве либо относительного пути для вашего каталога с Drupal (например, если вы ставите Drupal не в корневой каталог сайта, а в подкаталог). Т.е. при названии подкаталога скажем drupal, попробуйте указать

RewriteBase /drupal

Возможно это и не все проблемы, которые случаются при неработающих "чистых" URL, однако в 99% написанное вам поможет. А если вы нашли новую проблему и решение, присылайте на указанный ниже адрес электронной почты для назидания потомкам.