Абсурдное поведение MySQL над одним и тем же набором данных, но разными потоками - PullRequest
2 голосов
/ 14 марта 2012

Я подключаюсь к базе данных MySQL из двух разных экземпляров PHP. Первый поток добавляет новую строку, передает идентификатор новой строки во второй поток через очередь. Иногда второй поток не может найти новые данные строки, хотя теоретически он должен попасть в базу данных после того, как первые потоки закончили свою работу.

Упрощенный псевдокод выглядит примерно так:

Тема 1

$db = get_mysql_connection();
$db->beginTransaction();
$rowid = $db->query("insert data..");
$db->commit();

//For Debugging purposes only
$db->check_if_row_exists($rowid); //Always returns true

send_to_queue($rowid);

Тема 2

$rowid = fetch_from_queue();
$db = get_mysql_connection();
$db->check_if_row_exists($rowid); //Sometimes returns false;
usleep(1000000);
$db->check_if_row_exists($rowid); //Always returns true.

Я не могу понять, почему поток 1 показывает, что данные имеют действительную запись, а поток 2, который, безусловно, делает запрос иногда после потока 1, не может найти данные. Я использую транзакции для фиксации данных, это делает что-то странное?

Я использую Gearman в качестве очереди. Поток 1 запускается через Apache, а поток 2 просто запускается как отдельный процесс.

Редактировать 1: Это происходит, когда поток 2 работает одновременно с потоком 1. Очевидно, он достигает некоторого состояния гонки с потоком 1, но я не могу понять, почему.

Редактировать 2: Как указывает Н.Б., Innodb задерживает запись данных на диск, и, следовательно, они не видны для второго потока.

Как мне справиться с этим сценарием? Sleep / Usleep почти всегда является неоптимальным решением, так как в условиях большой нагрузки время ввода-вывода диска может увеличиться. Есть ли какой-нибудь способ «уведомить» второй поток о том, что Innodb завершил ввод / вывод диска?

1 Ответ

0 голосов
/ 14 марта 2012

Из моего комментария видно, что нет необходимости что-либо менять:

Здесь нет условий гонки. Поток 1 может видеть свои транзакции и данные. Поток 2 не может, потому что они еще не достигли диска (нет Вызов fsync был сделан InnoDB). Естественно, вы всегда будете увидеть данные из потока 1, но если он не находится на диске во время вызов - вы не увидите его в потоке 2. Потоки 1 и 2 не видят поделитесь тем же самым потоком соединения mysql, оба используют другой. Так Короче говоря - если нет на диске, данные отсутствуют. Это не на диске потому что InnoDB будет задерживать запись, пока привод не будет готов к записи. Вот почему вы видите это после сна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...