Как этот запрос может сломать мою репликацию MySQL? - PullRequest
1 голос
/ 27 октября 2011

У меня стандартная однонаправленная настройка главный-подчиненный.Таблицы имеют механизм хранения MyIsam.

Версии:

Версия главного сервера: 5.1.41-3ubuntu12.10-log Версия протокола: 10

Первый ведомый: Серверверсия: 5.1.41-3ubuntu12.10 Версия протокола: 10

2nd Slave: Версия сервера: 5.1.49-1ubuntu8.1 Версия протокола: 10

Я настроил всех пользователей, кромевыделенный пользователь репликации, доступный только для чтения на ведомых устройствах.

Следующая инструкция, выполненная на ведущем устройстве, не реплицируется правильно:

$insert = "INSERT INTO search_affiliate_product
(film_id, ext_id, affiliate_id, `status`, url, created_at)
SELECT film_id, LPAD(imdb, 7, '0'), $affiliate_id, 5, CONCAT('http://www.imdb.com/title/tt', LPAD(imdb, 7, '0'),'/'), NOW() FROM search_film_entity
WHERE film_id NOT IN (SELECT film_id FROM search_affiliate_product WHERE affiliate_id = $affiliate_id)
AND status IN (5, 9)
AND release_year BETWEEN 0 AND $year
AND imdb > 0";

Подчиненное устройство получает эту ошибку:

Error 'Duplicate entry '271769' for key 'PRIMARY'' on query. Default database:     'flimmit_search_14'. Query: 'INSERT INTO `search_affiliate_product` (`affiliate_id`,     `ext_id`, `url`, `status`, `film_id`, `created_at`, `updated_at`) VALUES ('16', '1991/JohnnyStecchino', 'http://www.cineman.ch/movie/1991/JohnnyStecchino/review.html', '5', '102164', '2011-10-26 02:30:05', '2011-10-26 02:30:05')'

Я также сделал несколько других наблюдений:

  • Оператор передается «как есть» через журнал bin (журнал ретрансляции и главный журнал), поэтому явные данные, которыевставленный не содержится, но весь оператор с select и subselect выполняется на ведомом устройстве, полагаясь на локальные данные.

  • Если я смотрю на таблицу master и slave и сортирую попервичный ключ, я вижу ряд вставок производится бПриведенное выше утверждение на обоих серверах.Строки до и после этого синхронизируются.Также много строк в этом диапазоне, которые производятся этим оператором, равны.Но есть и расхождения.

Я думал, что проблема может быть из-за одновременных транзакций SQL.Так что процесс вставки мешает другим вставкам, и поэтому значения перепутаны, где на ведомом устройстве этого не происходит, потому что журнал обрабатывается процедурно.

Я также заметил, что во время процесса вставки оператора некоторыеКажется, вставлены идентификаторы, которые не вставляются на другом сервере, и вставляются некоторые дубликаты (дубликаты в поле ext_id, которое заполняется полем imdb из другой таблицы, которая уникальна ...

IЯ действительно застрял здесь.

Любые предложения? Мне бы очень хотелось понять, почему это происходит.

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

Следующая странная вещь - то, что второй раб, кажется, работает нормально! только первый раб получает проблемы. Япросто не понимаю этого.

Ответы [ 2 ]

2 голосов
/ 19 марта 2012

этот тип репликации можно надежно выполнять только в innodb со следующими настройками на клиенте

[mysqld]
innodb_flush_log_at_trx_commit=1
sync_binlog=1
1 голос
/ 27 октября 2011

Я бы сказал, что ваши счетчики AUTO_INCREMENT для (предполагающего) столбца ID в таблице search_affiliate_product вышли из строя.В частности, я подозреваю, что значение AUTO_INCREMENT на первом ведомом устройстве каким-то образом опередило эквивалентное мастер-значение.Я предполагаю, что значение на подчиненном сервере 2 осталось в шаге, поэтому ошибка там не возникает.

Если вы запустите следующее на главном сервере, сервере 1 и сервере 2, вы сможете увидеть, является ли этоtrue или нет:

select auto_increment
 from information_schema.tables
 where table_name = 'search_affiliate_product';

Одна из причин, по которой это может произойти, заключается в том, что данные вставляются в search_affiliate_product непосредственно на подчиненном сервере 1, то есть не через мастер, следовательно, увеличивая значение AUTO_INCREMENT и вызывая егоопередить мастера.

Простое решение для этого - получить максимальный идентификатор от подчиненного сервера 1, используя:

select max(id) from search_affiliate_product;

Допустим, вы получите значение 123456. Добавьте 100для удачи, а затем измените значение auto_increment главной таблицы search_affiliate_product:

alter table search_affiliate_product auto_increment = 123556;

Затем попробуйте снова запустить вставку.

Если это не так, то я думаю, этовозвращается к чертежной доске!

...