Я разработал веб-сервис (PHP / MySQL), который просто выводит код купона через строку JSON.
Как это устроено: приложение получает 1 параметр (электронная почта), затем делает запрос к таблице базы данных, чтобы получить код купона, который еще не был назначен. Затем делается запрос на обновление строки этого кода купона и положить «1» в назначенном столбце. (SELECT / UPDATE рутина)
После этого JSON выводится так:
echo '{"couponCode": "'. $coupon_code . '"}';
Это все.
Проблема в том, что веб-сервис получает 10000 запросов примерно за 1 минуту. Это происходит только один раз в день. Если я посмотрю в необработанных журналах apache, то увижу, что он каждый раз получает ровно 10000 запросов, но в моей таблице обновлено только 984 строки (т.е. дано 984 кодов купонов). Я тестировал его несколько раз, и каждый раз он колеблется между 980 и 986. Файл журнала, созданный веб-сервисом, не показывает никаких ошибок и точно отражает то, что было обновлено в базе данных, каждый раз от 980 до 986 новых строк.
Мой вопрос: что случилось с пропущенными запросами? Неужели у сервера недостаточно памяти для обработки таких многочисленных запросов в этот короткий промежуток времени? (Когда я тестирую с 5000 запросов, он работает нормально)
Если это может помочь, вот функция, которая получает новые коды купона:
function getNewCouponCode($email){
$stmt = $this->connector->prepare("SELECT * FROM coupon_code WHERE email = '' ORDER BY id ASC LIMIT 1");
$stmt2 = $this->connector->prepare("UPDATE coupon_code SET email = :email WHERE id = :id");
try{
$this->connector->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->connector->beginTransaction();
$this->connector->exec("LOCK TABLES coupon_code WRITE");
/*TRANSACTION 1*/
$stmt->execute();
$result["select"] = $stmt->fetch(PDO::FETCH_ASSOC);
/*TRANSACTION 1*/
/*TRANSACTION 2*/
$stmt2->bindParam(":email", $email);
$stmt2->bindParam(":id", $result["select"]["id"]);
$result["update"] = $stmt2->execute();
/*TRANSACTION 2*/
$this->connector->commit();
$this->connector->exec('UNLOCK TABLES');
return $result;
}catch(Exception $e) {
$this->connector->rollBack();
$this->connector->exec('UNLOCK TABLES');
$result["error"] = $e->getMessage();
return $result;
}
}
Заранее спасибо.
986 запросов в минуту — это довольно значительная нагрузка для приложения PHP, как вы его проектировали, и веб-сервера Apache. Похоже, вы запускаете все это на одном сервере.
Прежде всего, кто бы ни хлопнул вас со скоростью 10 000 раз в минуту, вы должны знать, чтобы потом повторить попытку в случае сбоя. Почему этого не происходит? Если эта удаленная система находится под вашим контролем, посмотрите, сможете ли вы это исправить.
Далее вы обнаружите, что модель потоков Nginx гораздо эффективнее, чем Apache, для ваших действий.
Теперь, что касается вашего приложения … это не похоже, что вы действительно нуждаетесь в SELECT
а потом UPDATE
, Почему бы не просто обновить, а проверить результат? Тогда он сам по себе атомарный, и вам не нужно выполнять эту блокировку таблиц (что на самом деле замедлит вас).
Других решений пока нет …