升级 MySQL

升级 MySQL

这里以 MySQL 5.7.33 版本升级到 8.0.23 版本为例,版本类型选择二进制版本,操作系统使用 Linux。

必知事项

建议

  • 升级之前必须进行备份,且备份应包含 mysql 库
  • 升级后需要重新安装 MySQL 语言接口

升级路径

  • 从 5.6 升级到 5.7,建议先升级到最新版本,然后再升级到下一版本
  • 不支持跳版本升级,例如,从 5.5 升级到 5.7
  • 支持在发行系列中进行升级和跳版本升级,例如,从 5.7.x 升级到 5.7.y,从 5.7.x 升级到 5.7.z

了解目标版本的变化

MySQL 8.0 版本相对于 5.7 版本的变化还是很大的,建议仔细查看官方文档。

升级前的准备

官方文档中列出了详细的检查事项,同时提供了一个官方的升级检查器。

检查事项

具体请查看 官方文档:https://dev.mysql.com/doc/refman/8.0/en/upgrade-prerequisites.html

升级检查器

MySQL Shell 用来检查服务器实例的兼容性错误和升级问题。最低只支持检查 5.7 版本实例,且必须是 GA 发行版。

也可以检查配置文件中已定义,但在目标版本中已删除的系统变量,以及未在配置文件中定义,但是在目标版本中有默认值的系统变量。

如果要检查配置文件, 需要提供配置文件路径。

  • 安装
    • 下载

      下载地址:https://dev.mysql.com/downloads/shell/

      wget https://dev.mysql.com/get/Downloads/MySQL-Shell/mysql-shell-8.0.23-linux-glibc2.12-x86-64bit.tar.gz
      
    • 解压
      tar -xvf mysql-shell-8.0.23-linux-glibc2.12-x86-64bit.tar.gz -C /opt/
      
    • 创建软链接
      ln -s /opt/mysql-shell-8.0.23-linux-glibc2.12-x86-64bit /opt/mysqlsh
      
    • 添加环境变量
      [root@yingzai ~]# vim /etc/profile
      ...
      MYSQLSH_HOME=/opt/mysqlsh
      export PATH=PATH:MYSQLSH_HOME/bin
      ...
      [root@yingzai ~]# source /etc/profile
      
    • 验证
      [root@yingzai ~]# mysqlsh
      MySQL Shell 8.0.23
      ...
      Type '\help' or '\?' for help; '\quit' to exit.
       MySQL  JS > 
      
  • 语法
    util.checkForServerUpgrade([connectionData][, options])
    
    • 参数

      这两个参数都是可选的。

      • ConnectionData
        • 提供连接数据
      • options
        • 选项字典,用来指定选项
    • 选项

      这里的选项不全,完整的选项列表请查看官方文档。

      • password
        • 密码
      • targetVersion
        • 计划升级到的目标版本,最好指定完整版本号
      • configPath
        • 配置文件路径
      • outputFormat
        • 输出格式,包括 TEXT (默认) 、JSON (易于解析和处理)
    • 查看
      • 帮助
        mysqlsh> util.help("checkForServerUpgrade")
        
      • 当前实例状态
         MySQL  JS > \status
        MySQL Shell version 8.0.23
        
        Not Connected.
        
  • 使用

    MySQL Shell 支持两种查询方式,既可以登录到 mysqlsh 内部调用函数 util.checkForServerUpgrade(),也可以直接在命令行启动。

    • 登录后调用函数
       MySQL  JS > util.checkForServerUpgrade('172.16.0.30:3306', {"password":"root", "targetVersion":"8.0.23", "outputFormat":"JSON", "configPath":"/mdata/3306/my.cnf"})
      {
          "serverAddress": "172.16.0.30:3306",
          "serverVersion": "5.7.32-log - MySQL Community Server (GPL)",
          "targetVersion": "8.0.23",
          "errorCount": 0,
          "warningCount": 24,
          "noticeCount": 1,
          "summary": "No fatal errors were found that would prevent an upgrade, but some potential issues were detected. Please ensure that the reported issues are not significant before upgrading."
      ...
      
    • 命令行启动

      支持 TCP/IP 和 socket 两种连接方式。

      • TCP/IP 方式
        mysqlsh -- util checkForServerUpgrade root@'172.16.0.30':3306 --target-version=8.0.23 --output-format=JSON --config-path=/mdata/3306/my.cnf
        mysqlsh -- util check-for-server-upgrade { --user=root --host='172.16.0.30' --port=3306 } --target-version=8.0.23 --output-format=JSON --config-path=/mdata/3306/my.cnf
        
      • socket 方式
        mysqlsh --socket=/mdata/3306/mysql.sock --user=root -e "util.checkForServerUpgrade()"
        

升级方式

原地升级

  • 检查未提交的 XA 事务
    mysql> XA recover;
    

    Note: 如果返回结果,结束事务。

    XA COMMIT xid [ONE PHASE]
    XA ROLLBACK xid
    
  • 如果存在加密的 InnoDB 表空间
    mysql> ALTER INSTANCE ROTATE INNODB MASTER KEY;
    
  • 缓慢关闭服务

    缓慢关闭时,InnoDB 会在关闭前执行完全清除和更改缓冲区合并,为版本中的文件格式差异做准备。

    -- 5.7 版本
    mysql> SET GLOBAL innodb_fast_shutdown = 0;
    
    -- 8.0 版本,快速/缓慢关闭都可以
    mysql> SET GLOBAL innodb_fast_shutdown = 1; -- fast shutdown
    or
    mysql> SET GLOBAL innodb_fast_shutdown = 0; -- slow shutdown
    

    Note: 5.7 版本升级到 8.0 版本,建议缓慢关闭。

    • innodb_fast_shutdown={0|1|2}
      • 0:缓慢关闭
      • 1:快速关闭
      • 2:冷关闭
  • 关闭服务
    shell> mysqladmin -uroot -p -S /mdata/3306/mysql.sock shutdown
    
  • 升级软件版本

    将新的安装包解压到安装目录,创建软链接,修改环境变量。

  • 使用原有数据目录启动服务

    shell> mysqld_safe --user=mysql --datadir=/mdata/3306/data &
    

    Note: 8.0 版本,如果有加密的 InnoDB 表空间,需要使用 –early-plugin-load 选项加载 keyring 插件。启动过程中会自动升级数据字典等信息。

  • 运行 mysql_upgrade

    mysql_upgrade 检查所有表与当前版本的兼容性,并升级 mysql 库。但是,不会升级时区表和帮助表。

    shell> mysql_upgrade -uroot -p
    

    Note: 从 8.0.16 版本开始,这一步已经废弃了,原先这一步所做的操作在上一步已经自动完成。

  • 重启服务

    shell> mysqladmin -uroot -p -S /tmp/mysql.sock shutdown
    shell> mysqld_safe --defaults-file=/mdata/3306/my.cnf &
    

    Note: 因为上一步启动时未指定 socket 文件,所以使用了默认的 /tmp/mysql.sock 。如果后续重启失败,很可能是因为配置文件中使用了已废弃的变量,需要排查错误日志。

  • 登录验证

    shell> mysql -uroot -p -S /mdata/3306/mysql.sock
    

    Note: 实际生产中,验证的过程比较复杂,需要对库表、数据以及应用程序做多方面的验证。

逻辑升级

逻辑升级是指利用备份工具 mysqldump 或 mysqlpump 导出备份,然后恢复到新服务器的方法,类似数据迁移。

  • 备份
    shell> mysqldump -u root -p -S /mdata/3306/mysql.sock --add-drop-table -R --events -A \
    --ignore-table=mysql.innodb_index_stats \
    --ignore-table=mysql.innodb_table_stats --force > /tmp/full.sql
    

    Note: 如果备份文件包含系统表,则不建议在服务器上启用 GTID。

  • 关闭服务

    shell> mysqladmin -uroot -p -S /mdata/3306/mysql.sock shutdown
    
  • 部署新的实例
    • 安装新的版本

      略。

    • 初始化新的数据目录

      shell> mysqld --initialize --user=mysql --basedir=/opt/mysql --datadir=/mdata/3306/data
      
    • 启动服务
      shell> mysqld_safe --user=mysql --datadir=/path/to/5.7-datadir &
      
    • 重置密码
      mysql> ALTER USER USER() IDENTIFIED BY 'your new password';
      
  • 恢复数据

    “`shell
    shell> mysql -u root -p -S /tmp/mysql.sock –force mysql_upgrade -uroot -p -S /tmp/mysql.sock
    shell> mysqladmin -u root -p -S /tmp/mysql.sock shutdown
    shell> mysqld_safe –user=mysql –datadir=/mdata/data &
    “`

    • 8.0.16 版本之后
      shell> mysqladmin -u root -p -S /tmp/mysql.sock shutdown
      shell> mysqld_safe --user=mysql --datadir=/mdata/data --upgrade=FORCE &
      

      Note: 从 8.0.16 版本开始,mysql_upgrade 已经废弃。改为 mysqld 程序搭配 --upgrade 选项,用来处理升级过程。

  • 登录验证

    shell> mysql -uroot -p -S /tmp/mysql.sock
    

    Note: 实际生产中,验证的过程比较复杂,需要对库表、数据以及应用程序做多方面的验证。

  • 删除多余表

    mysql> DROP TABLE mysql.event;
    mysql> DROP TABLE mysql.proc;
    

    Note: MySQL 8.0 版本加载 5.7 版本的 dump 备份文件时,会重新创建两个不再使用的表:event 和 proc,升级完毕后需要删除。

错误汇总

权限错误和主键冲突

  • 错误场景

    • MySQL 5.7 版本升级到 8.0 版本,使用逻辑升级,在恢复时,报权限错误和主键冲突
  • 报错信息
    [root@yingzai tmp]$ mysql -u root -proot -S /tmp/mysql.sock --force < /tmp/full_gtid.sql
    mysql: [Warning] Using a password on the command line interface can be insecure.
    ERROR 3554 (HY000) at line 318: Access to system table 'mysql.innodb_index_stats' is rejected.
    ERROR 3554 (HY000) at line 321: Access to system table 'mysql.innodb_index_stats' is rejected.
    ERROR 3554 (HY000) at line 338: Access to system table 'mysql.innodb_index_stats' is rejected.
    ERROR 1062 (23000) at line 340: Duplicate entry 'mysql-gtid_executed-PRIMARY-n_diff_pfx01' for key 'innodb_index_stats.PRIMARY'
    ERROR 3554 (HY000) at line 348: Access to system table 'mysql.innodb_table_stats' is rejected.
    ERROR 3554 (HY000) at line 351: Access to system table 'mysql.innodb_table_stats' is rejected.
    ERROR 3554 (HY000) at line 366: Access to system table 'mysql.innodb_table_stats' is rejected.
    ERROR 1062 (23000) at line 368: Duplicate entry 'mysql-gtid_executed' for key 'innodb_table_stats.PRIMARY'
    
  • 报错原因
    • 具体的原因网上也没有一个准确的说法,只能归结于 8.0 版本系统表和 5.7 版本系统的差异性。因为 8.0 之前的版本,mysql 系统表使用 MyISAM 存储引擎。
  • 解决方法
    • 可以在备份时,使用 --ignore-tables 选项,跳过这两个报错的表

1条评论

  1. 这里有一处显示格式的错误,不是 Markdown 语法的问题,而是 WordPress 的插件导致的,这个插件对 Markdown 语法的识别有误,导致部分格式没有正确显示。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注