Помните двухсистемное решение для миграции и слияния компаний-единорогов?

Java

предисловие

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

задний план

Последней компанией была компания по управлению активами P2P, которая в то время была в самом разгаре в Ханчжоу. В то время произошло две вещи: во-первых, наша собственная платформа управления активами была подключена к банковской депозитарной системе, а во-вторых, наша компания приобрела местную P2P-компанию в Ханчжоу (должен сказать, что компания все еще была сильна в того времени). Поэтому на уровне компании было принято решение перенести и синхронизировать пользовательские данные приобретенной компании с нашей собственной системной системой.Во-первых, нет необходимости повторно обращаться к платформе приобретения для банковского депозитария.Во-вторых, удобно управлять и поддерживать data. , но и провести демонстрационную работу, чтобы в будущем приобрести больше платформ (должен сказать, амбиции очень большие, но амбиции не стоят рыжеволосого документа, хахаха).

анализировать

Далее я использую для их представления соответственно системы A и B. Система B является объектом миграции и должна быть объединена с системой A.
Для такой работы, как миграция системы, я лично считаю, что мы должны начать с двух аспектов:

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

С точки зрения бизнеса говорить, собственно, не о чем, из-за разницы в системном бизнесе то, как быть совместимым с существующим бизнесом, зависит от реальной ситуации. Например, пользовательские таблицы систем A и B могут иметь разные поля, более или менее, или концептуальные конфликты, все из которых возможны, в зависимости от их соответствующих компромиссов. Конечно, есть особый сценарий, который нужно учитывать, то есть пользователь зарегистрировался в системах А и Б и имеет пользовательское поведение. Это также зависит от бизнес-сценария. В то время наша практика заключалась в том, чтобы по-прежнему вести запись системы Б, но эта запись использовалась не как настоящая, а только как логотип. Согласно записям B можно запросить реальные пользовательские данные A.
Конечно, поскольку это решение, оно больше с технической точки зрения. Как спроектировать это решение для этого — задача на общем уровне.
Прежде всего, нам нужно уточнить эффект, которого мы хотим достичь с помощью этой миграции:

  1. согласованность данных;
  2. Сделайте переход максимально плавным.

Проблема согласованности данных здесь на самом деле не является большой проблемой, хотя это самое необходимое звено. Как плавно перенести данные — самая сложная задача. Когда я услышал требование плавной миграции, моей первой реакцией были несколько сборщиков мусора, о которых я упоминал, когда смотрел на JVM, особенно классическая метафора: выплевывать шелуху, подметая пол. На самом деле эта сцена такая же. Благодаря плавной миграции это означает, что системы A и B, особенно система B, не перестанут обслуживаться. Затем во время миграции могут генерироваться новые данные, то есть операции DML в пользовательском трафике.

Решения

Кажется, что это не так просто сделать, неужели нет решения? Похожее решение, которое я могу придумать, - это синхронизация master-slave MySQL. В настоящее время MySQL большинства компаний использует архитектуру master-slave для обеспечения своей доступности. Так как же ведомая библиотека MySQL гарантирует, что она останется согласованной с основной библиотекой после сбоя и восстановления? Правильно, то, что все думают, это практика бэкапа + лог бинлога.
Журнал MySQL binlog, который очень важен для MySQL, используется для записи операции DML каждой записи. Для записи путем сбора журнала binlog для этой записи данные будут гарантированно согласованными на нескольких концах, или, другими словами, комбинация нескольких binlogs является окончательной записью базы данных. Это напоминает мне, что когда я работал в первой компании, я однажды выполнил требование агрегации таблиц MySQL для создания широкой таблицы.Его метод состоит в том, чтобы отслеживать журнал binlog в MySQL и отправлять его в Kafka, а также использовать сообщения kafka для генерации Генерируйте и обслуживайте записи таблицы базы данных синхронно, чтобы обеспечить согласованность данных с основной таблицей.
Но, к сожалению, из-за отсутствия инженерной службы, связанной с мониторингом бинлога MySQL на уровне компании, его нельзя напрямую запустить с уровня MySQL, но идея все же такая идея, которую можно инкрементно обрабатывать на уровне кода.

что вовлечено

Система

Для системы A роль в этом процессе миграции не очень важна, но стоит упомянуть, что поскольку будут добавлены пользователи системы B, часть идентификатора автоинкремента пользовательской таблицы необходимо освободить. имеет более 200 Вт данных, а система B имеет более 50 Вт данных, поэтому идентификатор автоинкремента необходимо изменить на 300 Вт, а автоинкремент начинается с 300 Вт. Эта часть пользователей системы B вставляется в соответствии с методом сопоставления (240w + идентификатор пользователя системы B).
почему ты хочешь сделать это? Это в основном для облегчения позиционирования уже откалиброванных данных. После переноса данных необходимо откалибровать данные, в противном случае о них можно будет судить только на основе уникальной информации пользователя. Когда информация о пользователе существует как в системах A, так и в системах B, она будет очень безвкусной в это время. .

Система Б

Что касается системы B, необходимо гарантировать, что пользователь может нормально использовать ее во время работы по миграции.Конечно, некоторые потери производительности могут быть допущены, но нельзя сказать, что доступность потеряна. Когда пользователь выполняет операцию запроса, это не повлияет, но когда есть добавления, удаления и модификации, вам нужно обратить внимание на запись соответствующего SQL в это время. Потому что по вышеизложенным идеям бэкап будет вырезаться в определенное время, поэтому и работа по миграции идет и на этот бэкап. Операции добавления, удаления и изменения, сгенерированные пользователем после этого, необходимо синхронизировать в виде инкрементного SQL. Конечно, здесь тоже бывают ситуации: а если пользовательские данные мигрируют и в это время генерируется SQL? Что, если задание миграции уже обрабатывает добавочный SQL в этот момент, а система B генерирует новый SQL? Нам необходимо тщательно проанализировать эти ключевые сценарии.

Миграция Слияние

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

Процедура калибровки

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

план

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

Над картинкой Над картинкойЭто блок-схема системы B.Это блок-схема процедуры миграции.
Прежде чем объяснять, я заранее сделаю две вещи:

  1. Установите пользователя системы B в Redis, и идентификационное содержимое равно 0. Например, ключ — com:showyool:user:123, а значение — 0. 0 означает, что миграция не началась, а 1 — что идет миграция.
  2. Отправьте эти идентификаторы пользователей в RocketMQ. Когда программы миграции запускаются на нескольких машинах, они будут использовать эти сообщения и сохранять их в ConcurrentLinkedQueue в памяти. Пул потоков в программе миграции будет обращаться к этой очереди, чтобы получать пользователей по одному и обрабатывать их одновременно.

Блок-схема системы B

Далее мы можем это объяснить.Во-первых, блок-схема системы потока B начинает объяснять:

  1. Когда приходит запрос операции DML от пользователя, сначала мы получаем ключ распределенной блокировки1, разумеется, это блокировка на уровне пользователя. Эта блокировка предназначена для координации с программой миграции.
  2. Если приобретение прошло успешно, вам нужно зайти в Redis, чтобы определить, существует ли com:showyool:user:xxx.Неважно, 0 это или 1, потому что пока он существует, это означает, что пользовательские данные не был перенесен, и поскольку был получен распределенный ключ блокировки 1, поэтому не нужно беспокоиться о работе программы миграции, что можно увидеть позже. Если он существует, то операция DML выполняется нормально, затем SQL организации сохраняется в MySQL, и, наконец, ключ распределенной блокировки1 высвобождается. Если он не существует, это означает, что данные пользователя были перенесены, а затем организуйте отправку SQL в RocketMQ. (Здесь вы можете спросить, почему в первом случае SQL хранится в MySQL, а во втором случае SQL отправляется в RocketMQ. Первоначальная идея здесь заключается в том, что если его отправить в RocketMQ, он может быть быстро использован, а первый In В одном случае миграция еще не выполнена, и добавлять, удалять или изменять SQL в случае отсутствия записи нецелесообразно, поэтому есть надежда, что информация, хранящаяся в MySQL, может быть активно извлечена после работы по миграции завершены.Конечно, SQL выполняет Sequential, на самом деле это могут гарантировать и MySQL, и RocketMQ).
  3. Возвращаясь к предыдущему слою, если распределенный ключ блокировки1 не получен в начале, то переходим к получению содержимого пользователя в redis. Если он не существует, это означает, что пользовательские данные были перенесены, и это использование обычного пользовательского трафика, а это означает, что предыдущий запрос пользователя мог сначала получить распределенную блокировку. Затем выполните обычные операции DML и организуйте отправку SQL в RocketMQ. Если это содержимое равно 0, выражение представляет собой обычный параллелизм пользовательского трафика, и данные еще не начали перенос в это время, затем выполните обычную операцию DML и организуйте SQL для хранения в MySQL. Есть еще один случай, тоже более сложный, то есть контент равен 1, значит, в это время он уже мигрирует. То есть программа миграции сначала получила распределенный ключ блокировки1, а затем установила содержимое в 1, и миграция уже началась. Тогда система B может в это время выполнять обычные операции DML. Далее, более хлопотным является то, что необходимо получить распределенный ключ блокировки2, который также находится на уровне пользователя. Зачем заниматься очередной распределенной блокировкой? Это сценарии, которые мы анализировали ранее. Давайте посмотрим на картинку ниже

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

  1. Добавлен первый новый SQL.Поскольку программа миграции еще не начала обрабатывать новый SQL, целесообразно добавить SQL в этот момент;
  2. Второй новый SQL, потому что программа миграции приобрела новый SQL, но добавила еще один SQL, на самом деле это типичная проблема фантомного чтения, когда мы изучаем принцип базы данных, это неразумно;
  3. Третий вновь добавленный SQL, так как программа миграции уже обработала инкрементальный SQL, вновь добавленный SQL в этом месте обрабатываться не будет, и ситуация аналогична второй.

Так что же делать с последними двумя случаями? Давайте сначала взглянем на третий новый SQL.В этом случае вам не нужно хранить его в MySQL, и вы можете отправить его непосредственно в RocketMQ для использования и обработки. Беда во втором случае. В данном случае у нас ее фактически не должно быть, поэтому нужно провести контроль параллелизма, поэтому я ввел вторую распределенную блокировку!
Как упоминалось выше, если распределенный ключ блокировки2 получен успешно, то судите, существует ли пользователь все еще в Redis.Если он не существует, значит, программа миграции была обработана, то это третий случай, и хорошо отправить его в RocketMQ. Если он все еще существует в Redis, то это первый случай, просто сохраните его в MySQL. Если получение распределенной блокировки не удается, это либо проблема параллелизма обычного пользовательского трафика, либо работа по миграции обрабатывает добавочный SQL. В это время просто повторите попытку и повторно получите распределенную блокировку, что устраняет вторую ситуацию. .

Блок-схема процедуры миграции

Если вы уже понимаете блок-схему приведенной выше системы B, то вы определенно сможете очень быстро понять процесс этой программы миграции. В серьезном отношении, я еще хочу сказать тебе об этом: (Видишь, мое отношение так хорошо, почему оно тебе не нравится, о, о, о)

  1. Потоки в пуле потоков получают пользователя из ConcurrentLinkedQueue, а затем запускают операцию миграции для этого пользователя.
  2. В первую очередь все равно необходимо получить распределенный ключ блокировки 1. Если он получен успешно, то пользовательский контент в redis устанавливается в 1, указывая на то, что он перешел в состояние миграции. Далее следует долгий период работы по миграции и слиянию, это кодовая операция делового характера, поэтому подробнее говорить неудобно. Когда работы по миграции и слиянию завершены, получен ключ распределенной блокировки2, то есть требуется шаг выполнения инкрементного SQL.Нормальные люди проспали, что, не выспались, то вы??). Затем выполните добавочный SQL, очистите информацию о пользователе в Redis после выполнения и, наконец, снимите распределенные блокировки key2 и key1. Затем, если получение распределенного ключа блокировки 2 не удается, это означает, что пользователь работает в это время, а затем повторите попытку.
  3. Если распределенный ключ блокировки2 не удалось получить, это означает, что пользовательский трафик вошел в систему B и удерживает ключ2, затем запишите пользователя в redis и откройте новый ключ, например com:showyool:fail:user:123, значение - количество отказов. Затем через некоторое время будет получен распределенный ключ блокировки 1. Если приобретение будет успешным, будет выполнен описанный выше процесс. Если это не удастся, счетчик будет продолжать увеличиваться. Если всего 15 отказов, то пользователь больше не будет эксплуатироваться, и будет выбран следующий пользователь. Это нужно учитывать, что этот пользователь может быть очень активным пользователем, поэтому этот тип пользователя может рассматриваться отдельно, хотя процесс обработки аналогичен основному процессу (он не появился во время миграции в то время, но было несколько пользователи проваливаются раз-два, это довольно неожиданно, да, неожиданность, вы это переводите, какая уж тут неожиданность).

воплощать в жизнь

Затем выше описываются основные идеи и планы, а затем также делится конкретной ситуацией реализации в то время.

  1. Защитите регистрационную запись системы B и направьте регистрацию пользователя в систему A.
  2. Выберите 2 часа ночи, чтобы начать операцию. Причиной выбора этого момента времени является то, что в 2 часа большинство пользователей уже ложатся спать, поэтому операции DML пользователя не особенно велики. Кроме того, будет большое количество запланированных задач, выполняемых рано утром, таких как начисление процентов, штрафных процентов и т. Д. (Вы можете увидеть доход Юэбао на Alipay, не отображаемый вовремя в 0:00 , но все запланированные задачи являются запущенными задачами в расчете). Поскольку запланированная задача будет иметь большую волну операций DML во время выполнения задачи, она может избежать этого момента времени и, как правило, может быть выполнена до 1:30.
  3. В 2 часа службы системы B должны быть отключены, а написанный код должен быть отправлен в системы A и B, а программа миграции и слияния должна быть развернута. На уровне базы данных требуется резервная копия базы данных системы B, а auto_increment пользовательской таблицы в базе данных системы A изменен на 300w. Прежде чем система B выйдет в онлайн, в redis нужно установить пользовательские данные, например com:showyool:user:123=0.Если говорить о полной плавной миграции, то это время не особо считается, ведь это тоже небольшая сервисная приостановка, К счастью, это место не занимает много времени.
  4. Все службы инспекции подключены к сети, и процедуры инспекции и калибровки запущены. Я не говорил много об этой части выше, потому что я думаю, что эта процедура является просто калибровкой делового характера, а также для согласованности данных. Кроме того, идентификатор пользователя должен быть отправлен в RocketMQ, и эти программы слияния миграции будут использовать эту тему и сохранять ее в ConcurrentLinkedQueue в своей соответствующей памяти. Потоки в пуле потоков будут постоянно получать идентификаторы пользователей из этой очереди. Как только появляется идентификатор пользователя, начинается работа по миграции.
  5. Следующим шагом является наблюдение за различными условиями данных, например, сколько пользователей было перенесено и сколько пользователей осталось.
  6. Конечно, неудачный пользователь также упоминается в приведенной выше блок-схеме.Хотя он не отображается в реальной ситуации, если в конце есть такой неудачный пользователь, он будет повторно отправлен в RocketMQ для продолжения выполнения.
  7. В конце концов, конечно же, его отдали на пробу... а я просто смотрел на восходящее солнце, гадая, то ли я в оцепенении, то ли сплю.

следовать за

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

Наконец

Если моя статья была вам полезна, я надеюсь, что вы, ребята,обращать внимание\color{red}{Нажмите, чтобы подписаться} поставить лайк\цвет{красный}{Нравится}, Еще раз спасибо за вашу поддержку!
Вот также мой адрес Github:GitHub.com/showyoOL/Согласно…