Назад | Перейти на главную страницу

Как масштабировать php5 + MySQL выше 200 запросов в секунду?

Я настраиваю свою домашнюю страницу для повышения производительности, в настоящее время она обрабатывает около 200 запросов в секунду на 3.14.by, который потребляет 6 SQL-запросов, и 20 запросов в секунду на 3.14.by/forum, который является форумом phpBB.

Как ни странно, на некоторых VPS и выделенном сервере Atom 330 цифры примерно одинаковые.

Серверное программное обеспечение следующее: Apache2 + mod_php prefork 4 childs (пробовал разные числа здесь), php5, APC, nginx, memcached для хранения сессий PHP.

MySQL настроен на использование около 30% доступной оперативной памяти (~ 150 МБ на VPS, 700 МБ на выделенном сервере)

Похоже, где-то есть узкое место, не позволяющее мне подниматься выше, есть предложения? (т.е. я знаю, что выполнение менее 6 SQL-запросов сделает его быстрее, но это не похоже на ограничивающий фактор, поскольку sqld потребляет не более нескольких% сверху из-за кешированных запросов)

Кто-нибудь тестировал, что запускать предварительно сформированный apache2 и оставлять только nginx + php намного быстрее?

Еще несколько тестов

Small 40-byte static file: 1484 r/s via nginx+apache2, 2452 if we talk to apache2 directly. 
Small "Hello world" php script: 458 r/s via ngin+apache2.

Обновить: Похоже, узким местом является производительность MySQL на кэшированных данных. Страница с одним SQL показывает 354 запросов / сек, с 6 SQL - 180 запросов / сек. Как вы думаете, что я могу здесь настроить? (Могу раскошелиться на MySQL 100-200Мб)

[client]
port        = 3306
socket      = /var/run/mysqld/mysqld.sock

[mysqld_safe]
socket      = /var/run/mysqld/mysqld.sock
nice        = 0

[mysqld]
default-character-set=cp1251
collation-server=cp1251_general_cs

skip-character-set-client-handshake

user        = mysql
pid-file    = /var/run/mysqld/mysqld.pid
socket      = /var/run/mysqld/mysqld.sock
port        = 3306
basedir     = /usr
datadir     = /var/lib/mysql
tmpdir      = /tmp
skip-external-locking

bind-address        = 127.0.0.1

key_buffer      = 16M
max_allowed_packet  = 8M
thread_stack        = 64K
thread_cache_size   = 16
sort_buffer_size    = 8M
read_buffer_size    = 1M

myisam-recover      = BACKUP
max_connections        = 650
table_cache            = 256
thread_concurrency     = 10

query_cache_limit       = 1M
query_cache_size        = 16M

expire_logs_days    = 10
max_binlog_size         = 100M

[mysqldump]
quick
quote-names
max_allowed_packet  = 8M

[mysql]
[isamchk]
key_buffer      = 8M

!includedir /etc/mysql/conf.d/

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

MySQL

  • query_cache_type = 1 - кеширование SQL запросов включено. Если установлено значение 2, запросы кэшируются только в том случае, если им передается подсказка SQL_CACHE. Аналогично с типом 1 вы можете отключить кеш для определенного запроса с подсказкой SQL_NO_CACHE
  • key_buffer_size = 128M (по умолчанию: 8M) - буфер памяти для индексов MyISAM таблицы. На выделенных серверах старайтесь установить key_buffer_size как минимум на четверть, но не более половины от общего объема памяти на сервере.
  • query_cache_size = 64M (по умолчанию: 0) - размер кеша запросов
  • back_log = 100 (по умолчанию: 50, максимум: 65535) - очередь невыполненных запросов на подключение. Имеет значение только при большом количестве подключений за короткое время
  • join_buffer_size = 1M (по умолчанию: 131072) - буфер, который используется при полном сканировании таблицы (без индексов)
  • table_cache = 2048 (по умолчанию: 256) - должно быть max_user_connections, умноженное на максимальное количество JOIN, которое содержит ваш самый тяжелый SQL-запрос. Используйте в качестве ориентира переменную open_tables в часы пик. Также посмотрите на переменную "open_tables" - она ​​должна быть близка к "open_tables"
  • query_prealloc_size = 32K (по умолчанию: 8K) - постоянная память для синтаксического анализа и выполнения операторов. Увеличьте при наличии сложных запросов
  • sort_buffer_size = 16M (по умолчанию: 2M) - помогает с сортировкой (операции ORDER BY и GROUP BY)
  • read_buffer_size = 2M (по умолчанию: 128K) - помогает при последовательном сканировании. Увеличьте, если выполняется много последовательных сканирований.
  • read_rnd_buffer_size = 4M - помогает таблице MyISAM ускорить чтение после сортировки
  • max_length_for_sort_data - размер строки для хранения вместо указателя строки в файле сортировки. Можно избежать случайного чтения таблицы
  • key_cache_age_threshold = 3000 (по умолчанию: 300) - время держать ключевой кеш в горячей зоне (до того, как он понижен до теплого)
  • key_cache_division_limit = 50 (по умолчанию: 100) - включает более сложный механизм вытеснения кеша (два уровня). Обозначает процент, сохраняемый для нижнего уровня. delay_key_write = ALL - буфер ключей для таблицы не сбрасывается при каждом обновлении индекса, а только когда таблица закрывается. Это значительно ускоряет запись ключей, но если вы используете эту функцию, вам следует добавить автоматическую проверку всех таблиц MyISAM, запустив сервер с параметром --myisam-recovery = BACKUP, FORCE.
  • memlock = 1 - заблокировать процесс в памяти (для уменьшения свопинга / выгрузки)

Apache

  • изменить метод нереста (например, на mpm)
  • отключите журналы, если возможно
  • AllowOverride None - по возможности отключать .htaccess. Он останавливает apache для поиска файлов .htaccess, если они не используются, поэтому он сохраняет запрос поиска файла.
  • SendBufferSize - установить по умолчанию ОС. В перегруженных сетях вам следует установить этот параметр, близкий к размеру самого большого файла, обычно загружаемого
  • KeepAlive Off (по умолчанию On) - и установка lingerd для правильного закрытия сетевых подключений и быстрее
  • DirectoryIndex index.php - Сделайте список файлов максимально коротким и абсолютным.
  • Опции FollowSymLinks - для упрощения процесса доступа к файлам в Apache
  • Избегайте использования mod_rewrite или хотя бы сложных регулярных выражений
  • ServerToken = prod

PHP

  • variables_order = "GPCS" (Если вам не нужны переменные среды)
  • register_globals = Off - помимо угрозы безопасности, это также влияет на производительность
  • Сохраняйте include_path как можно меньше (избегайте лишних поисков в файловой системе)
  • display_errors = Off - отключить отображение ошибок. Настоятельно рекомендуется для всех производственных серверов (в случае возникновения проблем не отображает некрасивые сообщения об ошибках).
  • magic_quotes_gpc = Выкл.
  • magic_quotes _ * = Выкл.
  • output_buffering = Вкл.
  • По возможности отключите ведение журнала
  • expose_php = Выкл.
  • register_argc_argv = Выкл.
  • always_populate_raw_post_data = Выкл.
  • поместите файл php.ini туда, где php будет его искать в первую очередь.
  • session.gc_divisor = 1000 или 10000
  • session.save_path = "N; / path" - рассмотрите возможность его использования для больших сайтов. Разделяет файлы сеанса на подкаталоги

Настройки ОС

  • Подключите использованные жесткие диски с параметром -o noatime (без времени доступа). Также добавьте эту опцию в файл / etc / fstab.
  • Настройте / proc / sys / vm / swappiness (от 0 до 100), чтобы увидеть, что дает лучшие результаты
  • Используйте RAM-диски - mount --bind -ttmpfs / tmp / tmp

Поскольку сервер не кажется проблемой, возможно, генератор нагрузки. Попробуйте запустить его на нескольких машинах.

Я бы посмотрел на кеширование с помощью Nginx (memcached) или Лак.

По крайней мере, вы должны серверить статические файлы с помощью Nginx, как сказал SaveTheRbtz.

Если узким местом является не ЦП, то его ввод-вывод - либо сетевой, либо дисковый. Итак .. вам нужно увидеть, сколько операций ввода-вывода происходит. Я бы не подумал, что это сеть (если вы не используете полудуплексный канал со скоростью 10 Мбит / с, но стоит проверить переключатель, если автоматическое обнаружение не выполняет свою работу правильно).

Остается дисковый ввод-вывод, который может быть большим фактором, особенно на VPS. Используйте sar или iostat, чтобы посмотреть на диски, затем погуглите, как найти более подробную информацию, если ваш диск интенсивно используется.

Мне кажется, вы используете максимальное количество подключений, которое позволяет Apache. Взгляните на свою конфигурацию Apache. Увеличение лимита сервера и максимального количества клиентов должно помочь, если вы еще не связаны каким-либо другим лимитом, таким как ввод-вывод или память. Посмотрите на значения, представленные для mpm_prefork_module или mpm_worker_module, и отрегулируйте соответственно своим потребностям.

ServerLimit 512
MaxClients 512

Эта нагрузка создается инструментом или реальными нагрузками?

Вы можете проверить memcached. Я видел проблемы с высокой скоростью соединения, вызывающие задержку в приложении.

Если вы используете генератор нагрузки, что вы получите при открытии небольшой статической страницы?

Во время загрузки вы можете проверить сетевой стек на наличие условий TIME_WAIT. Возможно, вы заполняете очередь на подключение.

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

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

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

Кроме того, попробуйте проанализировать все свои запросы с помощью EXPLAIN (а почему бы не профилировать свои запросы с помощью SHOW PROFILE?).