Особенности средних нагрузок

В этой статье я постараюсь описать те проблемы и пути их решения, с которыми я впервые столкнулся при работе с проектами с суточной посещаемостью 300 тысяч человек и более.

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

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

Все проводимые работы можно условно разделить на несколько фронтов – база данных, сами скрипты и организация группы серверов.

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

Допустим, у нас есть социальная сеть вроде news2.ru. Зайдя на главную страницу сайта, мы можем увидеть список рекомендованных новостей и всякие другие полезные списки, которые отображаются на каждой странице сайта. Такие элементы далее будем называть виджетами (не совсем корректно, но условимся что это так).

Запросы к БД

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

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

Такие “горячие” данные обычно кэшируют в памяти через memcached. Кэшировать их на файлах было бы не разумно, потому что база данных, по сути, тоже файловое хранилище и нагрузка на жесткий диск изменится незначительно.

Итак, как только мы начнем кэшировать данные в памяти, нагрузка на сервер сократится в разы.

Примечание:
Нагрузка на сервер не является абстрактной величиной и может быть количественно измерена. В начале статьи я писал о том, что у нас есть доступ к выделенному серверу. Я работал с выделенными серверами под управлением ОС FreeBSD, поэтому буду рассматривать на ее примере. Чтобы посмотреть насколько загружен Ваш сервер в текущий момент, воспользуйтесь командой “top” – она покажет загрузку каждого из процессоров в виде десятичного числа (Например, 1.05 или 10.2 и т.д.).

Что ж, теперь у нас есть средство для мониторинга загрузки сервера.

Далее, несмотря на то, что мы кэшировали большую часть “лишних” запросов, нам необходимо оптимизировать оставшуюся часть.

Тут нам на помощь приходит второе средство мониторинга загрузки (на этот раз базы данных).
Я работал с СУБД MySQL, поэтому далее буду рассматривать только ее. При заходе в консоль рабочей базы данных пишем запрос: show full processlist; либо show processlist;

Эти запросы выводят список активных запросов к базе данных (которые выполняются в настоящий момент).
Кроме самих запросов в нем присутствует такой параметр как время ее выполнения. Запросы, время выполнения у которых самое большое необходимо либо оптимизировать, либо кэшировать (если они еще не кэшированы).

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

Частые INSERT`ы.

Последнее, что хочу заметить относительно запросов к базе данных – это ведение статистики. Во всех системах статистики производится частые вставки (INSERT) в одну таблицу или группу таблиц. При больших нагрузках все запросы на запись могут не успевать обрабатываться , поэтому они будут сбрасываться. Чтобы этого не происходило, вместо запросов вида INSERT, используйте запись INSERT DELAYED, тогда запросы будут просто суваться в очередь, которая со временем будет разгребаться сервером.

Сессии

Сессии, как и база данных, по сути, является файловым хранилищем (файлы сессий хранятся на жестком диске сервера), поэтому обращение к ним следует минимизировать. Довольно часто данные, которые хранятся в сессиях, можно перенести в куки пользователей. В этом случае нагрузка с сервера будет снята. Единственное, что необходимо помнить в этом случае – это то, что данные в куках находятся под полным контролем пользователей и некоторые их них могут изменить их. Меры защиты для чувствительных данных должны быть приняты в этом случае.

Организация системы серверов.

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

База данных

Когда одна база данных не справляется с количеством запросов, нужно добавить еще один сервер для нее.
Однако, новые возможности, как правило, рождают и новые обязательства. При добавлении нового сервера базы данных мы не сможем тупо разделить весь трафик между ними средствами системного администрирования. Нам нужно будет определить какие запросы направлять на вторую БД. В нашем случае это может быть вся система статистики и еще какие-нибудь служебные данные. С этим все ясно.

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

Схемы репликации бывают разными, как и способы передачи данных используемые в них (об этом можно почитать подробнее в инете).

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

Веб-сервера.

Распределение трафика между веб-серверами уже можно настроить средствами системного администрирования, однако, тут возникает ряд других проблем.

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

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

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

Для решения второй проблемы я знаю только один способ – хранить данные вместо сессий в куках пользователя. Если кто-то подскажет что-то еще буду очень рад.

На этом у меня все. Удачи.





Читайте также:



28 Ответов на “Особенности средних нагрузок”

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

    “Для решения второй проблемы я знаю только один способ – хранить данные вместо сессий в куках пользователя. Если кто-то подскажет что-то еще буду очень рад.”
    Как вариант, хранить в куках id сессии, а всю иё инфу - в мемкеше (плюс БД на случай протухания кеша).

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

    “Для решения второй проблемы я знаю только один способ – хранить данные вместо сессий в куках пользователя. Если кто-то подскажет что-то еще буду очень рад.”
    Как вариант, хранить в куках id сессии, а всю её инфу - в мемкеше (плюс БД на случай протухания кеша).

  3. >база данных, по сути, тоже файловое хранилище
    1. Смотря какая СУБД и какой Storage Engine (см. MySQL MEMORY например)
    2. Мемкеш тоже БД

  4. >Другой способ определения запросов, которые нужно оптимизировать

    смотрите log-slow-queries

  5. >Сессии

    Мы как раз для этого используем Memcached

  6. >Для решения второй проблемы я знаю только один способ – хранить данные вместо сессий в куках пользователя. Если кто-то подскажет что-то еще буду очень рад.

    еще раз - memcache

  7. 2 Глеб Белогорцев:
    “Как вариант, хранить в куках id сессии, а всю иё инфу - в мемкеше (плюс БД на случай протухания кеша).”
    Этот вариант будет работать только в случае когда два сервера связаны в локальную сеть (в одной стойке стоят например в дата центре).

  8. >Этот вариант будет работать только в случае когда два сервера связаны в локальную сеть

    Почему?

  9. 2 adw0rd: Если обращаться в мемкешу через сеть, то это будет тормознуто работать, особенно если учитывать что там объемы данных будут большие при нагрузках.

  10. 2 cryptus: так ведь это только данные сессии, их много навряд ли будет. Конечно, надо смотреть в каждом конкретном случае, но скорее всего, сходить на другой сервер за готовыми данными будет быстрее, чем собирать их из БД (которая, кстати, тоже может оказаться на отдельном сервере).

  11. Людмила

    Что такое Cookia?И зачем он нужен?

  12. novice
  13. 2Людмила [ссылка]

  14. > INSERT DELAYED
    Этот режим не поддерживается InnoDB, поэтому в большинстве таблиц им не воспользоваться. Использовать MyISAM и отложенные вставки надо на таблицах, доля вставок записей в которых велика относительно запросов select. Это, например, таблицы хранения “сырых” данных по статистике посещения. В остальных случаях не целесообразно отказываться от преимуществ InnoDB.

  15. 300 человек в день равносильно тому что у вас одновременно не более 10 человек на сайте.

    Вот у меня одновременно от 60 до 150 человек, как стало переваливать за 100, тогда пришлось оптимизировать.

  16. Для больших проектов лучше использовать DLE.Особенно кеш мне там нравиться

  17. “300 тысяч человек” - АХРЕНЕТЬ!!! (завидую)
    Толковая статейка. Хотелось бы узнать из Вашего блога больше про XML. Вы очень доходчиво пишете.

  18. Интересно…. реальная цифра…. с трудом верица мне..

  19. Спасибо. Продолжение было бы весьма интересно.

  20. >> Для больших проектов лучше использовать DLE.Особенно кеш >> мне там нравиться

    Серьезно? ) Цифры есть или голословно?

    Статья неплохая, правда вот теория кругом одна, нет бы что-нибудь из реализации показать )

  21. Ivan

    Вы еще не упомянули про раздельную обработку статики и динамики. Статику (картинки, джаваскрипт и CSS) можно отдавать легким сервером, наподобие nginxX или lighttpd.
    Динамику можно перекидывать на Апач или другой сервер (томкат, например, если используется Java).
    Т.е. используется двухзвенная система из веб-серверов. На фронте (на морде) стоит легкий сервер, который обрабатывает статику. А запросы на динамику он передает на бек-енд сервер (Апач, томкат и т.п.).

    Я бы начинал оптимизировать именно с этого.
    Второй вещью, которой бы сделал - это использование кешера, типа memcached.

  22. asserte

    Немного критики )

    >> Во всех системах статистики производится частые вставки (INSERT) в одну таблицу или группу таблиц…
    Во всех системах статистики ведется т.н. промежуточное кеширование информации. Т.е. висит себе демон в памяти и сбрасывает все в файлик с критической частотой. А по расписанию кидает все в базу (вспоминаем пересчеты статистики li.ru и иже с ними)

    >> Другой случай может оказаться сложнее, и в другую БД будет писаться информация, которая потом будет использоваться на проекте (на основном сервере). Поэтому данные двух баз данных нужно как-то синхронизировать.
    Схему репликации Master-Master крайне не советую использовать.

    По поводу базы. Некритичные данные можно инсертить на мастер-сервер, а забирать из слейв-сервера. Но такая схема работы подразумевает жесткое условие: Идет обновление данных - работаем с мастером. Идет чтение - работаем со слейвом. На проектах, с 1к запросами в секунду (биллинг) только так и получается балансировать на грани сохранения резерва вычислительной мощности двух серверов.

    >> Сессии, как и база данных, по сути, является файловым хранилищем (файлы сессий хранятся на жестком диске сервера), поэтому обращение к ним следует минимизировать.
    Даже если вы уберете данные из сессии, то идентификатор-то все-равно лежит на ФС. А скорость доступа к файлу, в основном, зависит от скорости поиска. Т.е. изменение размера файла сессии с 5кб на 1кб вы ничего не получите. Только геморрой и будете тратить лишнее процессорное время на операции анализа куков (или, неявно, воспользуетесь стандартным разборщиком). Обратите внимание, что от хранения файлов сессий на ФС вы так и не отказались 😉

    >> Скрипты, как их не оптимизируй создают большую нагрузку на процессор.
    Число пи высчитываете? При загрузке процессора 0.75 php-cgi (спаунинг) ест не более 0.01. Остальное - СУБД.

    :)

  23. Иван

    Хорошая статья. Интересная. Об этом можно целый блог отдельный открыть. А может быть такой уже есть и кто то знает?

    Для начинающего (растущего) программиста, менеджера проектов подобную информацию не найти. Она очень ценная. Спасибо.

  24. Rowman Pirce

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

    memcache… бррр что-то лично мне он не нравится.. для кеширования я использую след. схему:

    для “виджетов”: создается статичный контент виджета(на время до обновления), сохраняется к примеру в папке cached.
    да и в прочем так для всего, что можно закешировать.. в том числе и сессии..

    идея сама в использовании tmpfs (типа RAM-DISK. не знаю я как в винде это правильно называется). TMPFS - это файловая система, которая представляет собой часть ОЗУ, примонтированной в определенную точку.. так вот по поводу папки cache, примонтировать в нее tmpfs, и туда уже сохранять в кеш. соответственно эти кешированные данные лежат не на диске, а в ОЗУ.

    так же поступить и с сессиями. надеюсь, не нужно разжевывать.

    по поводу ведения статистики - если не критично, то можно инфу просто сохранять в конец файла. т.е. к примеру одно обращение к серверу - 1 строка в файле. и так заполнять. а в более разгруженное время суток, когда сервер “расслабляется”, уже парсить файл и сохранять в базе инфу.

  25. Для решения второй проблемы я знаю только один способ – хранить данные вместо сессий в куках пользователя. Если кто-то подскажет что-то еще буду очень рад.

    Вы ведь наверняка выделили под memcached отдельный сервер? Вообще, в нём же можно хранить данные сессий (а ещё, например, готовые html - уже сгенерированные по типу ob_start/end)… У меня где-то даже класс завалялся, для работы с сессиями в memcached. Однако - тут встаёт более хитрая проблема. Данные в memcached имеют свойство пропадать (например при потоке 100 новых сессий в секунду + кэш запросов + ещё что-то) старые данные у вас просто вытеснятся, и юзера выкинет. В общем, всё не так то наглядно. Как вариант можно хранить данные с избыточностью, например.

  26. Rowman Pirce

    2Алекс, а зачем хранить html кеш в памяти? довольно не плохой вариант будет просто генерить сразу необходимые страницы.. а если прям неимоверная нагрузка, то держать самые популярные странички в памяти

  27. Rowman Pirce

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

  28. Некропостер

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


© Copyright. . I-Novice. All Rights Reserved. Terms | Site Map