Разработка для Windows (Dev. Studio 2005, SQL Server 2003);
Apache получает ...
Для начала несколько деталей для описания ситуации в целом:
- База данных MySQL (5.1.50) на очень мощной (32 ядра ЦП, 64 ГБ ОЗУ) машине FreeBSD 8.1-RELEASE который также запускает Apache 2.2.
- Apache получает в среднем около 50 обращений в секунду. Подавляющее большинство этих обращений - это вызовы API для торговой платформы.
- Вызовы API обычно занимают около половины секунды или меньше для генерации результата, но могут занять до 30 секунд в зависимости от третьих сторон.
- Каждый вызов API сохраняет строку в базе данных. Информация, хранящаяся там, важна, но только примерно на пятнадцать минут, после чего она должна истечь.
- В таблице, в которой хранится информация о вызовах API (схема для этой таблицы приведена ниже), InnoDB используется блокировка на уровне строк. для синхронизации между потоками (соединения Apache, действительно), запрашивая одну и ту же информацию в одно и то же время, что случается часто. Это означает, что несколько потоков могут ожидать блокировки строки до 30 секунд , поскольку вызовы API могут занимать столько времени (но обычно этого не происходит).
- Прежде всего, самое важное, что следует отметить, - это то, что все работает отлично при нормальных обстоятельствах.
Тем не менее, это очень часто используемая таблица (около пятидесяти INSERT в секунду, много SELECT, блокировка на уровне строк используется) Я выполняю запрос DELETE для:
CREATE TABLE `sales` (
`sale_id` int(32) unsigned NOT NULL auto_increment,
`start_time` int(20) unsigned NOT NULL,
`end_time` int(20) unsigned default NULL,
`identifier` char(9) NOT NULL,
`zip_code` char(5) NOT NULL,
`income` mediumint(6) unsigned NOT NULL,
PRIMARY KEY USING BTREE (`sale_id`),
UNIQUE KEY `SALE_DATA` (`ssn`,`zip_code`,`income`),
KEY `SALE_START` USING BTREE (`start_time`)
) ENGINE=InnoDB DEFAULT CHARSET=ascii ROW_FORMAT=FIXED
Запрос DELETE
выглядит следующим образом и запускается каждые пять минут в cron (я бы предпочел запускать его раз в минуту):
DELETE FROM `sales` WHERE
`start_time` < UNIX_TIMESTAMP(NOW() - INTERVAL 30 MINUTE);
Я использовал INT
для поля времени, потому что очевидно, что MySQL имеет проблемы с использованием индексов с полями DATETIME
.
Итак, проблема заключается в следующем: запрос DELETE
большую часть времени работает нормально (возможно, в 7 случаях из 10). В других случаях запрос завершается быстро, но кажется, что после этого MySQL на некоторое время забивается. Я не могу точно доказать, что это MySQL работает, но время, когда возникают симптомы, определенно совпадает со временем выполнения этого запроса. Вот симптомы, пока все забито:
- Вход в MySQL и использование
SHOW FULL PROCESSLIST;
, всего несколько INSERT INTO
продаж ...
выполняются запросы, которых обычно больше сотни. Что здесь ненормально, так это отсутствие каких-либо задач в списке процессов, а не их слишком много. Кажется, MySQL полностью перестает принимать соединения.
- Проверяя состояние сервера Apache, Apache достиг MaxClients. Все потоки находятся в состоянии «Отправка ответа».
- Apache начинает использовать много системного времени центрального процессора. Средняя нагрузка резко возрастает, я видел средние нагрузки за 1 минуту, достигающие 100. Нормальная средняя нагрузка для этой машины составляет около 15. Я вижу, что она использует системный ЦП (в отличие от ЦП пользователя), потому что я использую GKrellM для мониторинга это.
- В
вверху
есть много процессов Apache, использующих много ЦП.
- Веб-сайт и API (обслуживаемый Apache, конечно) большую часть времени недоступны. Некоторые запросы проходят, но занимают около трех-четырех минут. Другие запросы отвечают через некоторое время с сообщением «Не удается подключиться к серверу MySQL через /tmp/mysql.sock». ошибка - это та же ошибка, которую я получаю, когда MySQL превышает емкость и имеет слишком много соединений (только он фактически не говорит о слишком большом количестве соединений).
- MySQL принимает максимум 1024 соединения, сообщает mysqltuner.pl "[ !!] Максимальное использование соединения: 100% (1025/1024) ", что означает, что потребовалось больше, чем можно было обработать в какой-то момент. Обычно при нормальных условиях существует не более нескольких сотен одновременных подключений MySQL. mysqltuner.pl не сообщает о других проблемах, я был бы рад вставить вывод, если кто-нибудь захочет.
В конце концов, примерно через минуту или две, все восстанавливается самостоятельно без какого-либо вмешательства. Использование ЦП возвращается в норму, Apache и MySQL возобновляют нормальную работу.
Итак, что я могу сделать? : ) Как мне вообще начать выяснять, почему это происходит? Мне нужен этот запрос DELETE для выполнения по разным причинам, почему что-то сходит с ума, когда он выполняется (но не все время)?