Назад | Перейти на главную страницу

репликация базы данных для регистрации нового пользователя

У меня есть база данных, в которой хранятся пользователи моего приложения. Когда новый пользователь регистрируется, запись для этого пользователя вставляется в базу данных. У меня есть реплицированная версия (подчиненная) этой базы данных (пока используется mysql).

Меня беспокоит такой сценарий:

Шаг 1: пользователь регистрируется, и пользовательская запись вставляется в базу данных

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

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

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

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

Есть три решения, которые я использовал в прошлом, и одно, которое я не использовал лично.

  1. Следите за задержкой репликации на ведомом, вынимайте его из пула, если он отстает от ведущего. Самый надежный способ справиться с этим - использовать инструмент Heartbeat из набора Percona. Это, вероятно, не решит проблему с сообщениями на форуме.
  2. Придерживайтесь запросов от мастера для определенных категорий запросов. Например, успешная страница и любые страницы в CMS или центре администрирования будут запрашивать только у мастера. Это создает дополнительную нагрузку на мастера.
  3. Используйте кеширование. Что-то вроде Memcached или подобное. Записи, которые подвержены этой проблеме, должны одновременно записываться в memcached, а чтение должно происходить в первую очередь оттуда. Промахи считываются с ведомого, а это значит, что он все равно стоит иметь. Вам придется изменить каждую часть вашего приложения, которая читает или пишет, но если вы правильно абстрагировались, это не должно быть трудным. Вы мог также реализовать это, используя что-то вроде mysql-proxy, но я не могу рекомендовать этот вариант.
  4. Синхронная репликация. Я не думаю, что MySQL может это сделать, но в следующем крупном выпуске у них есть нечто, называемое полусинхронной репликацией. Идея состоит в том, что исходный запрос на запись не вернется, пока данные также не будут записаны на ведомые устройства. У этого есть обратная сторона, из-за которой ваши запросы на запись занимают больше времени, а вся ваша платформа отключается, когда это делает ведомый.

Вариант 3 был для меня наиболее успешным в прошлом, и я бы выбрал его в будущем.

Не совсем (насколько я знаю); у вас должна быть значительная задержка (или серьезная ошибка, приводящая к рассинхронизации ведомого устройства), чтобы пользователь мог войти в систему и потенциально попасть в подчиненную базу данных быстрее, чем подчиненная база данных может реплицировать сервер.

Единственная альтернатива, которую я могу придумать, - это иметь что-то на уровне приложения, которое запускает ведущее устройство, если ведомое устройство не может найти запись; но это, скорее, в первую очередь противоречит цели возможности запросить подчиненное устройство.

Перед выполнением запроса проверьте, является ли база данных подчиненной, если да, проверьте, запущены ли подчиненные потоки, и если да, проверьте Seconds_Behind_Master. Все в SHOW SLAVE STATUS;. Если он не работает или наблюдается значительная задержка, запустите запрос на главном сервере.