• Русский
  • Миграция MySQL-PXC на MySQL-MGR

    Это руководство содержит подробные инструкции по миграции с MySQL-PXC (Percona XtraDB Cluster) 5.7 на MySQL Group Replication (MGR) 8.0 на Alauda Container Platform.

    Содержание

    ПредпосылкиЗадачаРешениеИнформация об окруженииPXC vs MGR: основные различияТиповые сценарии использованияПредварительные требованияВажные ограниченияНачало работы1. Получите пароль root MySQL2. Определите имена Pod3. Проверьте состояние кластера4. Рекомендации по kubectl execПошаговое руководствоШаг 1: Анализ совместимости схемыИсправление проблем со схемойШаг 2: Анализ набора символов и collationПреобразование в utf8mb4Шаг 3: Создайте целевой экземпляр MySQL-MGR 8.0Шаг 4: Миграция данных, пользователей и привилегийШаг 5: Проверьте миграциюШаг 6: Оптимизация после миграции1. Обновите статистику таблиц2. Проверьте фрагментациюПереключение приложенияШаг 7: Переключите приложение на целевой кластер1. Убедитесь, что приложение остановлено2. Обновите строку подключения приложения3. Перезапустите приложение4. Проверьте работоспособность приложенияМониторингАварийное восстановлениеПлан откатаРаспространенные проблемы и решенияПроблема: ошибка GTID_PURGEDПроблема: ошибки преобразования набора символовПроблема: ошибки привилегий DEFINERПроблема: ошибки плагина аутентификацииУстранение неполадокДиагностические командыРекомендацииПланирование перед миграциейВо время миграцииПосле миграцииСправочные сведенияОценка размера и времениСправка по флагам mysqldumpПолезные ссылки

    Предпосылки

    Задача

    Срок поддержки MySQL 5.7 истек в октябре 2023 года, а MySQL-PXC считается устаревшим и удаляется, начиная с Alauda Database Service for MySQL v4.3.0. Организациям необходимо перейти на MySQL 8.0, чтобы продолжать получать обновления безопасности и использовать новые возможности.

    Миграция production-баз данных требует учета множества сложных факторов:

    • Совместимость схемы с зарезервированными ключевыми словами MySQL 8.0
    • Изменения набора символов (utf8mb4)
    • Обновление плагинов аутентификации
    • Обеспечение целостности данных во время миграции

    Решение

    Это руководство содержит полные, проверенные инструкции по миграции MySQL-PXC 5.7 на MySQL-MGR 8.0:

    • Проверенный подход: подтверждено на ACP v4.0+ с использованием Alauda Database Service for MySQL
    • Полное покрытие объектов: миграция всех стандартных объектов MySQL (таблиц, представлений, routines, triggers, events, пользователей, grants)
    • Совместимость схемы: автоматические проверки и исправления проблем совместимости с MySQL 8.0
    • Комплексная проверка: верификация по 9 категориям объектов
    • Минимальный риск: подробные процедуры отката и проверка на каждом этапе

    Информация об окружении

    КомпонентВерсия
    Источник (PXC)Percona XtraDB Cluster 5.7.44
    Назначение (MGR)MySQL Group Replication 8.0.44
    Версия ACPv4.0 или новее
    MySQL Operatorv4.0 или новее

    PXC vs MGR: основные различия

    АспектPXC 5.7 (Источник)MGR 8.0 (Назначение)
    Шаблон имени Pod${NAME}-pxc-0${NAME}-0
    Спецификатор контейнераНе требуется (по умолчанию mysql)Требуется: -c mysql
    Основная конечная точка${NAME}-proxysql.${NS}.svc.cluster.local:3306${NAME}-read-write.${NS}.svc.cluster.local:3306
    Конечная точка репликиТа же, что и основная (маршрутизацию выполняет ProxySQL)${NAME}-read-only.${NS}.svc.cluster.local:3306
    Тип репликацииGalera (синхронный multi-master)Group Replication (single-primary с асинхронными репликами)
    Шаблон имени Secret${NAME}mgr-${NAME}-password
    WARNING

    Всегда проверяйте фактические имена Pod с помощью kubectl get pod -n <namespace> перед выполнением команд миграции.

    Типовые сценарии использования

    СценарийРазмер базы данныхОценочное время простоя
    Небольшая база< 10GB15-30 минут
    Средняя база10-50GB30-60 минут
    Большая база50-200GB1-2 часа
    Проблемы со схемойЛюбой размер+1-2 часа на исправления
    Миграция набора символовЛюбой размер+30-60 минут

    Предварительные требования

    Перед выполнением миграции убедитесь, что у вас есть:

    • ACP v4.0 или новее с MySQL Operator v4.0 или новее
    • Рабочий кластер MySQL-PXC 5.7 в качестве источника
    • Включенный режим GTID (@@gtid_mode = ON, @@enforce_gtid_consistency = ON)
    • Новый кластер MySQL-MGR 8.0, созданный как целевой до миграции
    • Объем хранилища в 2-3 раза больше размера исходной базы данных
    • Сетевое подключение от вашей локальной машины к обоим кластерам

    Важные ограничения

    • Во время экспорта и импорта требуется простой приложения, чтобы обеспечить согласованность
    • Рекомендуемый максимальный размер базы данных: 200GB (для более крупных баз могут потребоваться альтернативные подходы)
    • GTID должен быть включен на исходном кластере
    • Целевой кластер должен быть создан до начала миграции
    • Производительность хранилища на целевом кластере должна соответствовать или превышать показатели исходного

    Начало работы

    1. Получите пароль root MySQL

    # Для источника PXC 5.7
    kubectl get secret <source-name> -n <source-namespace> -o jsonpath='{.data.root}' | base64 -d
    
    # Для целевого MGR 8.0
    kubectl get secret mgr-<target-name>-password -n <target-namespace> -o jsonpath='{.data.root}' | base64 -d

    2. Определите имена Pod

    # Проверьте Pod исходного PXC
    kubectl get pod -n <source-namespace> | grep <source-name>
    # Пример вывода: source-pxc-0, source-pxc-1, source-pxc-2
    
    # Проверьте Pod целевого MGR
    kubectl get pod -n <target-namespace> | grep <target-name>
    # Пример вывода: target-0, target-1, target-2

    3. Проверьте состояние кластера

    # Проверьте состояние источника PXC
    kubectl get mysql <source-name> -n <source-namespace>
    # Ожидается: STATE = ready, PXCSTATE = ready
    
    # Проверьте состояние целевого MGR
    kubectl get mysql <target-name> -n <target-namespace>
    # Ожидается: все 3 участника готовы, STATUS = Running

    4. Рекомендации по kubectl exec

    Для PXC 5.7 (источник):

    # Спецификатор контейнера не нужен для PXC
    kubectl exec <source-name>-pxc-0 -n <namespace> -- \
      mysql -uroot -p<password> -e "SQL_HERE"

    Для MGR 8.0 (назначение):

    # Для MGR всегда используйте -c mysql
    kubectl exec <target-name>-0 -n <namespace> -c mysql -- \
      mysql -uroot -p<password> -e "SQL_HERE"
    TIP
    • Всегда используйте порядок параметров: kubectl exec -n <namespace> <pod-name> -- <command>
    • Перед командой используйте -- (double dash), чтобы отделить параметры kubectl от команды
    • Избегайте heredoc (<<EOF) с kubectl exec — они часто не работают из-за особенностей экранирования shell

    Пошаговое руководство

    Шаг 1: Анализ совместимости схемы

    Выполните этот анализ за одну неделю до запланированной миграции.

    Запустите следующие команды для выявления проблем совместимости схемы:

    # Проверка столбцов с зарезервированными ключевыми словами
    kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
      mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -e "
        SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME
        FROM information_schema.COLUMNS
        WHERE LOWER(COLUMN_NAME) IN ('rank','groups','function','tables','indexes','procedure','file','process');
      "
    
    # Проверка столбцов ZEROFILL
    kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
      mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -e "
        SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, COLUMN_TYPE
        FROM information_schema.COLUMNS
        WHERE COLUMN_TYPE LIKE '%ZEROFILL%';
      "
    
    # Проверка недопустимых значений по умолчанию для дат
    kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
      mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -e "
        SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, COLUMN_DEFAULT
        FROM information_schema.COLUMNS
        WHERE COLUMN_DEFAULT = '0000-00-00'
           OR COLUMN_DEFAULT = '0000-00-00 00:00:00';
      "

    Исправление проблем со схемой

    # Исправление столбцов с зарезервированными ключевыми словами (пример)
    kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
      mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -e "
        USE db1;
        ALTER TABLE users CHANGE COLUMN rank user_rank INT;
      "
    
    # Исправление столбцов ZEROFILL
    kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
      mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -e "
        USE db1;
        ALTER TABLE products MODIFY COLUMN price DECIMAL(10,2);
      "

    Шаг 2: Анализ набора символов и collation

    Проверьте таблицы, не использующие utf8mb4:

    kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
      mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -e "
        SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_COLLATION
        FROM information_schema.TABLES
        WHERE TABLE_SCHEMA NOT IN ('information_schema','mysql','performance_schema','sys')
          AND TABLE_COLLATION NOT LIKE 'utf8mb4%';
      "

    Преобразование в utf8mb4

    # Преобразование баз данных в utf8mb4
    for db in ${DATABASES}; do
      kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
        mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -e "
          ALTER DATABASE ${db} CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
        "
    done
    
    # Преобразование таблиц в utf8mb4
    for db in ${DATABASES}; do
      TABLES=$(kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
        mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -N -e "
          SELECT TABLE_NAME FROM information_schema.TABLES
          WHERE TABLE_SCHEMA = '${db}' AND TABLE_TYPE = 'BASE TABLE';
        ")
    
      for table in ${TABLES}; do
        echo "Converting ${db}.${table}..."
        kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
          mysql -uroot -p${SOURCE_MYSQL_PASSWORD} ${db} -e "
            ALTER TABLE ${table} CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
          "
      done
    done
    WARNING

    Для таблиц с длинными индексами VARCHAR/TEXT (>191 символ) может потребоваться настройка длины индекса:

    ALTER TABLE users DROP INDEX idx_email;
    ALTER TABLE users ADD UNIQUE INDEX idx_email (email(191));

    Шаг 3: Создайте целевой экземпляр MySQL-MGR 8.0

    Создайте целевой экземпляр MySQL-MGR 8.0 незадолго до этапа миграции данных.

    Через веб-консоль:

    1. Выберите версию MySQL 8.0
    2. Настройте ресурсы (рекомендуется +10-20% памяти по сравнению с исходным кластером из-за накладных расходов MySQL 8.0)
    3. Установите размер хранилища в 2-3 раза больше размера исходной базы данных

    Через командную строку:

    TARGET_NAME="mysql-8-target"
    NAMESPACE="your-namespace"
    STORAGE_SIZE="500Gi"
    
    cat << EOF | kubectl -n $NAMESPACE apply -f -
    apiVersion: middleware.alauda.io/v1
    kind: Mysql
    metadata:
      name: $TARGET_NAME
      namespace: $NAMESPACE
      labels:
        mysql/arch: mgr
    spec:
      mgr:
        enableStorage: true
        image: {}
        members: 3
        monitor:
          enable: true
          exporter: {}
        resources:
          server:
            limits:
              cpu: "2"
              memory: 4Gi
            requests:
              cpu: "2"
              memory: 4Gi
        router:
          replicas: 1
          resources:
            limits:
              cpu: 500m
              memory: 512Mi
            requests:
              cpu: 500m
              memory: 512Mi
          svcRO:
            type: ClusterIP
          svcRW:
            type: ClusterIP
        strictSecurityModeEnabled: true
        upgradeOption: {}
        volumeClaimTemplate:
          metadata: {}
          spec:
            accessModes:
            - ReadWriteOnce
            resources:
              requests:
                storage: ${STORAGE_SIZE}
            storageClassName: dataservice-topolvmsc
          status: {}
      params:
        mysql: {}
        router:
          DEFAULT:
            max_total_connections: "200"
          logger:
            level: info
      upgradeOption:
        autoUpgrade: false
      version: "8.0"
    EOF

    Проверка целевого кластера:

    kubectl -n $NAMESPACE get mysql $TARGET_NAME -w
    # Ожидается: STATE = Ready, MGRSTATE = ready

    Шаг 4: Миграция данных, пользователей и привилегий

    Важно: остановите запись приложения

    С этого момента приложение должно оставаться остановленным (или строго только для чтения) до завершения переключения. Любые данные, записанные в исходную базу после этого шага, будут потеряны.

    Процедура:

    1. Остановите запись приложения: масштабируйте приложение до нуля реплик:

      kubectl scale deployment <app-name> --replicas=0 -n <app-namespace>
    2. Определите базы данных для миграции:

      # Список пользовательских баз данных (НЕ включайте: information_schema, mysql, performance_schema, sys)
      kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
        mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -N -e "
          SELECT SCHEMA_NAME FROM information_schema.SCHEMATA
          WHERE SCHEMA_NAME NOT IN ('information_schema','mysql','performance_schema','sys');
        "
    3. Экспорт и импорт данных:

      SOURCE_NAME="source"
      SOURCE_NAMESPACE="your-namespace"
      SOURCE_MYSQL_PASSWORD="source-root-password"
      
      TARGET_NAME="mysql-8-target"
      TARGET_NAMESPACE="your-namespace"
      TARGET_MYSQL_PASSWORD="target-root-password"
      
      DATABASES="db1 db2 db3"
      
      for db in ${DATABASES}; do
        echo "Migrating database: ${db}..."
      
        # Экспорт из источника PXC
        kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
          mysqldump -uroot -p${SOURCE_MYSQL_PASSWORD} \
            --single-transaction \
            --quick \
            --lock-tables=false \
            --set-gtid-purged=ON \
            --routines \
            --events \
            --triggers \
            --databases ${db} \
          | grep -v "SET @@GLOBAL.GTID_PURGED" \
          | kubectl exec -i ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
            mysql -uroot -p${TARGET_MYSQL_PASSWORD}
      
        echo "Migrated: ${db}"
      done
    4. Миграция пользователей и привилегий:

      # Список не-системных пользователей из источника PXC
      USERS=$(kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
        mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -N -e "
          SELECT CONCAT('''', User, '''@''', Host, '''')
          FROM mysql.user
          WHERE User NOT IN ('root','mysql.sys','mysql.session','mysql.infoschema',
                             'monitor','operator','clustercheck','xtrabackup','replication')
            AND User NOT LIKE 'mysql.%'
            AND Host != 'localhost';
        ")
      
      # Для каждого пользователя создайте учетную запись и примените grants на целевом кластере
      for user_host in ${USERS}; do
        echo "Migrating user: ${user_host}..."
      
        # Получить оператор CREATE USER (включает auth plugin и хеш пароля)
        CREATEUSER=$(kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
          mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -N -e "SHOW CREATE USER ${user_host};")
      
        # Создать пользователя на целевом кластере
        kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
          mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "${CREATEUSER};"
      
        # Получить операторы GRANT с источника
        GRANTS=$(kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
          mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -N -e "SHOW GRANTS FOR ${user_host};")
      
        # Применить grants на целевом кластере
        echo "${GRANTS}" | while read grant; do
          kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
            mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "${grant};"
        done
      done
      
      # Обновить привилегии на целевом кластере
      kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
        mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "FLUSH PRIVILEGES;"
      TIP

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

      kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
        mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "
          ALTER USER ${user_host} IDENTIFIED WITH mysql_native_password BY '<password>';
        "
    TIP

    Подход со streaming через mysqldump не требует дискового пространства для файлов дампа.

    Шаг 5: Проверьте миграцию

    TARGET_NAME="mysql-8-target"
    TARGET_NAMESPACE="your-namespace"
    TARGET_MYSQL_PASSWORD="target-root-password"
    DATABASES="db1 db2 db3"
    
    for db in ${DATABASES}; do
      echo "=== Verifying database: ${db} ==="
    
      # Сравнение количества таблиц
      echo "Tables:"
      kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
        mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -N -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = '${db}' AND TABLE_TYPE = 'BASE TABLE';"
    
      kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
        mysql -uroot -p${TARGET_MYSQL_PASSWORD} -N -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = '${db}' AND TABLE_TYPE = 'BASE TABLE';"
    
      # Проверка корректной работы представлений
      kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
        mysql -uroot -p${TARGET_MYSQL_PASSWORD} -N -e "
          SELECT TABLE_NAME FROM information_schema.VIEWS WHERE TABLE_SCHEMA = '${db}';
        " | while read view; do
          kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
            mysql -uroot -p${TARGET_MYSQL_PASSWORD} ${db} -e "SELECT 1 FROM ${view} LIMIT 1;" > /dev/null 2>&1 \
            && echo "✓ View ${view} OK" \
            || echo "✗ View ${view} FAILED"
        done
    done

    Контрольный список проверки:

    • Одинаковое количество таблиц в каждой базе данных
    • Одинаковое количество строк в каждой таблице
    • Одинаковое количество представлений
    • Все представления успешно выполняются
    • Все stored procedures и functions существуют
    • Все triggers и events мигрированы
    • Все учетные записи пользователей существуют
    • Все grants перенесены

    Шаг 6: Оптимизация после миграции

    1. Обновите статистику таблиц

    for db in ${DATABASES}; do
      echo "Analyzing tables in ${db}..."
      TABLES=$(kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
        mysql -uroot -p${TARGET_MYSQL_PASSWORD} -N -e "
          SELECT TABLE_NAME FROM information_schema.TABLES
          WHERE TABLE_SCHEMA = '${db}' AND TABLE_TYPE = 'BASE TABLE';
        ")
    
      for table in ${TABLES}; do
        kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
          mysql -uroot -p${TARGET_MYSQL_PASSWORD} ${db} -e "ANALYZE TABLE ${table};" 2>&1 | grep -v "Table"
      done
    done

    2. Проверьте фрагментацию

    # Постройте корректно экранированный список баз данных через запятую
    DB_LIST=$(echo $DATABASES | sed "s/ /','/g")
    DB_LIST="'$DB_LIST'"
    
    kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
      mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "
        SELECT TABLE_SCHEMA, TABLE_NAME,
               ROUND(DATA_FREE / 1024 / 1024, 2) AS 'Fragmentation (MB)'
        FROM information_schema.TABLES
        WHERE TABLE_SCHEMA IN ($DB_LIST)
          AND DATA_FREE > 0
        ORDER BY DATA_FREE DESC;
      "

    Если обнаружена значительная фрагментация (>100MB), перестройте таблицы:

    OPTIMIZE TABLE db1.orders;

    Переключение приложения

    Шаг 7: Переключите приложение на целевой кластер

    1. Убедитесь, что приложение остановлено

    # Убедитесь, что приложение масштабировано вниз
    kubectl scale deployment <app-name> --replicas=0 -n <app-namespace>
    
    # Проверьте отсутствие активных соединений на источнике
    kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
      mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -e "SHOW PROCESSLIST;" | grep -v "Sleep"

    2. Обновите строку подключения приложения

    # Обновите ConfigMap или переменные окружения
    kubectl patch configmap <app-config> -n <app-namespace> --type=json \
      -p='[{"op": "replace", "path": "/data/database-host", "value":"mysql-8-target-read-write.'${TARGET_NAMESPACE}'.svc.cluster.local"}]'
    
    kubectl patch configmap <app-config> -n <app-namespace> --type=json \
      -p='[{"op": "replace", "path": "/data/database-port", "value":"3306"}]'

    3. Перезапустите приложение

    # Масштабируйте приложение вверх
    kubectl scale deployment <app-name> --replicas=<original-replica-count> -n <app-namespace>
    
    # Дождитесь готовности Pod
    kubectl -n <app-namespace> rollout status deployment <app-name>

    4. Проверьте работоспособность приложения

    # Проверьте подключение к базе данных
    kubectl exec <app-pod> -n <app-namespace> -- \
      mysql -h mysql-8-target-read-write.${TARGET_NAMESPACE}.svc.cluster.local \
        -uroot -p${TARGET_MYSQL_PASSWORD} -e "SELECT 1 AS test;"
    
    # Проверьте журналы приложения на наличие ошибок
    kubectl logs -n <app-namespace> <app-pod> --tail=100 | grep -i error

    Мониторинг

    Наблюдайте за перенесенным экземпляром в течение 24-48 часов:

    # Проверьте состояние экземпляра MySQL 8.0
    kubectl -n ${TARGET_NAMESPACE} get mysql ${TARGET_NAME} -w
    
    # Мониторинг журналов ошибок
    kubectl logs -n ${TARGET_NAMESPACE} ${TARGET_NAME}-0 -c mysql --tail=100 -f

    Аварийное восстановление

    План отката

    Если после переключения обнаружены критические проблемы:

    # 1. Остановите приложение
    kubectl scale deployment <app-name> --replicas=0 -n <app-namespace>
    
    # 2. Верните строку подключения на источник
    kubectl patch configmap <app-config> -n <app-namespace> --type=json \
      -p='[{"op": "replace", "path": "/data/database-host", "value":"'${SOURCE_NAME}'-proxysql.'${SOURCE_NAMESPACE}'.svc.cluster.local"}]'
    
    # 3. Перезапустите приложение
    kubectl scale deployment <app-name> --replicas=<original-replica-count> -n <app-namespace>
    
    # 4. Проверьте подключение
    kubectl exec <app-pod> -n <app-namespace> -- \
      mysql -h ${SOURCE_NAME}-proxysql.${SOURCE_NAMESPACE}.svc.cluster.local \
        -uroot -p${SOURCE_MYSQL_PASSWORD} -e "SELECT 1 AS test;"
    WARNING

    Не удаляйте custom resources PXC, пока миграция не будет подтверждена и не завершится окно отката.

    Распространенные проблемы и решения

    Проблема: ошибка GTID_PURGED

    Симптомы:

    ERROR 3546 (HY000) at line XX: Cannot update GTID_PURGED with the Group Replication plugin running

    Решение: уже обработано в процедуре миграции путем фильтрации с помощью grep -v "SET @@GLOBAL.GTID_PURGED"

    Проблема: ошибки преобразования набора символов

    Симптомы:

    ERROR 1366 (HY000): Incorrect string value

    Решение:

    kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
      mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "
        ALTER DATABASE ${db} CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
      "

    Проблема: ошибки привилегий DEFINER

    Симптомы:

    ERROR 1449 (HY000): The user specified as a definer ('user'@'host') does not exist

    Решение:

    # Найдите все объекты с отсутствующими definers
    kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
      mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "
        SELECT DISTINCT DEFINER
        FROM information_schema.VIEWS
        WHERE TABLE_SCHEMA = '${db}';
      "

    Проблема: ошибки плагина аутентификации

    Симптомы:

    ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded

    Решение:

    kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
      mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "
        ALTER USER 'app_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
        FLUSH PRIVILEGES;
      "

    Устранение неполадок

    Диагностические команды

    Проверка хода миграции:

    kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
      mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "SHOW PROCESSLIST;"
    
    kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
      mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -e "SHOW PROCESSLIST;"

    Проверка целостности данных:

    for db in ${DATABASES}; do
      echo "=== Database: ${db} ==="
      kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
        mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -N -e "
          SELECT TABLE_NAME, TABLE_ROWS
          FROM information_schema.TABLES
          WHERE TABLE_SCHEMA = '${db}' AND TABLE_TYPE = 'BASE TABLE'
          ORDER BY TABLE_NAME;
        " > /tmp/source_counts.txt
    
      kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
        mysql -uroot -p${TARGET_MYSQL_PASSWORD} -N -e "
          SELECT TABLE_NAME, TABLE_ROWS
          FROM information_schema.TABLES
          WHERE TABLE_SCHEMA = '${db}' AND TABLE_TYPE = 'BASE TABLE'
          ORDER BY TABLE_NAME;
        " > /tmp/target_counts.txt
    
      diff /tmp/source_counts.txt /tmp/target_counts.txt || echo "Обнаружены различия в количестве строк!"
    done

    Проверка журналов ошибок MySQL 8.0:

    kubectl logs -n ${TARGET_NAMESPACE} ${TARGET_NAME}-0 -c mysql --tail=100 -f | grep -i error

    Рекомендации

    Планирование перед миграцией

    • Тестирование в Staging: всегда сначала выполняйте тестовую миграцию вне production
    • Очистка схемы: исправьте все проблемы совместимости схемы до миграции production
    • Миграция набора символов: переведите на utf8mb4 заранее (за 3-5 дней)
    • Стратегия резервного копирования: убедитесь, что доступны свежие резервные копии
    • Окно обслуживания: запланируйте достаточный простой в зависимости от размера базы данных

    Во время миграции

    • Остановите запись приложения: убедитесь, что во время экспорта/импорта нет записей для обеспечения согласованности
    • Контролируйте ход выполнения: отслеживайте прогресс экспорта/импорта через регулярные интервалы
    • Сохраняйте источник в рабочем состоянии: не удаляйте исходный кластер, пока миграция не будет подтверждена

    После миграции

    • Комплексное тестирование: тщательно проверьте работу приложения
    • Мониторинг производительности: отслеживайте производительность запросов в течение 24-48 часов
    • Сохраняйте источник для отката: держите исходный кластер 24-48 часов на случай отката
    • Обновите документацию: обновите строки подключения и панели мониторинга

    Справочные сведения

    Оценка размера и времени

    Размер базы данныхВремя экспортаВремя импортаОбщее время простоя
    < 10GB1-5 min2-10 min15-30 min
    10-50GB5-20 min10-30 min30-60 min
    50-100GB20-40 min30-60 min1-2 hours
    100-200GB40-80 min1-2 hours2-4 hours

    Справка по флагам mysqldump

    ФлагНазначение
    --single-transactionСогласованный снимок с использованием MVCC (InnoDB)
    --quickПолучать строки по одной (экономия памяти)
    --lock-tables=falseНе блокировать таблицы (использует single-transaction)
    --set-gtid-purged=ONВключить информацию GTID
    --routinesЭкспортировать stored procedures и functions
    --eventsЭкспортировать events
    --triggersЭкспортировать triggers
    --databasesУказать базы данных для экспорта

    Полезные ссылки