Як масштабувати php5 + MySQL вище 200 запитів в секунду?


16

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

Як не дивно, цифри приблизно однакові на деяких VPS і на спеціальному сервері Atom 330.

Програмне забезпечення сервера таке: Apache2 + mod_php prefork 4 дитини (тут пробували різні номери), php5, APC, nginx, записані для зберігання сеансів PHP.

MySQL налаштований з'їдати близько 30% доступної оперативної пам’яті (~ 150Mb на VPS, 700Mb на виділеному сервері)

Це виглядає так, що десь є вузьке місце, яке не дозволяє мені піднятися вище, якісь пропозиції? (тобто я знаю, що виконання менше 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 показує 354req / sec, з 6 SQL - 180 req / sec. Як ви думаєте, що я можу тут налаштувати? (Я можу розщедрити 100-200Mb для MySQL)

[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/

Чому ви використовуєте і Apache, і nginx?
jamieb

Це загальна конфігурація, Apache2 до PHP та різні додатки, що потребують інфраструктури apache, nginx для зменшення сліду пам’яті apache2 при навантаженні.
BarsMonster

Насправді я не розумію вашої проблеми. Зараз ваш сайт повільний? Якщо так, то наскільки це повільно? І скільки ви хочете пришвидшити? Чи намагалися ви профайлювати якісь частини вашого веб-сайту, щоб визначити, де знаходиться вузьке місце?
jamieb

Це в описі: зараз це на 180-200 запитів / секунду. Хоча цього для домашньої сторінки досить багато, я хочу налаштувати цю настройку, щоб інші сайти, побудовані на тій же кодовій базі, працювали швидше. В ідеалі я хочу наситити 100Мбітне з'єднання динамічними сторінками :-)
BarsMonster

2
"Запити на секунду" насправді не є значимим показником у цьому контексті. Мій нетбук міг обробляти "200 запитів за секунду". Вам потрібно повідомити, який час відгуку ви хочете досягти відповідно до такої швидкості з'єднання.
jamieb

Відповіді:


29

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

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 = 64М (за замовчуванням: 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 = 16М (за замовчуванням: 2М) - допомагає в сортуванні (ЗАМОВЛЕННЯ ПО І ГРУППУ ОК)
  • read_buffer_size = 2М (за замовчуванням: 128 Кб) - допомагає при послідовному скануванні. Збільшити, якщо багато послідовних сканувань.
  • read_rnd_buffer_size = 4М - допомагає таблиці MyISAM прискорити читання після сортування
  • max_length_for_sort_data - розмір рядка для зберігання замість вказівника рядка у файлі сортування. Можна уникнути випадкових читання таблиці
  • key_cache_age_threshold = 3000 (за замовчуванням: 300) - час зберігати кеш-пам'ять клавіш у гарячій зоні (до того, як вона знизиться для нагрівання)
  • key_cache_division_limit = 50 (за замовчуванням: 100) - дозволяє вдосконалити механізм вилучення кешу (два рівні). Позначає відсоток, який слід утримувати для нижнього рівня. delay_key_write = ВСЕ - буфер ключа не обробляється для таблиці під час кожного оновлення індексу, а лише тоді, коли таблиця закрита. Це значно прискорює запис на клавішах, але якщо ви використовуєте цю функцію, вам слід додати автоматичну перевірку всіх таблиць MyISAM, запустивши сервер за допомогою параметра --myisam-recovery = BACKUP, FORCE
  • memlock = 1 - процес блокування в пам'яті (щоб зменшити заміну вводу / виходу)

Апач

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

PHP

  • variables_order = "GPCS" (Якщо вам не потрібні змінні середовища)
  • register_globals = Вимкнено - окрім ризику для безпеки, він також впливає на продуктивність
  • Зберігайте enable_path якомога менше (уникайте додаткових пошукових файлів)
  • display_errors = Вимкнено - відключити показ помилок. Настійно рекомендується для всіх виробничих серверів (не відображає некрасивих повідомлень про помилки у разі проблеми).
  • 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; / шлях" - для великих сайтів розгляньте можливість його використання. Розбиває файли сеансу на підкаталоги

Налаштування ОС

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

Це хороший список, я вже мав їх більшість, і коли я додав інші речі, продуктивність не зросла. Схоже, вузьке місце знаходиться десь між PHP та MySQL, не в змозі обробляти більше 800 запитів в секунду з кешу запитів ...
BarsMonster

Гаразд, як ви підключаєтесь до бази даних (mysql_pconnect () замість mysql_connect ())? Чи використовуєте ви стійкі зв’язки? спробуйте обидва способи ...
Іван Пеєвський

Я вже на pconnect і об’єднання з'єднань увімкнено у php.ini ...: -S
BarsMonster,

Щойно заради повноти, я б спробував просто з'єднатись. Я бачив випадки (особливо в тестуванні навантаження), коли це краще.
Іван Пеєвський

1

Якщо вузьким місцем не є процесор, то його IO - або мережевий, або диск. Отже .. вам потрібно побачити, скільки ІО відбувається. Я б не подумав, що його мережа (якщо ви не перебуваєте на напівдуплексному каналі потужністю 10 Мбіт / с, але варто перевірити комутатор, якщо автоматичне виявлення не виконує свою роботу правильно).

Це залишає диск IO, який може бути важливим фактором, особливо для VPS. Використовуйте sar або iostat, щоб переглянути диски, а потім google, як знайти більше деталей, якщо ваш диск активно використовується.


Так, мережа не є проблемою - при запуску ab з локального сервера продуктивність точно така ж. Я перевірив iowait time - це менше 0,01% - в основному все знаходиться в кеш-диску, і немає записів на диску, які беруть участь у запиті обробки (усі журнали вимкнено).
BarsMonster

1

Я б розглядав кешування з Nginxпам'яткою ) або з лаком .

По крайней мере, ви повинні сервер статичних файлів з Nginx, як сказав SaveTheRbtz.


Це динамічні сторінки, тому я вважаю за краще не кешувати їх.
BarsMonster

1
memcached не є традиційним додатком кешування і може творити чудеса для динамічних сторінок. Він знаходиться між БД і вашим додатком. Ви додасте спочатку запити, які зберігаються для об'єкта, якщо його немає, він завантажується з БД. Чистий ефект полягає в тому, що ви використовуєте оперативну пам’ять для обслуговування запитів БД, а не набагато повільніше стійкого зберігання в БД.
jamieb

Memcache можна використовувати з nginx, що є відомою особливістю. Повільне стійке зберігання не використовується, це все в кеші запитів у MySQL.
BarsMonster

Memcached і кеш запитів MySQL насправді не порівнянні; вони навіть не роблять те саме. Ви досить швидко збиваєте майже кожну пропозицію, розміщену тут, не намагаючись зрозуміти їх. Я рекомендую вам бути трохи більш відкритим.
jamieb

Я чітко розумію різницю між кешованим і кешеним запитами MySQL. Але через те, що все знаходиться в кеші запитів із 100% -ним співвідношенням звернень, я б не назвав це "повільним стійким зберіганням". Оригінальна вчорашня відповідь стосувалася використання NginX + Memcached, що є досить поширеним сценарієм кешування цілих сторінок. Кешування окремих об'єктів - ще один, абсолютно інший сценарій. Хоча використання пам’яті перед MySQL знаходиться на столі, я зараз замислююся про те, щоб отримати більше соку без нього (оскільки це зажадає зовсім небагато змін коду).
BarsMonster

1

Оскільки сервер, здається, не є проблемою, можливо генератор навантаження є. Спробуйте запустити його на декількох машинах.


Продуктивність однакова, навіть якщо я запускаю її з самого сервера. Незалежно від того, як виробляються одночасні підключення - 10 або 50. Тестування навантаження здійснюється через ab -c 10 -t 10
BarsMonster

1

Мені це здається, що ви, можливо, потрапляєте на максимальну кількість з'єднань, які дозволяє Apache. Погляньте на вашу конфігурацію Apache. Збільшення ліміту сервера та максимальних клієнтів повинно допомогти, якщо вас вже не обмежує якийсь інший ліміт, наприклад введення / виведення або пам'ять. Подивіться на значення, присутні для mpm_prefork_module або mpm_worker_module та відповідно відрегулюйте їх відповідно до ваших потреб.

ServerLimit 512
MaxClients 512

Ну, чи справді мені це потрібно, за умови, що я маю nginx перед apache2, тому я вірю, що немає більшого сенсу мати більше, ніж фізичні ядра * 2 Apache2 процеси ....
BarsMonster,

Щойно це підтвердили. Збільшення кількості процесів Apache2 з 4 до 16 зовсім не покращило продуктивність (навіть знизилося на 0,5%). Збільшення кількості nginx працівників до 2 або 4 нічого не покращило.
BarsMonster

1
Якщо ваші дані досить статичні, тобто вони не оновлюються при завантаженні кожної іншої сторінки, ви можете збільшити свій кеш-запит. MySQL буде утримувати набір результатів таким чином і витягувати з пам'яті. Однак, якщо таблиця, яка кешується, отримує будь-які записи протягом цього часу, вона скасовує кеш (навіть якщо дані не впливають), роблячи це марною пам'яттю.
Ерік Гіберті

Зараз я бачу 100%
-не

1
Додайте рішення пропуску імені до вашого конфігураційного файлу MySQL. Це дозволить зберегти пошук DNS при кожному підключенні до сервера. Недолік тут полягає в тому, що всі з'єднання повинні бути заблоковані IP-адресом (якщо ви не використовуєте "%"). Якщо SQL знаходиться на одному сервері і не потребує доступу до нього, крім localhost, ви також можете додати пропускну мережу, щоб знищити весь стек TCP / IP. Однак я думаю, що вузьким місцем є Apache.
Ерік Гіберті

0

Це навантаження генерується інструментом чи реальними навантаженнями?

Можливо, ви захочете перевірити запам’ятовування. Я бачив проблеми з високою швидкістю з'єднання, що спричиняє затримку в додатку.

Якщо ви використовуєте генератор навантажень, що ви отримуєте, потрапляючи на маленьку статичну сторінку?

Під час навантажень ви можете перевірити мережевий стек на TIME_WAIT. Можливо, ви заповнюєте свою чергу зв’язку.

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


Це тестується через ab-c 10 -t 10 URL, який я орієнтую з самого сервера, тому мережа не повинна бути проблемою. Я опублікував більше тестів на ваш запит.
BarsMonster

Я б не витрачав занадто багато зусиль, налаштовуючи з ab. Ви можете виявити, що це не добре перетворюється на реальну роботу. Можливо, ви хочете зробити розсічення програми та протестувати кожен компонент. Наприклад, натисніть на сервер apache безпосередньо за допомогою дуже маленької статичної сторінки. Це дасть вам уявлення про вашу максимальну кількість запитів на секунду. Помістіть nginx попереду, повторно протестуйте виклик того самого файлу бекенда. Потім тестуйте за допомогою простої php-сторінки "привіт світ" Іноді всі шари можуть замаскувати щось просте. Також слідкуйте за підключеннями під час тесту. Переконайтеся, що ваш мережевий стек не заповнюється.
jeffatrackaid

Я зробив ці орієнтовні показники вчора, і вони містяться в оновленому описі початкового запитання. Також тести робляться на localhost, тому мережа не є проблемою.
BarsMonster

Мережа може бути проблемою, навіть якщо це зроблено на локальному хості. У вашому випадку це мало ймовірно, але це може спричинити проблеми. Поки що у вас є верхня межа ~ 450 req / сек при вашому поточному налаштуванні PHP. Наступний крок - залишити виклик бази даних і подивитися, як це змінюється. Мені подобається розбивати це, коли ви робите налаштування на високому рівні, оскільки це дійсно може допомогти вам точно визначити шар, що викликає більшість проблем.
jeffatrackaid

-1

99% відсотків таких питань, як цей, буде відслідковуватися до бази даних. Переконайтесь, що ваші індекси вражаючих насамперед. Якщо це не працює, починайте кешувати все, що можете.


Це все індекси, і, як я вже говорив, він навіть потрапляє в кеш запитів MySQL у 100% випадків
BarsMonster

-1

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

Також спробуйте проаналізувати всі ваші запити за допомогою EXPLAIN (а чому б не профілювати ваші запити за допомогою SHOW PROFILE?).


Усі запити використовують індекси. Використовується пул підключення MySQL.
BarsMonster
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.