游戏数据库版本更新神器Flyway

项目实战

本文主要介绍的是 mysql 数据库使用 flyway 的实战经验;

程序操作指引

操作指引

1)将DB的sql文件与服务端版本文件一起提交,并严格遵守上述的目录结构和sql文件名规范要求;
2)sql文件内容中不需要用use语句指定数据库;
3)sql文件内容采用增量修改的方式提交,尽量不要有drop table再create table的语句,避免误删数据(除了非常确定该表中的数据无用!);
4)如果提交到svn中的sql文件已经被更新到了任一个游戏服,此sql文件不可再修改或删除;
5)sql文件内容,事务数量越小越好,避免sql执行部分失败后,需要回滚相关操作;

注意事项

#重要的事情说三遍
一般情况下:
只增量添加sql文件,不要删除和修改!
只增量添加sql文件,不要删除和修改!!
只增量添加sql文件,不要删除和修改!!!

只有一种例外情况可以删除或修改一个已经提交到svn的sql文件:该sql文件提交到svn之后尚未更新到任何游戏服,因为按照Flyway的更新逻辑,DB更新是以sql文件为粒度的,在DB更新之前的sql内容修改是没有关系的;但是如果一个sql文件已经更新到某个服务器,再去修改它,那么再次修改的内容将不会在该服务器上被执行。

SRE 操作指引

Flyway 安装部署

官方文档:https://flywaydb.org/documentation/commandline/#download-and-installation

version=5.2.4  #  可以在 Flyway 官网查看最新的版本号,此处以当前(2019.06.06)的最新版本为例。
cd /home/xxxx
wget -qO- https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/${version}/flyway-commandline-${version}-linux-x64.tar.gz | tar xvz
sudo ln -s `pwd`/flyway-${version}/flyway /usr/local/bin

Flyway 的默认配置文件:

vim flyway-${version}/conf/flyway.conf
flyway.url=jdbc:mysql://host:port/dbname?useSSL=false
flyway.user=xxxxx
flyway.password=xxxxxxxxx

Flyway 执行可以使用以下两种方式:

1)直接在 flyway 命令行中直接加上参数,无需配置文件;

2)在配置文件中指定好默认的配置,无需参数;

Flyway 更新 DB 指令

方法一:指定 schemas 来更新。Flyway 从默认目录 flyway-version/sql/{database}) 来读取 sql 文件

#  同步 sql 版本文件到 Flyway 默认 sql 目录
rsync -azL --delete ${updating_dir}/ /home/${project_user}/flyway/sql/${database}/

#  执行 migrate 指令
flyway -baselineOnMigrate=true -baselineVersion=0 -schemas="${database}" -user="${user}" -password="${password}" -url="jdbc:mysql://${host}" migrate

方法二:直接指定 sql 目录来更新。直接指定 locations 参数【推荐】

#  在参数中指定 sql 文件的位置,直接执行 migrate 指令
flyway -baselineOnMigrate=true -baselineVersion=0 -user="${user}" -password="${password}" -url="jdbc:mysql://${host}" -schemas=${database} -locations=filesystem:/home/xxx/server/database/htdocs_local/db/alter/stg/ migrate

备注:两者并无本质差异,推荐使用方法二直接参数中指定 locations 的方式,少了一步 rsync,减少出错概率。

参数说明:

1、-baselineOnMigrate=true :表示如果当前DB未使用Flyway的话,以当前DB版本为基线版本
2、-baselineVersion=0:指定基线的版本,第一次使用 flyway 的时候指定为0,之后可以指定为当前版本,当前版本参考 flyway_schema_history 中的记录。
3、-schemas:数据库名
4、-locations:sql文件目录
5、migrate:对DB进行migrate更新
6、-user -password -url:用户名、密码和数据库访问地址信息

更新流程

1、程序按照Flyway规范提交新版本的sql文件;
2、提交阿拉丁流程来更新DB;
3、DB Client机器上备份数据库;
4、DB Client机器上下载新版本的sql文件;
5、执行Flyway进行DB更新;
6、如有报错,则进行排查并修复后重新更新;

问题排查

sql 文件的 checksum 不一致

原因:sql 文件被更新之后,文件内容进行了变更,再次执行更新会有这个报错 ;

解决方法:执行 flyway repair;

flyway -baselineOnMigrate=true -baselineVersion=0 -user="${user}" -password="${password}" -url="jdbc:mysql://${host}" -schemas=${database} repair

sql 文件描述不一致

原因:sql 文件被更新之后,文件名有变更 ;

解决方法:修改 flyway_schema_history 表中该 sql 文件对应的 description 字段 ;

Migration V6.7__xxx_xxx.sql failed

原因:sql 文件内容执行失败 ;

解决方法:根据 Flyway 输出的 Error Message 进行对应处理即可 ;

#注意:
1)如果对这个sql回滚,然后修改后重新提交的话,需要删除flyway_schema_history表中的该行记录;
2)如果修改内容后重新执行的话,需要执行repair指令修复下checksum;
3)如果手动执行完毕该sql内容的话,需要在对应的flyway_schema_history表中将该行的success字段改为true;

Validate failed: Detected failed migration to version 6.7

原因:该 sql 文件之前已经更新过,但是执行失败了 ;

解决方法:灵活处理 flyway_schema_history 表 ;

#注意:
1)如果对这个sql回滚,然后修改后重新提交的话,需要删除flyway_schema_history表中的该行记录;
2)如果手动执行完毕该sql内容的话,需要在对应的flyway_schema_history表中将该行的success字段改为true;

Validate failed: Detected resolved migration not applied to database: 2.7

原因:该版本的 sql 之前已经通过 Flyway migrate 更新过,但是新版本中该文件被删除了,导致验证不通过;

解决方法:flyway_schema_history 将该记录删除,或者在 flyway 命令中加上跳过这个验证的参数:-ignoreMissingMigrations=true;

WARNING: DB: Duplicate index ‘idx_flyway_a_index’ defined on the table ‘sbtest.sbtest1’. This is deprecated and will be disallowed in a future release. (SQL State: HY000 – Error Code: 1831)

原因:理由不明,索引是正确添加的,但是会有 WARNING;

解决方法:不用处理 , 可以忽略;

总结

规范化管理业务变更一直是 sre 工作目标,数据库做为业务的核心,业务 sre 理应管控全局,对其进行规范化的管理,避免各种误操作带来的问题或故障。多个项目数据库更新使用 flyway 后,传统数据库更新带来的痛点不会再变为 sre 的负担,而且能够高质高效的完成每一次变更。