У меня есть очень простой запрос, который вставляет каждый вызов API в таблицу messageRequest. это может идти максимум 1000 запросов или больше в секунду.
например, http://myapplication.com/sendMessage.php?phone=123&GSM = Mobitel&сообщение = HelloWorld
Предположим, любой, у кого есть мобильное приложение, будет называть этот URL и когда я делаю как 1000 звонков через
ab -n 1000 -c 10 «http://myapplication.com/sendMessage.php?phone=123&GSM = Mobitel&сообщение = HelloWorld«
Запрос insert into messageRequest values(null, phone, gsm, message);
он работает нормально, но проблема в том, что при наличии такого количества одновременных звонков я пытаюсь использовать страницу журнала активности в этом URL http://myapplication.com/apiLogs.php чтобы увидеть, сколько SMS-вызовов API получено за последние 30 минут.
Это просто запросы SELECT count(*) from messageRequest where created_at > '2016-10-01 12:01:00'
для возврата результата требуется около 100 секунд. и когда я перестал делать параллельные звонки через ab -n command
работает нормально. поэтому я предположил, что когда происходит 1000 одновременных вызовов и запись вставляется для каждого вызова, MYSQL таблица messageRequest блокируется.
чтобы избежать этой проблемы,
я изменил это на несколько сеансов, например, на sendMessage.php
я сделал это с user1, и для apiLogs.php я сделал это с user2. таким образом, две сессии diff могут обращаться к одной и той же таблице для одновременного чтения и записи, но это тоже не помогло.
sendMessage.php
define('DB_HOST', 'localhost');
define('DB_USER', 'user1');
define('DB_PASS', '');
apiLogs.php
define('DB_HOST', 'localhost');
define('DB_USER', 'user2');
define('DB_PASS', '');
я запутался, как заставить это работать без всякого времени ожидания, когда столько одновременных звонков?
Обновить
код sendMessage.php
define('DB_HOST', 'localhost');
define('DB_USER', 'user1');
define('DB_PASS', 'user1');
mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db('smsApp');mysql_query(
"insert into messageRequest values (
NULL,
'{$_REQUEST['phone']}',
'{$_REQUEST['gsm']}',
'{$_REQUEST['message']}',
'{$_REQUEST['text']}',
now()
);
");
И я делаю параллельный запрос с этой командой
ab -n 1000 -c 10 "http://myapplication.com/sendMessage.php?phone=123&gsm=mobitel&message=helloworld&text=123"
И пока работает, я пытаюсь просмотреть эту страницу apiLogs.php (исходный код ниже)
define('DB_HOST', 'localhost');
define('DB_USER', 'user2');
define('DB_PASS', 'user2');
mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db('smsApp');
$30m_ago = new DateTime("30 minutes ago");
$s = $30m_ago->format("Y-m-d H:i:s");
$result = mysql_query("SELECT count(*) from messageRequest where created_at > '$s'");
$response['last_30_min_sms_count'] = current(mysql_fetch_row($result));
echo json_encode($response)."\n";
Используйте InnoDB, а не MyISAM. Таким образом, стол не будет заблокирован.
Не используйте устаревший mysql_*
API, использовать mysqli_*
или же PDO
,
«Не ставь в очередь, просто сделай это». То есть может быть значительно быстрее просто выполнить задачу, чем проходить через очередь.
Фрагмент кода подвержен «SQL-инъекции».
Иметь INDEX(created_at)
, Тот SELECT
может работать полностью в индексе.
Вместо DateTime
пакет, вы могли бы просто сказать, SELECT ... WHERE created_at > NOW() - INTERVAL 30 MINUTE
,
Больше
С InnoDB я предлагаю innodb_flush_log_at_trx_commit = 2
значительно сократить ввод-вывод, вызванный 1000 отдельных INSERTs
в секунду.
Других решений пока нет …