• Русский
  • Миграция 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. Проверьте фрагментациюCutover приложенияШаг 7: Переключите приложение на целевой кластер1. Убедитесь, что приложение остановлено2. Обновите строку подключения приложения3. Перезапустите приложение4. Проверьте работоспособность приложенияМониторингАварийное восстановлениеПлан откатаЧастые проблемы и решенияПроблема: ошибка GTID_PURGEDПроблема: ошибки преобразования набора символовПроблема: ошибки привилегии DEFINERПроблема: ошибки authentication pluginУстранение неполадокДиагностические командыРекомендацииПланирование до миграцииВо время миграцииПосле миграцииСправкаОценка размера и времениСправка по флагам mysqldumpПолезные ссылки

    Контекст

    Проблема

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

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

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

    Решение

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

    • Проверенный подход: подтвержден на ACP v4.0+ с использованием Alauda Database Service for MySQL
    • Полное покрытие объектов: мигрируются все стандартные объекты MySQL (tables, views, routines, triggers, events, users, 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 с async replicas)
    Шаблон имени 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 mode (@@gtid_mode = ON, @@enforce_gtid_consistency = ON)
    • Новый кластер MySQL-MGR 8.0, созданный в качестве цели до начала миграции
    • Вместимость хранилища в 2-3 раза больше размера исходной базы данных
    • Сетевое подключение с локальной машины к обоим кластерам

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

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

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

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

    # For PXC 5.7 source
    kubectl get secret <source-name> -n <source-namespace> -o jsonpath='{.data.root}' | base64 -d
    
    # For MGR 8.0 target
    kubectl get secret mgr-<target-name>-password -n <target-namespace> -o jsonpath='{.data.root}' | base64 -d

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

    # Check source PXC pods
    kubectl get pod -n <source-namespace> | grep <source-name>
    # Example output: source-pxc-0, source-pxc-1, source-pxc-2
    
    # Check target MGR pods
    kubectl get pod -n <target-namespace> | grep <target-name>
    # Example output: target-0, target-1, target-2

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

    # Check PXC source status
    kubectl get mysql <source-name> -n <source-namespace>
    # Expected: STATE = ready, PXCSTATE = ready
    
    # Check MGR target status
    kubectl get mysql <target-name> -n <target-namespace>
    # Expected: All 3 members ready, STATUS = Running

    4. Лучшие практики использования kubectl exec

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

    # No container specifier needed for PXC
    kubectl exec <source-name>-pxc-0 -n <namespace> -- \
      mysql -uroot -p<password> -e "SQL_HERE"

    Для MGR 8.0 (цель):

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

    Руководство по выполнению

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

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

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

    # Check for reserved keyword columns
    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');
      "
    
    # Check for ZEROFILL columns
    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%';
      "
    
    # Check for invalid date defaults
    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';
      "

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

    # Fix reserved keyword columns (example)
    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;
      "
    
    # Fix ZEROFILL columns
    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

    # Convert databases to 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
    
    # Convert tables to 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 characters) может потребоваться скорректировать длину индексов:

    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 незадолго до этапа миграции данных.

    Через Web Console:

    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: 1
        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
        crVersion: 4.2.0
      version: "8.0"
    EOF

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

    kubectl -n $NAMESPACE get mysql $TARGET_NAME -w
    # Expected: STATE = Ready, MGRSTATE = ready

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

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

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

    Процедура:

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

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

      # List user databases (DO NOT include: 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}..."
      
        # Export from PXC source
        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. Перенесите пользователей и привилегии:

      # List non-system users from PXC source
      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';
        ")
      
      # For each user, create user and apply grants on target
      for user_host in ${USERS}; do
        echo "Migrating user: ${user_host}..."
      
        # Get CREATE USER statement (includes auth plugin and password hash)
        CREATEUSER=$(kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
          mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -N -e "SHOW CREATE USER ${user_host};")
      
        # Create user on target
        kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
          mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "${CREATEUSER};"
      
        # Get GRANT statements from source
        GRANTS=$(kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
          mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -N -e "SHOW GRANTS FOR ${user_host};")
      
        # Apply grants on target
        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
      
      # Flush privileges on target
      kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
        mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "FLUSH PRIVILEGES;"
      TIP

      На целевом MySQL 8.0 SHOW CREATE USER сохраняет исходный authentication plugin и хэш пароля, поэтому пользователи смогут входить в систему со своими существующими паролями после миграции. Если вам нужно переключиться на 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>';
        "
      Целевой MySQL 8.4

      На целевом MySQL 8.4 plugin mysql_native_password не загружается по умолчанию и не может быть включен, поэтому повторное применение определения SHOW CREATE USER из 5.7/8.0 (которое использует mysql_native_password) завершается ошибкой ERROR 1524 (HY000): Plugin 'mysql_native_password' is not loaded. Для цели на 8.4 создавайте каждого пользователя заново с plugin по умолчанию caching_sha2_password вместо сохранения исходного хэша:

      kubectl exec ${TARGET_NAME}-0 -n ${TARGET_NAMESPACE} -c mysql -- \
        mysql -uroot -p${TARGET_MYSQL_PASSWORD} -e "
          CREATE USER ${user_host} IDENTIFIED BY '<password>';
        "
      # then re-apply the user's GRANTs (collected above)

      Для этого необходимо знать пароль каждого пользователя или сбросить его — хэш mysql_native_password нельзя перенести в caching_sha2_password. Убедитесь, что application drivers/connection strings поддерживают caching_sha2_password.

    TIP

    Указанный выше подход со streaming mysqldump не требует дискового пространства для dump-файлов.

    Шаг 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} ==="
    
      # Compare table counts
      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';"
    
      # Verify views execute correctly
      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

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

    • Одинаковое количество таблиц в каждой базе данных
    • Одинаковое количество строк в каждой таблице
    • Одинаковое количество views
    • Все views успешно выполняются
    • Все 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. Проверьте фрагментацию

    # Build properly-quoted comma-separated list
    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;

    Cutover приложения

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

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

    # Ensure application is scaled down
    kubectl scale deployment <app-name> --replicas=0 -n <app-namespace>
    
    # Verify no active connections on source
    kubectl exec ${SOURCE_NAME}-pxc-0 -n ${SOURCE_NAMESPACE} -- \
      mysql -uroot -p${SOURCE_MYSQL_PASSWORD} -e "SHOW PROCESSLIST;" | grep -v "Sleep"

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

    # Update ConfigMap or environment variables
    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. Перезапустите приложение

    # Scale up application
    kubectl scale deployment <app-name> --replicas=<original-replica-count> -n <app-namespace>
    
    # Wait for pods to be ready
    kubectl -n <app-namespace> rollout status deployment <app-name>

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

    # Test database connectivity
    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;"
    
    # Check application logs for errors
    kubectl logs -n <app-namespace> <app-pod> --tail=100 | grep -i error

    Мониторинг

    Отслеживайте мигрированный экземпляр в течение 24-48 часов:

    # Check MySQL 8.0 instance health
    kubectl -n ${TARGET_NAMESPACE} get mysql ${TARGET_NAME} -w
    
    # Monitor error logs
    kubectl logs -n ${TARGET_NAMESPACE} ${TARGET_NAME}-0 -c mysql --tail=100 -f

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

    План отката

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

    # 1. Stop application
    kubectl scale deployment <app-name> --replicas=0 -n <app-namespace>
    
    # 2. Update connection string back to source
    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. Restart application
    kubectl scale deployment <app-name> --replicas=<original-replica-count> -n <app-namespace>
    
    # 4. Verify connectivity
    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

    Решение:

    # Find all objects with missing 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}';
      "

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

    Симптомы:

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

    Решение (цель MySQL 8.0): переключите пользователя на mysql_native_password для более старых клиентов, которые не могут согласовать caching_sha2_password:

    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;
      "

    Решение (цель MySQL 8.4): mysql_native_password недоступен в 8.4 (ERROR 1524: Plugin 'mysql_native_password' is not loaded), поэтому использовать его как резервный вариант нельзя. Вместо этого обновите client driver/connector до версии, поддерживающей caching_sha2_password (и используйте TLS, который требуется caching_sha2_password для первоначального обмена паролем при подключении не с локального хоста). Оставьте пользователя на plugin по умолчанию caching_sha2_password.

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

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

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

    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 "Row count differences detected!"
    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 дней до миграции)
    • Стратегия резервного копирования: убедитесь, что доступны свежие резервные копии
    • Окно обслуживания: запланируйте достаточное время простоя в зависимости от размера базы данных

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

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

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

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

    Справка

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

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

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