Локализация через статический файл для Друпала 5

Главные вкладки

Аватар пользователя jason32 jason32 24 июля 2007 в 0:08

Итак, проснулся я в хорошем настроении и решил наконец-то облегчить жизнь тем людям, которых раздражает кол-во запросов к базе у Друпала 5 при переводе. Для Друпал 4.7 я уже такое делал, пришла очередь пятого. Итак, без патча к сожалению не обошлось, можно и не надеяться.
файл common.inc
<?php
function t($string, $args = 0) {
global $locale;
//////////////////////////////////////////////////////////////
if (function_exists('locale_static') && $locale != 'en') {
$string = locale_static($string);
}
else
///////////////////////////////////////////////////////////////
if (function_exists('locale') && $locale != 'en') {
$string = locale($string);
}
if (!$args) {
return $string;
}
else {
// Transform arguments before inserting them
foreach ($args as $key => $value) {
switch ($key[0]) {
// Escaped only
case '@':
$args[$key] = check_plain($value);
break;
// Escaped and placeholder
case '%':
default:
$args[$key] = theme('placeholder', $value);
break;
// Pass-through
case '!':
}
}
return strtr($string, $args);
}
}
?>
Добавлены строчки, которые между вот такими полосками - ///////////////////////////////////////////////////////////////.
C патчами закончили. Приаатачиваю МОДУЛЬ, никаких теперь левых конвертеров Smile
PS Как вы понимаете, модуль сырой и не особенно тестированный, так что просьба сбрасывать сюда вопросы и найденные баги и фичи.

ВложениеРазмер
Файл locale_static-5.x-1.1-dev.tgz2.48 КБ

Комментарии

Аватар пользователя restyler restyler 24 июля 2007 в 2:03

прошу простить мне мою лень, ставить новый сайт на локалхост долго.. дальнейший перевод через веб-админку друпала доступен? Если доступен, то куда переводы сохраняются, в бд?
Привет Самаре из Ульяновска)

Аватар пользователя jason32 jason32 24 июля 2007 в 2:22

да , всё что было, всё остаётся и переводы и заливаются в базу, только можно потом уже из базы сгенерить текстовый файл, из которого и будут браться переводы... Привет Ульяновску!!

Аватар пользователя kiev1 kiev1 24 июля 2007 в 4:50

Спасибо, красиво так получилось.
С алиасами так не выйдет - при большом количестве ссылок - файл будет большой.
Да, и перегенерацию перевода можно делать по крону.

Аватар пользователя sas@drupal.org sas@drupal.org 24 июля 2007 в 9:39

О... спасибо, давай номер VISA баксов кину!
А от чего у тебя настроение поднимается ?
Там вот грозились функцию (system back) по замене в файлах t() на rassian вариант "накрапать", там может я тебе просто настроение подниму, раз ты такой умный и умелый Smile ?

Аватар пользователя emzi emzi 24 июля 2007 в 11:33

Интересно, действительно ли наблюдается прирост производительности при такой конфигурации?
Дело в том, что Друпал при генерации страницы единоразово грузит строки длиной менее 75 символов в память (в статический массив). Таким образом, для большинства вызовов функции t() обращений к базе не происходит. В основном нагрузка на БД происходит при работе в админке, т.к. длинные строки используются именно там.

Аватар пользователя Ю.Б. Ю.Б. 24 июля 2007 в 12:09

Только что прикрутил на недоделанный сайт.
До включения / после (для админского входа)
главная - 4026.77ms / 1514.49 ms
статья - 1284.4ms / 1177.86 ms

(Чем бы еще раз в десять ускорить? Lol

Аватар пользователя PVasili PVasili 24 июля 2007 в 12:25

А несколько раз в разное время проверить? А собрать среднюю статистику? Как будет вести себя на загруженном сайте?
Скорее всего в данном случае разница с очень большой погрешностью. И репрезентативность практически 0...
Как говориться: "геморрой не стоит этих свеч"...

Аватар пользователя Ю.Б. Ю.Б. 24 июля 2007 в 12:44

IMHO тут в основном играет разница в скорости работы php и БД. У меня такое подозрение, что у моего хостера на 6 хостинговых серверов всего один сервер БД.

Аватар пользователя PVasili PVasili 24 июля 2007 в 13:31

Могут быть и ещё и не такие дикие комбинации Smile Посему - всё это хорошо только в теории и $5 решат многие проблемы с производительностью.

Аватар пользователя sas@drupal.org sas@drupal.org 24 июля 2007 в 13:14

В любом случае - самое быстрое это то, что лежит в файлах both with or without t() , значит если основной russian надо менять все там на русский, а дальше у кого что, быстрей работает, либо перевод с файлов либо из базы, но что-то есть большие априорные сомнения, даже при отсутствие репрезентативности и хорошей корреляции, что запрос на каждый t() к базе есть быстрее чем из файлов Smile SQL хорошо "держит" нагрузку - график растет медленно, не первичная нагрузка для обращения даже к одной записи есть достаточно ощутимая величина, а таких запросов и так часто по поводу перевода - не такие задачи задумывалось решать с помощью SQL...

Аватар пользователя emzi emzi 24 июля 2007 в 13:26

On вт, 24/07/2007 - 13:14 sas@drupal.org says:
но что-то есть большие априорные сомнения, даже при отсутствие репрезентативности и хорошей корреляции, что запрос на каждый t() к базе есть быстрее чем из файлов

так нет же там запроса к базе на каждый t(). Один раз оно грузит все мелкие строки и потом ищет их в ассоциативном массиве. Лезет в базу только если не находит, и опять-таки, помещает найденное в массив, т.е. не более одного обращения к базе для строки.

Для сравнивающих производительность: считайте отдельно анонимов и залогиненных, и учитывайте, включен ли page cache

Аватар пользователя sas@drupal.org sas@drupal.org 24 июля 2007 в 15:52

Один раз оно грузит все мелкие строки и потом ищет их в ассоциативном массиве.
Ух ты ... наверно не маленький массив ? А сколько интересно ему места надо, а если Вы сведущи то наверно знаете в что в этом "не маленьком" массиве и много чего еще помещается - "светлая" картина получается, да и только Smile

Аватар пользователя jason32 jason32 24 июля 2007 в 15:01

sas@drupal.orgО... спасибо, давай номер VISA баксов кину!
А от чего у тебя настроение поднимается ?

Вот от таких предложений точно подымается.... Реквизиты в профиль кинул...
Ххочется услышать рационализаторские предложения, чего не хватает в модуле.....
Да, и кстати, у кого -нить работает Хук uninstall - я так и не смог его заставить заработать - глянул, он вообще не работает, у модуль aggregator вписано удаление таблиц при анинсталле - нифига не удаляет

Аватар пользователя emzi emzi 24 июля 2007 в 16:35

On вт, 24/07/2007 - 15:52 sas@drupal.org says:
Ух ты ... наверно не маленький массив

в сериализованном виде в таблице cache массив занимает 215Кб Smile с учетом того, что у меня грузятся строки до 90 байт включительно.
В любом случае это меньше, чем подгружать всю локализацию из файла. Насчет того, что быстрее, как уже говорил - не знаю.
Что касается помещается-не помещается, то важнее не "чтобы помещалось", а чтобы помещалось то, что чаще требуется. Только в этом случае общая производительность сможет вырасти.

Аватар пользователя emzi emzi 24 июля 2007 в 17:22

Про "выгрузки-загрузки" - не понял, что это. А обращения к базе - идут, но не для каждой страницы - а по мере необходимости, не более того.
Касательно размеров: 641К - это только ядро, а еще переводы модулей - в хорошем сайте на мегабайт потянет Smile
Вытаскивать это по мере надобности из базы или грузить при каждом обращении к странице - вопрос философский. Если жить на выделенном сервере, то наверное файловый вариант получше будет...
Но поскольку практика - критерий истины, я бы все-таки опирался на результаты сколько-нибудь продолжительного тестирования

Аватар пользователя Ю.Б. Ю.Б. 24 июля 2007 в 17:43

Интересно, а можно както-то так сделать, чтобы в файл выгружались только переводы front-end, а back по-прежнему из базы брался? Или вообще английским остался.

Аватар пользователя jason32 jason32 24 июля 2007 в 20:28

файл и так весит не ахти , у меня 600кб при кол-ве полей в базе более 5000 - так что не понимаю стенаний по поводу большого размера файлов. По поводу кэша - не знаю, но вроде народ мерит производительность и она выросла , потому что у наших хостеров самое уязвимое место - это именно база, а не php - на это то всегда хвата ресурсов...

Аватар пользователя Ю.Б. Ю.Б. 25 июля 2007 в 1:35

> у наших хостеров самое уязвимое место - это именно база, а не php

И как будто специально в подтверждение этого тезиса мой хостер около полуночи устроил время загрузки первой страницы сайта на Друпале >50 секунд. В то же время в другом окне броузера я вносил записи в каталог другого сайта, там же хостящегося, но сделанного на самопальном движке (два запроса к базе на страницу) - всё летало.

Аватар пользователя jason32 jason32 28 июля 2007 в 11:18

а как можно выложить модуль на Drupal.org ? Кто-нибудь выкладывал? Какой механизм в деталях? Выложат ли модуль в репозиторий при наличии патча ядра, кто как думает? Просветите, плиз, кто выкладывал или знает.....

Аватар пользователя B.X B.X 30 июля 2007 в 21:28

Включил модуль у себя на сайте. Довольно шустро стало работать по ощущениям. Конечно, тесты хорошо бы было провести, но они что-то не вызывают доверия. Спасибо за модуль, прошлым я тоже пользовался. Хорошо бы написать Readme или что-то вроде инструкции по применению.

"а как можно выложить модуль на Drupal.org ? Кто-нибудь выкладывал? Какой механизм в деталях? Выложат ли модуль в репозиторий при наличии патча ядра, кто как думает?"

Это к vadbars'у, он может выкладывать, и больше всего об этом знает...
Здесь вот вся информация: http://drupal.org/contribute/development
Сначала надо получить CVS-аккаунт: http://drupal.org/cvs-account

Модуль выложат, там много модулей делают, которым патчи необходимы. Тот же Advanced Cache.

Аватар пользователя Влад Савицкий Влад Савицкий (не проверено) 14 августа 2007 в 0:12

Если Друпал установлен в подпапке (не в корне сервера), то нужно заменить в locale_static.module:
$dir=$DOCUMENT_ROOT=$_SERVER['DOCUMENT_ROOT'].'/'.file_directory_path();
на
$dir=$DOCUMENT_ROOT=dirname($_SERVER["SCRIPT_FILENAME"]).'/'.file_directory_path();

Аватар пользователя Виталий Виталий (не проверено) 10 октября 2007 в 19:10

Вавилов Евгений, вы молодец.
Я еще не пробовал, но сама идея сделать нормальный способ хранения локализации, давно напрашивалась.
Не понимаю как друпаллеры с орга сами до этого никак не дойдут.

Аватар пользователя VladSavitsky VladSavitsky 13 ноября 2007 в 5:15

Axel предлагал строки прямо в код вшивать, чтобы быстрее было. Мне кажется, что написать такой скриптик, который из РО-файла пропишет в код несложно. Чем такой вариант будет уступать статичному файлу перевода?

Аватар пользователя axel axel 29 ноября 2007 в 23:12

Я ещё раз настоятельно не рекомендую такой подход. Такие радикальные средства имеют смысл очень редко. Для повседневного применения для разгрузки БД будет идеален модуль сделанный jason32, либо адаптация gettext.

Аватар пользователя axel axel 29 ноября 2007 в 23:10

В своё время под некоторые версии 4.x делал патчи для использования библиотеки gettext.
Плюс gettext: можно без изменений использовать po-файлы переводов поставляемые с модулями. При индексации (создание mo-файлов) скорость поиска строк не хуже, чем для php-инклюдов. Минусы: нет возможности правки перевода через вебинтерфейс - только правкой po-файлов. Минусы решения предлагаемого locale_static: больше расход памяти, т.к. переводы из файла при include полностью затягиваются в память каждый раз.

Аватар пользователя Nexor Nexor 14 января 2008 в 3:55

Есть пара рац. предложений.

1. Сохранять в файл только те строки, которые менее N символов длиной, остальное грузить из базы. Достигая компромисса между размером файла и обращениями к базе.

2. Слегка изменить сам формат создаваемого php-файла, можно уменьшить его размер на 3-5%.
или использовать serialize/unserialize, которые работают быстрее, однако размер файла в таком случае увеличится примерно на 10%.

3. Использовать кэш. Если искомой строки нет в кэше , то она считывается из базы и добавляется в кэш-массив. Теоретически, через какое-то время активного пользования сайтом, он должен содержать самые часто используемые строки. Можно сохранять в файл именно их. Хотя в данном случае файл скорее всего будет не нужен, по-сути он и есть кэш.

В 6ке сделано так:
1. Если перевода нет, обращамся к базе и считываем все строки из кэша
2. Если их нет, считываем все строки длиной менее 75 символов и загоняем в кэш
3. Если искомой строки в массиве нет, считываем ее из базы (Здесь бы неплохо еще добавить эту строку в кэш, но в коде drupal этого не реализовано)
4. Если ее и там нет, значит вставляем ее непереведенный прототип в базу и очищаем кэш (хотя логичнее было бы добавить ее туда)

В 5ке примерно также, но есть неоптимизированные места вроде вызова locale_refresh_cache в locale

В общем логика была и есть одна - грузить в кэш все, что меньше 75 символов.

Так что грешить на множественные запросы к базе из-за модуля locale несправедливо.

В большинстве случаев запрос к переводам(к кэшу) на сессию один.
И заменять его считыванием 600-1000 килобайтным файлом, который php еще должен распарсить, мне кажется сомнительным удовольствием.

Я бы пошел по пути накопления в кэше статистически чаще используемых строк, а не строк длиной менее 75 символов, как сделано в drupal, хотя это тоже вопрос спорный.

Аватар пользователя Nexor Nexor 14 января 2008 в 17:03

А вообще все уже сломано до нас.

Пакет патчей advcache кэширует потенциально ресурсоемкие места, такие как конвертация путей в синонимы и обратно, поисковые запросы, таксономию, узлы, форум, комменты.

Патч File-based caching содает кэш в файлах, вместо базы.

Модуль boost позволяет создавать статические страницы в html.

Кто-нибудь пробовал сравнивать производительность кэша на БД и файлах ?
На мой взгляд, хранение кэша в базе не целесообразно, т.к. это просто блочные данные, без всякой структуризации.

Аватар пользователя Nexor Nexor 15 января 2008 в 21:13

В общем, может кого-нибудь заинтересует, идея locale_static вдохновила меня создать include
-based cache, как замену стандартному api кэша drupal.
Идея такова: все кэшируемые данные преображаются в статический php-код и сохраняются в файлах, которые затем загружаются директивой include. Т.к. php все включения держит в памяти, то ускорение заметно.
Таким образом, кэшируются переводы, таксономия, карта синонимов, меню и все что использует cache api.
пока провожу тесты
На первый взгляд скорость генерации страниц админки по сравнению с кэшем в БД возросла на порядок.

Аватар пользователя andypost@drupal.org andypost@drupal.org 16 января 2008 в 19:03

Нужно очень внимательно подходить к вопросу что кешировать!
имхо, например для ноды нужно хранить рендер тизера и тела, а коменты и ссылки хранить отдельно и генерить - они зависсят от прав доступа как и меню

Аватар пользователя Nexor Nexor 18 января 2008 в 1:10

Что кэшировать, думаю отслеживать по ключу и таблице, которые в качестве параметров передают использующие кэш, функции.

Загвоздка возникла в функции cache_clear_all, которая по маске ключа, очищает соответствующие записи в выбранной таблице кэшей.

Т.к. имя файла = некая функция(имя ключа, имя таблицы), то всякие маски и вилдкарды реализовать не просто. Пока, при удалении любого элемента кэша в любой таблице, очищается он весь, что сказывается на производительности.

По поводу сериализации:
В апи 6го drupal, кэш реализован более грамотно, в качестве данных ему передается не строка сериализованных данных, как в 5м, а сами данные.

И только в случае, если их тип не является строкой, происходит сериализация.

serialize/unserialize ресурсоемкие функции, особенно это заметно на массивах в 600-1000 кб.

В случае кэша на файлах, сериализация становится ненужной. В 6ке достаточно заменить cache.inc, в 5ке пришлось убрать serialize/unserialize во всем коде.

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

Путаница получается и усложнение кода.
Логика конечно понятна, одна таблица - один файл. Когда ключей в таблице переваливает за некую отметку, дабы производительность при выборке кэша не упала, создаем новую таблицу.
Я конечно не спец, но по-моему, это от незнания sql. Есть всякие ключи, индексы, можно было б хотя бы создать отдельную таблицу ассоциаций ключ-номер.

Аватар пользователя andypost@drupal.org andypost@drupal.org 18 января 2008 в 5:22

По поводу таблиц - есть предположение, что это сделано специально, чтобы lock table который вызывается при записи в кеш не блокировал весь кеш, а только часть, иначе это станет "бутылочным горлышком", а так как кеш например для страниц очищается достаточно часто - получение переменных и меню будут ждать, пока очистится/обновится таблица - оно и так притормаживает на большой посещаемости!

Аватар пользователя Nexor Nexor 18 января 2008 в 13:31

lock table на самом деле не нужен для одиночной записи в базу. Что можно видеть на примере 6ки, там строки db_lock_table($table); db_unlock_tables(); убрали из кода.

Как написано в комментариях к cache_set, это сделано
1. для более быстрых выборок/вставок.
2. для разделения часто обновляемых и статичных данных.
3. якобы query кэш mysql работает лучше с множеством мелких статичных таблиц.

мне кажется, тут есть спорные моменты. как-то можно было по-другому. Не жесткое определение таблиц усложняет управление таким кэшом.

Аватар пользователя Nexor Nexor 22 января 2008 в 23:31

Может быть найдутся желающие испытать кэш на вложениях, поэтому привожу результат.
Модифицированный файл cache.inc для drupal 5
Установка: распаковать и скопировать cache.inc поверх существующего в папке includes. Вручную создать папку files/cache.
Настройки не требует, никаких своих ключей в базе не создает.

Данные в файлах кэшируются не все подряд.
То, какие таблицы кэшировать в файлах, а какие в базе, определяют ключи массива $keys в функции filecache_enabled.
По-умолчанию в файлах кэшируются таблицы cache,cache_node, cache_path, cache_taxonomy, остальные - как обычно, в БД.

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

Пожелания и сообщения о багах приветствуются.