У меня есть распределенное приложение, отправляющее информацию на серверы API, которые являются подчиненными серверами MySQL 8. Приложения выполняют полную начальную синхронизацию (~ 100 000 записей партиями по 500), за которой следует инкрементная синхронизация каждые 5 минут.
У меня есть 3 сервера Dell R620 с 512 ГБ оперативной памяти, 5 SSD в RAID 6, которые действуют как веб-серверы. Один я посвятил тому, чтобы стать мастером MySQL, используя следующую конфигурацию:
[mysqld]
server-id=1
# GENERAL #
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql/
bind-address=*
# GENERAL #
user = mysql
default-storage-engine = InnoDB
# MyISAM #
key-buffer-size = 32M
myisam-recover-options = FORCE,BACKUP
# SAFETY #
max-allowed-packet = 16M
max-connect-errors = 1000000
skip-name-resolve
#skip-grant-tables
# BINARY LOGGING #
log-bin = /var/lib/mysql/mysql-bin
binlog_expire_logs_seconds = 2000
sync-binlog = 1
# CACHES AND LIMITS #
tmp-table-size = 32M
max-heap-table-size = 32M
max-connections = 500
thread-cache-size = 50
open-files-limit = 10000
table-definition-cache = 4096
table-open-cache = 4096
#
## INNODB #
innodb-flush-method = O_DIRECT
innodb-log-files-in-group = 2
innodb-log-file-size = 512M
innodb-flush-log-at-trx-commit = 1
innodb-file-per-table = 1
innodb-buffer-pool-size = 360G
#
## LOGGING #
log-error = /var/lib/mysql/mysql-error.log
log-queries-not-using-indexes = 1
slow-query-log = 1
slow-query-log-file = /var/lib/mysql/mysql-slow.log
#
## REPLICATION ##
slave-parallel-workers=10
slave-parallel-type = LOGICAL_CLOCK
innodb-flush-log-at-timeout=1800
[mysql]
# CLIENT #
port = 3306
На других серверах, на которых размещен API, цель состоит в том, чтобы они выполняли запросы выбора на локальном подчиненном сервере и записывали изменения обратно на главный сервер, что позволит нам выделить дополнительные ресурсы для приема входящих вызовов API. Поскольку они предназначены в первую очередь для Apache / PHP, я уменьшил innodb-buffer-pool-size = 64G
.
Какие оптимизации я должен использовать для Apache и PHP для серверов с высокой оперативной памятью?
Я настроил это, но не уверен, что недостаточно использую доступные ресурсы:
<IfModule mpm_prefork_module>
StartServers 200
MinSpareServers 20
MaxSpareServers 50
MaxRequestWorkers 100
MaxConnectionsPerChild 0
ServerLimit 512
MaxClients 512
MaxRequestsPerChild 10000
</IfModule>
Более полный обзор моих настроек, включая переменные, статус, отчет mysqltuner.pl, можно найти здесь: http://plnkr.co/edit/eeGHzFX95j5auJ5lTYum?p=catalogue
Сейчас мы получаем около 5600 запросов в час, около 70% может иметь до 500 записей на запрос, требующий обновления или вставки запроса. Это составляет около 550 запросов в секунду. Загрузка сервера обычно составляет 2,5-4.
Веб-сайт был написан на Laravel 5.4, и мы протестировали пропускную способность для обычных маршрутов API, используя Laravel, Eloquent и т. Д., А также при использовании Apache Benchmark, используя следующее: ab -c 100 -n 2000 -p sample.json -T application/json -H "Content-Type: application/json" -H "Authorization: Bearer eyJ0eXAiO" https://www.myserver.com/api/accounting
Вот результаты:
Benchmarking www.myserver.com (be patient)
Completed 200 requests
Completed 400 requests
Completed 600 requests
Completed 800 requests
Completed 1000 requests
Completed 1200 requests
Completed 1400 requests
Completed 1600 requests
Completed 1800 requests
Completed 2000 requests
Finished 2000 requests
Server Software: Apache/2.4.29
Server Hostname: www.myserver.com
Server Port: 443
SSL/TLS Protocol: TLSv1.2,ECDHE-RSA-CHACHA20-POLY1305,2048,256
TLS Server Name: www.myserver.com
Document Path: /api/accounting
Document Length: 65 bytes
Concurrency Level: 100
Time taken for tests: 375.487 seconds
Complete requests: 2000
Failed requests: 1134
(Connect: 0, Receive: 0, Length: 1134, Exceptions: 0)
Total transferred: 735018 bytes
Total body sent: 162864000
HTML transferred: 131018 bytes
Requests per second: 5.33 [#/sec] (mean)
Time per request: 18774.370 [ms] (mean)
Time per request: 187.744 [ms] (mean, across all concurrent requests)
Transfer rate: 1.91 [Kbytes/sec] received
423.57 kb/s sent
425.49 kb/s total
Connection Times (ms)
min mean[+/-sd] median max
Connect: 3 315 1554.1 5 11497
Processing: 8420 18299 2501.9 18658 24051
Waiting: 8419 18298 2501.9 18658 24050
Total: 8424 18614 2791.2 18792 30388
Percentage of the requests served within a certain time (ms)
50% 18792
66% 19699
75% 20247
80% 20619
90% 21560
95% 22343
98% 23933
99% 27099
100% 30388 (longest request)
sample.json содержал 500 записей, и у нас была нагрузка на сервер до 103. Вы также заметите, что более половины наших сообщений терпят неудачу.
Кажется, что apache - наше узкое место, и когда я начал разбираться в нем, используя get_included_files()
Я обнаружил, что Laravel использует 275 включений только для того, чтобы добраться до файла routes.php, к тому времени, когда он начинает публикацию в нашем API, он использует 462, а к концу публикации в API он использует 575 включенных файлов.
Мы перестроили ту же функцию вне Laravel, используя единственную страницу PHP, которая определяла соединение PDO, перебирая запросы данных таким же образом, генерируя запросы для вставки и обновления, и выполняла ту же задачу с этой статистикой:
Concurrency Level: 100
Time taken for tests: 16.367 seconds
Complete requests: 2000
Failed requests: 228
(Connect: 0, Receive: 0, Length: 228, Exceptions: 0)
Total transferred: 502228 bytes
Total body sent: 162804000
HTML transferred: 126228 bytes
Requests per second: 122.19 [#/sec] (mean)
Time per request: 818.366 [ms] (mean)
Time per request: 8.184 [ms] (mean, across all concurrent requests)
Transfer rate: 29.97 [Kbytes/sec] received
9713.76 kb/s sent
9743.73 kb/s total
Connection Times (ms)
min mean[+/-sd] median max
Connect: 3 9 14.7 6 98
Processing: 242 800 281.3 764 2187
Waiting: 241 799 281.3 764 2187
Total: 246 809 283.8 774 2195
Percentage of the requests served within a certain time (ms)
50% 774
66% 905
75% 986
80% 1040
90% 1201
95% 1328
98% 1493
99% 1618
100% 2195 (longest request)
Нагрузка на сервер достигла только 12 при публикации этих сообщений с 0 неудачными сообщениями. Из-за значительного улучшения мы планируем извлечь код API из Laraverl и оптимизировать один сервер для Mysql, а затем иметь несколько подчиненных устройств. Каждое ведомое устройство будет иметь доступ только для чтения к localhost, чтобы API мог запросить, чтобы определить, должна ли каждая запись быть оператором обновления или вставки, а затем будет выполнять запросы на ведущем устройстве MySQL.
Хотя я искал ответы, так много ресурсов было написано, когда 4–32 ГБ ОЗУ было нормальным, а когда вы находите один с 512 ГБ, это обычно относится к SSD.
Грохочущее стадо. Не имейте такого большого количества детей Apache. Установите его не выше, чем, скажем, количество ядер (потоков) в вашем процессоре (ах). Имейте в виду, что MySQL также конкурирует за эти ядра.
У вас конфликтующие ценности для innodb_buffer_pool_size
. Установите его, возможно, вдвое больше, чем у вас есть, но не настолько большим, чтобы вызвать подкачку. И установить innodb_buffer_pool_instances = 16
.
"500" запросов в не замужем INSERT
или UPDATE
или ИОДКУ? Если нет, давайте посмотрим, что вы делаете, и постараемся сделать это одной командой SQL. Это может ускорить работу MySQL в 10 раз.
С этим связан вопрос, кто решает между «вставкой» и «обновлением»?
Какое значение имеет «JSON»? Есть ли большая строка JSON, которая разбивается на 500 вставок? Или строка JSON - это «мясо» вставки?
Чтобы лучше понять действие: сколько запросов в секунду вы выполняете? Сколько строк вставляется (или обновляется) в секунду?
Предложение для вашего ulimit -a результатов,
ulimit -n 24000 to enable more than current limit of 1024 Open Files
Вышесказанное является динамическим для ОС Linux. Сервисы Stop / Start будут иметь доступ к ручкам. Чтобы сделать это постоянным при выключении / перезапуске ОС, просмотрите этот URL-адрес для получения аналогичных инструкций для ОС. Эти инструкции устанавливают 500000 для file-max, пожалуйста, пока установите емкость на 24000. ulimit установите значение 24000, что позволит MySQL использовать 10000 запрошенных и иметь запасные части для других приложений.
https://glassonionblog.wordpress.com/2013/01/27/increase-ulimit-and-file-descriptors-limit/
Рекомендации для вашего раздела my.cnf [mysqld] (RPS = Скорость в секунду)
innodb_buffer_pool_size=36G # from 240G because your innodb data+ndx ~ 22G
innodb_lru_scan_depth=100 # from 1024 to conserve 90% cpu cycles used for this function
max_connections=600 # from 500 - you are denying many connections today
innodb_io_capacity=1900 # from 200 to enable higher IOPS
read_rnd_buffer_size=192K # from 256K to reduce handler_read_rnd_next RPS
Отказ от ответственности: я являюсь автором содержания веб-сайта, указанного в моем профиле, сетевом профиле.