乐趣区

关于mysql:在Rainbond中实现数据库结构自动化升级

Rainbond 这款产品始终致力于买通企业应用交付的全流程,这个流程中不可或缺的一环是企业应用的一直降级、迭代。Rainbond 特有的能力,是能够将囊括多个服务组件的企业应用零碎进行打包,并执行一键装置、降级以及回滚的操作。上述的内容仅仅解决了应用程序自身的版本控制问题。企业应用的降级迭代流程想要齐全实现自动化,还须要可能主动解决数据库表构造(Schema)的版本控制。通过一直的摸索,Rainbond 首先在源码构建畛域借助业界当先的 Liquibase 集成了云原生时代的数据库 Schema 版本治理的能力。

Schema 版本治理难题

数据库表构造(Schema)定义了数据表(Table)的名字,以及每一个数据表中所蕴含的数据列(Column)的名字、属性等信息。它形容了一个数据库所领有的框架,记录在数据库中的数据都须要遵循 Schema 里的定义。

区别于应用程序本身的降级,Schema 版本治理问题,实质上是一种长久化数据的降级,这一特色随同着两个疑难:

  • 长久化数据如何降级:云原生时代的交付,曾经无奈跳脱出容器化、平台化的特色。各大云原生平台在进行软件交付过程中,都不会轻易将长久化数据纳入版本控制体系中去。起因很简略,每个交付环境中的数据都是不同的,降级过程中很难抉择长久化数据的对立版本治理计划。
  • 哪些长久化数据须要降级:既然难以抉择长久化数据的对立版本治理计划,那么退而求其次,是否能够优先选择必要的长久化数据进行版本治理。放大范畴之后,就突出了数据库表构造这一非凡长久化数据类型。其版本治理的必要性是不言而喻的,应用程序自身从 V1 版本升级到了 V2 版本,那么对应的数据库表构造也须要减少必要的新表、新列。

这两个疑难引出了本文的宗旨:在企业级软件交付畛域, 如何正当的在每次降级的过程中解决数据库表构造(Schema)的版本控制?

传统软件交付畛域,在 Schema 版本治理方面有两种支流的解决方案:

  • 人工解决:这是最根底的 Schema 版本治理形式。现场交付人员不仅须要解决应用程序的降级流程,也间接操作数据库,实现 Schema 的降级。这种办法最间接,然而无奈自动化解决的流程都具备一些通病:低效、易错。
  • 代码解决:这是一种进阶的形式。通过在应用程序外部引入第三方库,来进行 Schema 的版本治理。这一操作曾经能够罢黜交付现场的人工解决流程,交付人员只须要将应用程序进行更新,程序自身会连贯到数据库,对 Schema 作出自动化的变更。这种形式的自动化水平曾经能够满足要求,然而也具备引入第三方库的通病:技术老本晋升、侵入性、与语言或框架绑定。

云原生时代的解决思路

云原生时代,应用程序的使用者、交付者都心愿通过所选用的平台来赋能本人的应用程序。在本文探讨的畛域中,这种期待能够具体的形容为:借助平台能力,以无侵入的形式,将 Schema 版本治理能力赋予利用,使得利用在进行一键降级时,Schema 也主动实现降级。

Rainbond 作为一款云原生利用治理平台,也在一直摸索为利用赋能之道。在 Schema 版本治理畛域,实现了在源码构建过程中集成 Schema 版本治理的能力。利用自身不须要改变任何代码,仅仅须要将两种类型的文件放进代码根目录下的指定目录下即可。这两种文件别离是:定义了数据库实例连贯地址的配置文件,降级 Schema 所应用的 Sql 脚本文件。

对于源码构建

源码构建性能,自身就是一种 Rainbond 对利用的赋能。云原生时代,利用都在向容器化的方向迈进。容器化的过程中看似无奈罢黜 Dockerfile 的编写,实则不然。源码构建性能能够间接对接源代码,将其编译成为可运行的容器镜像。整个过程不须要开发人员的染指,提供代码仓库地址即可,极大的升高了开发人员的技术累赘。

在源码构建的流程中,以无侵入的形式集成了很多能力。比方通过纳入 Pinpoint-agent 的形式集成 APM 能力。再比方通过纳入 jmx-exporter 的形式集成自定义业务监控能力。明天重点形容的,是通过纳入 Liquibase 的形式,集成 Schema 版本控制能力。

对于 Liquibase

Liquibase 是一款专门用于数据库表构造版本控制的 CI/CD 工具。从 2006 年开始,Liquibase 团队始终致力于让数据库变更治理更简略,尤其是在麻利软件开发畛域。这一工具基于 Apache 2.0 协定开源。

通过长期的迭代,Liquibase 曾经十分成熟牢靠,通过 sql、yaml、xml、json 在内的多种文件格式,开发人员能够疾速的定义出合乎 Liquibase 格调的数据库表构造变更文件,这种文件被称之为 changelog。基于 changelog 中的定义,Liquibase 能够十分不便的在多个变更操作版本之间降级与回滚。

Liquibase 提供多种形式供开发人员交互,包含一种通用的命令行操作模式,源码构建通过命令行模式集成 Liquibase 的 Schema 版本治理能力。

代码定义的 Schema 版本控制能力

Rainbond 源码构建推崇代码定义各种能力。对于 Schema 版本控制能力而言,也是通过代码仓库中的指定文件来定义的,咱们能够简要的称之为 Schema As Code,这种代码定义能力的实际,要求每一次 CI 工作都由一个代码仓库地址开始,比方 Git。对于每一个数据库实例来说,通过指定目录下的配置文件和 changelog 来定义数据库表构造版本。默认状况下,是指代码根目录下的 Schema 目录。

上面是一个代码构造示例,Rainbond 官网同时提供了一份残缺的代码示例 java-maven-demo :

.
├── Procfile
├── README.md
├── Schema
│   ├── changelog.sql       # 定义数据库表构造
│   └── mysql.properties    # 定义数据库实例连贯信息
├── pom.xml
└── src

Schema 目录下的 mysql.propertieschanglog.sql 文件定义了如何进行 Schema 版本控制。

mysql.properties 定义了数据库实例的连贯形式,以及所援用的 changelog 文件地址。

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?createDatabaseIfNotExist=true&characterEncoding=utf8
username=${MYSQL_USER}
password=${MYSQL_PASSWORD}
changeLogFile=changelog.sql

最简化定义项包含:

  • driver:指定应用的 jdbc 驱动,源码构建中集成的驱动反对 mysql、mariadb、mssql、mongo、postgresql、sqlite 等常见类型数据库。
  • url:定义数据库连贯地址,能够通过 jdbc 的规范写法来预创数据库实例。
  • username&password:定义数据库实例的登录凭据。
  • changeLogFile:定义该数据库实例表构造变更文件的门路。

源码构建过程中,会遍历辨认 Schema 目录下的所有 properties 文件,并在启动时解决每一个数据库实例的 Schema 版本控制流程。通过配置文件的组合,在以下各种常见场景中都能够很好的工作。

  • 单个数据库实例
  • 多个雷同类型数据库实例,比方利用同时连贯了多个 mysql
  • 多个不同类型数据库实例,比方利用同时连贯了 mysql、mongo
  • 同个数据库中的多个数据库实例,比方利用同时应用同个 mysql 中的多个库实例

changlog 的最佳实际

changelog 文件,是治理 Schema 的关键所在。以下是一个示例:

-- liquibase formatted sql
-- changeset guox.goodrain:1
create table person (
id int primary key,
name varchar(50) not null,
address1 varchar(50),
address2 varchar(50),
city varchar(30)
);
-- rollback drop table person;
-- changeset guox.goodrain:2
create table company (
id int primary key,
name varchar(50) not null,
address1 varchar(50),
address2 varchar(50),
city varchar(30)
);
-- rollback drop table company;

举荐应用 sql 类型的 changelog 文件来定义 Schema 版本,因为这最合乎开发人员的习惯。

changlog 文件通过正文来定义一些行为。常见如下:

# 定义 changelog 文件的格局,这是每一个 changelog 文件的结尾项
-- liquibase formatted sql 
# 定义变更集,前面追随的,是开发人员姓名,以及变更集的序号,这个序号很重要,倡议应用有序数字来定义
-- changeset guox.goodrain:1
# 定义回滚操作,每一个变更集都应该定义与之对应的回滚操作,这使得在变更呈现问题时,疾速回滚到指定版本的变更集
-- rollback drop table staff;

Liquibase 官网提出了一系列的最佳实际,有一些最佳实际应该作为开发人员的默认行为。

  • 每个变更集仅蕴含一个变更,通过细化数据库表构造的变更版本,这能够避免失败的主动提交语句使数据库处于意外状态。
  • changeset 的 ID,抉择有序且举世无双的数列,或者对开发者敌对的名字。
  • 让版本永远可回滚,为每一个 changeset 设置正当的回滚操作。

有对于 mysql.propertieschanglog.sql 文件的写法,更多的个性请参考 liquibase 文档,这些个性都能够被源码构建所继承。

Schema 生命周期流程

1. 构建流程

执行失常的源码构建流程时,会自动识别代码根目录下的 Schema 目录,筹备 Schema 版本管理所须要的根底环境,包含 jre 和 Liquibase 工具包。

构建日志会有以下提醒:

2. 启动流程

实现构建流程后,服务组件会主动进入启动过程中,Rainbond 平台会依据代码中定义好的配置文件,针对每一个数据库实例,进行主动降级解决。

处理过程中,在服务组件的日志中的头部地位,会打印相干的记录:

上图中演示了针对同一个 mysql 数据库中的多个库实例进行表构造的降级操作。对于空的库实例而言,这也相当于一次初始化的操作。

在示例中,Rainbond 别离向利用所连贯的同个 mysql 数据库中的两个库实例(别离名为 Initialize anotherdb)进行了表构造初始化操作,别离创立了表 companyperson 以及 another_companyanother_person。在数据库组件的 Web 终端登录后,能够验证:

3. 公布到组件库

Rainbond 特有的公布机制,能够将业务组件和数据库组件对立公布为一个利用模版。不便在不同的环境中一键装置交付。通过利用模版交付的利用,仍然具备 Schema 版本控制的能力。全新装置的利用模版,其数据库也会被初始化为上述状态。在这里,咱们称公布的利用为源利用,由利用模版装置而来的利用为已交付利用。

4. 代码更新

当开发人员继续迭代业务零碎的时候,Schema 也随之改变,假设新版本的业务零碎,要求 Initialize 新增表 staff,并为已有的 person 表增加一个新的列 country。那么开发人员应该为对应的 changelog.sql 文件新增以下内容,并和新的业务代码一并提交,保障业务代码和 Schema 保持一致。

-- changeset other.goodrain:3
alter table person add column country varchar(2);
create table staff (
id int primary key,
name varchar(50) not null,
address1 varchar(50),
address2 varchar(50),
city varchar(30)
);
-- rollback drop table staff;
-- rollback alter table person drop column country;

在源利用处点击构建,Rainbond 会拉取最新的代码,更新业务利用的同时,为 Schema 进行降级。

构建过程中没有任何变动,然而在启动过程中,针对更新的 Initialize 和保持原状的 anotherdb 库实例,Rainbond 给出两种不同的解决:

5. 基于利用模版的降级

源利用有了新的版本,已交付利用也应随之有变更。首先,利用模版须要有一个更新的版本,反复公布流程,定义更高的版本号即可。已交付利用能够依据 Rainbond 的提醒,一键降级到更新后的版本。

6. 验证

登录已交付利用的数据库组件中,能够查看对应的 Schema 变动。

7. 回滚

数据库表构造的回滚操作是一个很庄重的问题。本着数据库表构造只增不减的准则,曾经失效的 Schema 不会随着已交付利用的一键回滚而有任何变动。如果肯定要进行回滚,则须要运维人员登录业务组件的 Web 终端手动操作。

须要留神的是回滚的程序:数据库表构造应该先于应用程序回滚。这是因为一旦应用程序回滚实现,changlog 文件自身也回滚到了上个版本,无奈再进行数据库表构造的回滚。

执行以下命令,能够依据指定的配置文件,对数据库表构造进行回滚操作,回滚幅度以 1 个 changeset 为单位。

cd Schema/
liquibase rollbackCount 1 --defaults-file=mysql.properties

鉴于回滚后的业务组件一旦重启或更新,就会比对 changelog 文件后从新降级 Schema,所以在执行回滚操作后,务必增加环境变量 ALLOW_SCHEMA_UPDATE=false 来禁用 Schema 版本管理控制性能,直到新版本利用模版的降级。

常见问题

  1. 如何在 *.properties 配置文件中正当的定义所有数据库实例的连贯地址和凭据?

应用环境变量来代替 *.properties 配置文件中的数据路实例连贯地址和凭据信息,定义形式详见文中的示例。Rainbond 源码构建过程中,会拾取运行环境中的所有环境变量,对指标配置文件进行渲染,所以对于环境变量的命名并不重要,只须要保障定义的环境变量会在最终交付环境中生成即可。无论环境变量来自于自定义的环境配置还是 Rainbond 独有的连贯信息机制。

  1. 执行回滚操作失败?

回滚如何操作,定义在 changlog 文件中。务必保障每一个 changeset 都有对应的回滚策略,方可保障每次回滚都失去正确的后果。

  1. 执行 Schema 降级的过程中报错:!! Failed to check the database status. Check /app/Schema/xxx.properties.log

每一次执行 Schema 变更的过程中,都会先进行查看,包含数据库实例地址的连通性、changelog 文件的可执行性。如果查看不通过,则不会对数据库作出任何操作,然而查看的后果会记录在日志文件中,能够登录 Web 终端,查看提醒中的日志文件内容。

  1. 老用户如何获取 Schema 版本控制性能?

这一性能和 Rainbond 的版本脱离,所以老用户能够通过更新源码构建相干组件来获取这一能力。执行以下一组命令即可:

# 以下命令在 Rainbond 集群内任意节点执行;如果你应用 dind-allinone 版本,则应该在 rainbond-allinone 容器中执行
hubpassword=$(kubectl get rainbondcluster -o yaml -n rbd-system | grep password | awk '{print $2}')
docker login --username=admin --password=${hubpassword} goodrain.me
images=(builder runner)
for image in ${images[@]}
  do
    docker pull registry.cn-hangzhou.aliyuncs.com/goodrain/${image}:v5.5.0-release
    docker tag registry.cn-hangzhou.aliyuncs.com/goodrain/${image}:v5.5.0-release goodrain.me/${image}
    docker push goodrain.me/${image}
  done

References Link

Liquibase https://www.liquibase.com

java-maven-demo https://gitee.com/rainbond/ja…

对于 Rainbond

Rainbond 是一个开源的云原生利用治理平台,应用简略,不须要懂容器和 Kubernetes,反对治理多个 Kubernetes 集群,提供企业级利用的全生命周期治理,性能包含利用开发环境、利用市场、微服务架构、利用继续交付、利用运维、利用级多云治理等。

🌟 Github:https://github.com/goodrain/r…
😊 官网:https://www.rainbond.com
😉 微信群:关注 Rainbond 公众号退出技术交换群
🤔 钉钉群:请搜寻钉钉群号 31096419

退出移动版