Публикации

Пользователь:

Пароль:


Запомнить

Регистрация
Забыли пароль?



Пользователей: 3920
Новичок: panikaj0
Поддержи проект
Поддержите проект Webmoney
R197422573540
E197270426287
Z701768662172
Сказали «Спасибо»

Навигация

Про пути уменьшения нагрузки на базу данных


Автор: Fanat1k
 10.0 - 5 голосов -

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

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

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

Все что я пишу основывается на семилетнем опыте владельца самого посещаемого сайта в России на движке е107 - в день стабильно 10-30 тыс пользователей, в среднем 1600000 просмотров в сутки. По-крайней мере большие мне неизвестны - филка имхо не в счет, у них е107 служит только для новостей, основная часть посещает только форум IPB и основная нагрузка на базу идет именно с него.

Для все еще сомневающихся скриншотик из phpmyadmin - поверьте, без подобной оптимизации дела были бы значительно хуже
+ Показать

Ну и наверное подобная оптимизация важна при посещаемости от 500 человек в день и выше. Если у вас в день ходит 50 человек и смотрит 1000 страниц, то морочится с какой-то там оптимизацией не стоит.

Итак, я использую 4 метода отпимизации работы с е107:
1) Индексы на таблицы
2) Оптимизация запросов в class2.php
3) кэширование результатов работы плагинов
4) оптимизация наиболее медленных запросов

1) Индексы на таблицы
Это абсолютно понятная нормальная человеку вещь (вопрос конечно почему ее нет по-умолчанию в е107). Кому непонятно -
Все нагруженные таблицы, то есть как минимум #comments, #news, #private_msg, #rate, #user, #user_extended должны быть с индексами к соответствующим полям int (кое-где и к varchar)
Например, к таблице #comments у меня забито следующее:
+ Показать

В общем индексов много не бывает (ну кроме как к совсем часто изменяемым полям), поэтому phpmyadmin в руки и вперед

2) Оптимизация запросов в class2.php
Как некоторым здесь должно быть известно, class2.php инклюдится при обращении к любой странице движка e107 (ну кроме может быть rss, printnews и request), поэтому оптимизация запросов в нем сказывается сразу на всем сайте.
Суть самой оптимизации просто - уменьшение количества избыточно выполняемых запросов. К примеру, на мой взгляд совершенно излишне при генерации каждой страницы очищать временные таблицы, удалять забаненных пользователей и тд. Кроме лишней нагрузки на базу толку от этого - ноль. Поэтому нужно немного модифицировать код class2.php таким образом, чтобы подобные запросы выполнялись к примеру 1 раз на 100 (1000, 10000) генераций страниц.
Модификация кода простейшая - перед каждым запросом ставите if (rand(0, X) == 1) { код_запроса; } где X должен быть подобран эмпирически именно для вашего сайта.
Напишу то что изменил лично я, но имхо это с оглядкой на разницу в посещаемости не лишне будет сделать каждому.
+ Показать

Кстати, каждый из этих четырех запросов может вызывать блокировки таблиц, что является еще одним поводом вызывать их пореже

3) кэширование результатов работы плагинов
В е107 очень удобно добавлять различные статистические плагины в правую или левую часть сайта. Например, последние комменты, случайная картинка, последние закачки, кто онлайн и прочее.
Многие злоупотребляют этим делом, в результате при генерации каждой страницы бедный движок трудолюбиво и вхолостую проводит очень много вычислений. Например, для получения 5 последних комментов ему нужно:
1) считать в память всю таблицу комментов
2) если требуется только комменты к например новостям, то отфильтровать ее
3) отсортировать получившиеся данные по времени (а скажем 50 тыс комментов даже при наличии индекса будут отсортированы не так уж и быстро)
4) взять 5 первых комментов

Самое смешное, что эти 5 комментов будут с очень большой вероятностью совпадать с теми, которые только что были сгенерированы для другого пользователя, да и вообще первый новый коммент появится через 3 часа
Поэтому понятно, что вывод на главную только к примеру последних новостей, последних комментов, последних сообщений форума и последних закачек нагрузят базу данных по-полной абсолютно бессмысленной работой.
Но допустим вам жизненно необходимо выводить всю эту информация на каждой странице каждому пользователю. Мне например необходимо, так как это и удобно, и функционально, и полезно. Что делать?

Выход очень прост - надо проводить все эти вычисления только один раз, результат записывать в базу, а затем в течение определенного времени (ну например вы считаете, что список последних комментов следует обновлять только каждые 10 минут) просто выводить пользователю.
Можно подумать, что одно обращение к базе (к таблице комментов) просто заменяется обращением к таблице с хранимыми результатами. Это не так. В плагине может быть несколько сложных запросов (как показано выше - фильтрация, сортировка), в то время как вы меняете их на один простой (выборка).
Более того, никто не мещает вам (я например даже рекомендую ) сделать эту выборку отдельно не в каждом плагине, а только один раз при генерации страницы. Тогда получится, что запросы _всех_ подобных плагинов (10, 20, ...) в общем случае будут выполняться за один-единственный select.

Теперь о том как это сделать. Все очень просто:
1) Создаем в базе данных таблицу #mycache
  1. CREATE TABLE IF NOT EXISTS `e107_mycache` (
  2.   `mycache_id` tinyint(4) NOT NULL default '0',
  3.   `mycache_datetime` int(12) NOT NULL default '0',
  4.   `mycache_title` varchar(50) NOT NULL default '',
  5.   `mycache_description` text NOT NULL,
  6.   PRIMARY KEY  (`mycache_id`)
  7. ) ENGINE=MyISAM;

mycache_id - идентификатор плагина
mycache_datetime - время последнего обновления данных данных
mycache_title - заголовок данных
mycache_description - сами закэшированные данные

2) В class2.php где-нибудь в середине добавляем:
+ Показать

3) В плагине который собрались отпимизировать надо "обернуть" весь исполняемый код вставками для анализа последнего обновления и для сохранения данных в базе.
На примере - вот код плагина, выводящего список последних новостей:
+ Показать


Теперь тоже самое, но уже с оберткой:
+ Показать

Кому надо должны понять идею

4) оптимизация наиболее медленных запросов
Это самый сложный путь, поэтому думаю именно вам он может уже и не понадобиться если вы проделали 1-2-3
Поэтому мне и лень уже его расписывать, кому надо, прочитайте про:
1) определение медленных запросов
2) их оптимизацию

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

Автор статьи: Fanat1k
Обсуждение в этой ветке форума