如何在多节点生产服务器上迁移数据库?

时间:2016-06-16 14:05:06

标签: java mysql database spring hibernate

我有一个多节点生产服务器(CentOS 7.x上的Tomcat 8.x;每个节点都是一个单独的CentOS实例),它使用一个MySQL数据库服务器(MySQL 5.7.x)。服务器的每个节点都将手动更新:系统管理员停止每个节点并部署新版本的应用程序(.war文件)。这意味着该服务不会有停机时间,因为每时每刻都至少有一个工作节点。

数据库迁移是使用Liquibase变更集实现的,它们放在.war文件中。因此,每个节点都验证并更新(如果需要)数据库模式。实际上,只有第一个节点执行变更集,而其他节点只是验证它。

问题是每个节点的更新之间存在时间差:当第一个节点已经使用新的应用程序版本更新时,最后一个节点仍然可以使用以前的应用程序版本(可能使用数据库中的旧列)例)。这可能会导致数据库不一致。

示例

假设服务器有3个节点。此时他们正在处理N版本的应用程序。 下一版本需要更改数据库架构:将列title重命名为title_new

为了能够在不停机的情况下更新数据库架构,我们需要使用"两步更改":

  • 版本N + 1:
    • 添加了新列title_new
    • 不再使用列title(标记为已弃用);
    • 将列title中的所有数据复制到title_new;
    • 使用列title_new;
  • 版本N + 2会删除列title

现在管理员将部署版本N + 1。他停止第一个节点进行更新,但其他两个节点仍在使用版本N.当第一个节点正在更新时,一些用户可能会使用节点2或3更改其数据(有一个负载均衡器,将请求路由到不同的节点)。因此,我们需要一种方法来禁止用户通过节点2和3进行任何更改,而不会使用版本N + 1进行更新。

我认为有两种不同的方法可以解决这个问题:

  1. 在应用程序级别使用某种read_only模式 - 然后应用程序逻辑禁止用户进行任何更改。但是,我们需要使用控制台或管理面板随时实现某些启用此模式的方法(必须允许管理员启用此模式)。
  2. 在数据库级别使用read_only模式。但我无法找到任何可供MySQL使用的方法。
  3. 问题:解决上述问题的最佳方法是什么?

    P.S。应用程序基于Spring 4.x框架+ Hibernate 4.x。

2 个答案:

答案 0 :(得分:1)

解决此问题的另一种方法可能是:"使用数据库触发器":

版本N + 1:

  • 为每个重命名的列创建一个触发器,将标题中插入/更新的数据复制到title_new(参见here

版本N + 2:

  • 放下触发器,放下旧列

这种方法的优点是:

  • 可以使用liquibase完全完成(不需要为管理员提供额外的步骤)
  • 所有节点都保持完整功能(不是只读)

缺点:

  • 你必须写/使用触发器
  • 如果您的数据库更新更复杂(如列重命名+新数据库约束),
  • 可能会很棘手

答案 1 :(得分:0)

Zero Downtime Deployment with a Database

我发现上面的文章对于没有停机的数据库迁移的各种选项非常有见地。