В предыдущей статье, мы познакомились с настройкой связки nginx + apache в режиме хостинга и репозиториями dotdeb.
В этой статье мы познакомимся с настройкой backend: PHP, MySQL.
В части PHP мы познакомимся со следующими темами:
— общая настройка PHP
— правильная настройка PHP + Postfix для отправки писем через внутренний SMTP сервер посредством функции mail(),
— настройка кеширования кода и/или данных на основе APC.
В части MySQL я попробую раскрыть базовые моменты повышения производительности, ибо по умолчанию сервер MySQL настроен очень не эффективно.
Кто заинтересовался, добро пожаловать под кат
Информация:
Сам не являюсь профи по настройке баз данных. На то есть реально крутые перцы, и они люто мучают БД в разных конфигурациях на тестовых стендах и на реальных БД для получения максимальной производительности под конкретные задачи. В этой статье все проще. Основную конфигурацию я прикинул на глаз + поправил все проблемы которые увидел в SHOW VARIABLES. По ощущениям, после нормальной настройки основной ресурс стал работать быстрее чем раньше.
Снова приведем из прошлой статьи схему архитектуры настраиваемой системы, для наглядного представления ресурсов сервера (Картинко кликабельно)
Настройка PHP 5.3.18
В начале как всегда. Прошу мои конфиги php+apc: yadi.sk/d/0OuPvlBS0t01O
— Общая настройка PHP
В целом в файле php.ini я ничего интересного не нашел. Однако есть на что обратить внимание:
Очень важно, если берешь пакеты из dotdeb:
- date.timezone = Europe/Moscow — надо установить временной пояс, иначе функция date генерирует кучу предупреждений. Не знаю почему, но данная проблема появилась либо после обновления PHP на новую версию, либо из-за репозиториев dotdeb, которые компилированы немного иначе чем дебинские. В данном случае установлен временной пояс Москвы.
- ОЧЕНЬ ВАЖНО: session.save_path = «/var/lib/php5» — это обязательно надо установить так! По стандарту debian именно там должны находиться сессии. Не знаю почему, но в сборке debian эта переменная не выставляется. Видно она уже собрана по умолчанию. Dotdeb по умолчанию пишет сессии в директорию /tmp, что совершенно не верно. Прошу обратить внимание на конфигурацию разделов на сервере: 25G /, 20G swap, 100G /var, ~800G /home. Данная конфигурация разделов была рассчитана под debian. В результате этой неизвестности у меня произошла совершенно неожиданная авария на продакшин сервере! в результате чего могли пострадать клиенты. Авария произошла из-за того, что неожиданно забился раздел /. Проблема была найдена и оперативно исправлена. В директории /tmp почему-то не работал сборщик мусорных сессий, вероятно из-за прав доступа (это происходит из-за debian way сборки устаревших сессий).
Производительность и ресурсы:
- max_execution_time = 30 — время исполнения скриптов, оставлено по умолчанию. С одной стороны, скрипты не должны быть бесконечно исполняемые, поэтому ограничение должно быть. С другой стороны, можно предположить, что обычно бесконечных циклов не бывает, поэтому ограничение не нужно особо зажимать. Для тех у кого используются потенциальные бесконечные циклы рекомендуется закручивать данную настройку посильнее
- memory_limit = 128M — это то, какое максимальное количество памяти может потребить скрипт. PHP не будет выделать больше памяти, чем указано в этой настройке. Данная настройка указывается в зависимости от задач исполняемых на сервере. Для более точного расчета ресурсов следует закручивать этот параметр как можно сильнее и пытаться писать софт как можно качественнее.
- post_max_size = 70M — этот параметр должен быть меньше, чем общее количество выделенной памяти в memory_limit. Как мы уже указали в схеме, на уровне фронтенда nginx не пропустит тело запроса более чем 64M. Этот параметр взят с перехлестом, ибо читаем дальше.
- upload_max_filesize = 64M — максимальный размер файла который может быть загружен выверен под настройку nginx, поэтому бессмысленно его ставить выше. Лучше сделать перехлест, что бы не получить вот такую проблему с пустым POST
- При настройке PHP хочу, что бы вы обратили внимание на последовательность перехлестов: memory_limit — post_max_size — upload_max_filesize. Одно должно быть больше другого в указанной последовательности, тогда все будет работать стабильно.
- max_file_uploads = 20 — количество файлов, которые можно передать за один запрос. Этот параметр должен для себя решать каждый сам. Например, было подсчитано, что средняя фотография будет весить не более чем 3M, получается где-то 20 фотографий за раз. На сервере можно делать массовую загрузку фотографий/документов. Не знаю как на практике должно быть реализовано, а в теории работать должно.
Скрытие присутствия PHP
- session.name = SESSID изменил с PHPSESSID на SESSID, для пущей скрытности.
- expose_php = Off — отключает заголовки, которые показывают, что на сервере работает PHP, не светим тем, что у тебя стоит.
- user_agent=«EXAMPLE-SERVER» — это интересная штука. Если вы например делаете паука на PHP, то это будет тот заголовок user-agent который будет отправляться удаленному серверу при запросе каких-либо данных.
- остальное оставлено без изменений
Пару слов касательно вывода ошибок (+ Скрытие присутствия PHP 2):
- error_reporting = E_ERROR (E_ERROR | E_WARNING поправка от truezemez см. комментарии) — дабы, продакшен особо не грузить записью разных проблем, отключил данный параметр. Оставил, только самое критическое. С другой стороны, если вы имеете качественный софт, то стоит выставить максимальный вывод ошибок/проблем E_ALL | E_STRICT, что бы в реальных условиях находить проблемы
- display_errors = Off — очень частая ошибка вебмастеров, пожалуйста отключайте вывод ошибок на экран, пользователям очень неприятно на это смотреть, а взломщикам это просто объедение!
- log_errors = On — естественно, если логи мы не выводим, их надо писать!
- остальное оставлено без изменений
— Настройка кешироваия APC (версия 3.1.9):
APC кеширует опкоды, кроме того он умеет кешировать данные. Я использую APC по причине того что фреймворк Yii рекомендует его. В Yii есть уже написанные классы, для работы с данным кешером. Другие кешеры не рассматривал и не сравнивал по указанным выше причинам.
Конфиг файла по умолчанию пустой, все значения выставлены по умолчанию. В частности под кеширование выделено 32M — на код хватит, на данные нет.
В указанном мной конфиге файла, стоит обязательно обратить внимание на следующие:
- apc.shm_size = 512M — в debian/dotdeb APC скомпилирован с MMAP Support. Соответственно параметр apc.shm_segments не учитывается и следует пользоваться только этой настройкой
- apc.file_update_protection = 3 — чем выше этот параметр, тем меньше раз APC проверяет изменился ли файл с кодом. Указывается в секундах. Если вы редко обновляете код на сервере, то этот параметр можно поставить 60
- Есть и другие настройки, которые были оставлены по умолчанию
— Настройка фукции mail():
Из коробки функция mail() работать не должна. Что бы она работала нужен правильно работающий почтовый SMTP сервер. В предыдущей статье мы установили такой сервер.
Стоит в настройке обратить внимание на следующие вещи:
- sendmail_path = /usr/sbin/sendmail -t -i [email protected] — с помощью этой команды мы правильно настраиваем отправляемые заголовки. Правильные заголовки нужны для того, что бы не попасть в спам. По поводу правильных заголовков прошу прочесть мою статью: Грамотная настройка сервера отправки почты для скриптов PHP, настройка функции mail() (статья конечно жуткая каша, но все-таки объясняет что к чему, со временем я попробую написать мануал в духе данного цикла статей)
- mail.add_x_header = Off — как всегда, не светим тем, чем не надо
Настройка MySQL 5.5.28
Пока читал документацию наткнулся на причуды настройки на уровне фантастики. Люди специально заводят тесты, что бы выжимать из БД максимум производительности до 30 процентов на определенных настройках и на определенном железе.
У нас этого не будет. Мы просто будем следовать здравому смыслу и документации.
Добро пожаловать конфигам: yadi.sk/d/T1ov6qAF0t82y
Структура конфигурационных файлов:
- /my.cnf — собственно главный конфигурационный файл, в котором записаны основные настройки директорий и делающий загрузку других конфигурационных файлов
- /conf.d/.keepme — незамысловатое название как бы говорящее, что удалять его не стоит. Было оставлено по-дефолту.
- /conf.d/mysqld_base_perfomance.cnf — настройка общей производительности БД. Данные настройки не связаны с каким-либо используемым типом хранилища.
- /conf.d/mysqld_common.cnf — некие общие настройки, которые не удалось сгруппировать.
- /conf.d/mysqld_innodb.cnf — настройки хранилища InnoDB
- /conf.d/mysqld_log.cnf — настройки логов
- /conf.d/mysqld_myisam.cnf — настройки хранилища MyISAM
- /conf.d/mysqld_query_cache.cnf — настройка кеширования запросов
- /conf.d/mysqld_thread.cnf — настройка потоков
В файле my.cnf прошу обратить внимание на следующие настройки
- max_connections = 300 — увеличил количество соединений, равные 150*2 из расчета, что каждый PHP процесс может создать по 2 независимых соединения.
- max_allowed_packet = 2M — увеличил размер передаваемого пакета
- datadir = /home/mysql — при настройке сделана отдельная директория в /home для mysql с защитой от доступа другим пользователям, кроме mysql. Это сделано, что бы перенести данные из /var/lib/mysql (если я не ошибаюсь) в раздел /home — самый большой раздел диска на сервере, где и хранятся все данные.
— SHOW VARIABLES
Для просмотра того, какие операции выполняет БД был создан SHOW VARIABLES. С помощью него вы сможете узнать о таких вещах как количество операций ввода вывода, количство попаданий в кеш, количество сортировок через файлы и другое. Советую для ознакомления.
В конфигах рядом с каждой настройкой, влияющая на производительность указана ссылка (see) на какой параметр SHOW VARIABLES нужно смотреть. Ко всем остальным подробностям прошу обращаться к документации.
Некоторые настройки, на которые следует обратить внимание:
- /conf.d/mysqld_thread.cnf thread_cache_size/thread_concurrency — выставил по количеству ядер.
- mysqld_base_perfomance.cnf tmp_table_size = 8M — если вы имеете много сортировок через временные файлы, то нужно увеличить данный параметр. Не забывайте о том, что надо помнить возможности сервера. В нашем случае 300 соединений по 8M = 2.4G в пике мы будем тратить на сортировку во временной таблице.
- mysqld_query_cache.cnf query_cache_size = 256M — не злоупотребляйте размером кешом запросов, в этом случае больше не лучше, в отличии от некоторых других настроек БД. 256M это достаточно — в 8 раз больше значения по умолчанию. Подробности в документации
- mysqld_myisam.cnf concurrent_insert = ALWAYS — был приятно удивлен, когда узнал, что в MyISAM есть конкурентная вставка, пересмотрел свое отношение к этой таблице.
- mysqld_myisam.cnf key_buffer_size = 256M — если вы используете много таблиц MyISAM, то этот параметр должен быть больше, в противном случае лучше его увеличить до 256, что бы на душе было спокойно.
- Важно: mysqld_innodb.cnf innodb_buffer_pool_size = 5G — самый главный параметр, по умолчанию таблицы InnoDB вообще не настроены, для работы на хоть сколь маленьких серверах. Если не настроить данный параметр, то мы получим лютую нагрузку на дисковую подсистему. В идеале данный параметр рекомендуется держать чуть чуть большим чем суммарный размер всех БД.
- mysqld_innodb.cnf innodb_log_buffer_size = 32M — тоже самое, только для логов таблиц InnoDB. (это журналы транзакций, а не обычные логи настраиваемые в файле mysqld_log.cnf)
- Очень интересно почитать: mysqld_innodb.cnf innodb_buffer_pool_instances = 1 — там целые бои за данный параметр на грани фантастики. Вот ссылка, по которой можно найти информацию хорошо связанную между собой dimitrik.free.fr/blog/archives/2012/10/mysql-performance-innodb-buffer-pool-instances-in-56.html. До конца не понял о чем там пишут, дезинформировать не буду. Почитал, посмотрел графики, не стал рисковать и оставил 1.
Все остальные параметры вы сможете найти в конфигурационных файлах.
ЗЫ: Ух блин вылил. Надеюсь не слишком коряво? Если хотя бы 70% получилось донести, то это хорошо.
Если данная статья будет по вкусу, то собираюсь написать про настройку mail() + postfix + dkim в духе цикла статей. Потом написать про настройку прав доступа на сервере. Потом написать про разный опыт владения в своем распоряжении сервера, там же попробуем еще раз привести схему сервера и расписать основные узлы и потребления памяти и думаю туда же запихну скрипт для развертывания и управлением сервера (на уровне добавить и удалить пользователя) и соответственно разъясню все нюансы связанное например со стандартами именований принятые у меня. В конце всего цикла статей, я бы хотел познакомить с моим домашним сервером, который к слову можно совершенно просто масштабировать добавляя в «стойку» новые виртуальные машины и ноутбуки + еще виртуальные машины =). Все настройки вначале тестируются на этом маленьком сервере, перед тем как попадают на рабочие сервера.