【问题标题】:How to implement rolling updates and a relational database?如何实现滚动更新和关系数据库?
【发布时间】:2018-12-16 23:55:03
【问题描述】:

我有一个使用关系 DBMS 的现有系统。由于各种内部原因,我无法使用 NoSQL 数据库。

该系统将获得一些将使用 Kubernetes 和 Docker 部署的微服务,目的是进行滚动升级以减少停机时间。后端数据层将使用现有的关系 DBMS。微服务将遵循良好实践并在 DBMS 上“拥有”它们的数据存储。与此有关的一个大问题似乎是如何处理跨此管理数据库的结构。我已经完成了我的研究:

所有讨论似乎都围绕添加/删除列和数据迁移这一点而停止。没有讨论如何管理存储过程、视图、触发器等。

应用程序使用 .NET Full 和 .NET Core 编写,Entity Framework 作为 ORM。

有没有人对如何使用关系 DBMS 进行连续交付有任何见解,它是一个完整的生产系统?是不是又回到了这里的绘图板?使用关系 DBMS 对于滚动更新来说“太难”了?

PS。尽管这是一个持续的交付问题,但我也标记了 Kubernetes 和 Docker,因为这将是用于事物的编排/容器方面的底层技术。

【问题讨论】:

标签: docker kubernetes relational-database continuous-deployment


【解决方案1】:

以下所有内容均假设我正确理解“滚动更新”的含义及其后果。

它与“关系 DBMS”几乎没有关系(如:根本没有)。包含 XML 的平面文件将使您面临完全相同的问题。您的“滚动更新”将不可避免地导致(希望是短暂的)您的服务器端组件(例如数据库)必须与“版本 0”以及(客户端组件)的“版本 -1”交互的)你的系统。

这里“兼容性理论”(*)介入。“工作系统”是一个系统,其中提供的服务集是所需服务集的超集(可能是适当的超集)。因此,如果“提供的服务”永远不会减少并且“所需的服务”永远不会扩展,则可以保证向后兼容性。但是,后者通常是当当前“版本 0”移动到“-1”并且新的“当前版本 0”添加到混合中时总是发生的情况。所以结论是,“滚动更新”在理论上是可行的,只要服务器端提供的“服务”只被扩展,并且总是以这样的方式成为,并且总是保持,所需服务的超集(当前在客户端使用的任何版本。

“服务”在这里被解释为非常抽象的东西。它可能指的是一种保证,例如,如果该表的这一行中的列 X 具有值 Y,那么我使用计算出的键在该另一个表中找到另一行所以,并且可以保证其他行的列值满足这个或那个条件。

如果该“保证”引入作为(新版本)客户端的期望(即要求),则您必须在服务器端执行某些操作才能遵守。如果该“保证”当前提供,但矛盾的保证被引入作为(新版本)客户端的期望,那么您的滚动更新方案根据定义变得无法实现.

(*)http://davidbau.com/archives/2003/12/01/theory_of_compatibility_part_1.html

还有第 2 部分和第 3 部分。

【讨论】:

    【解决方案2】:

    我在实现持续交付的环境中工作。我们使用 MySQL。

    我们使用pt-online-schema-change 以最小的中断应用架构更改。也可以使用gh-ost

    如果应用程序代码可以使用额外的列,则可以随时添加列。例如,避免使用没有列列表子句的 SELECT *INSERT 等隐式列是一个很好的规则。在应用代码不再引用该列后,可以删除该列。在不协调应用程序发布的情况下重命名列会比较棘手,在这种情况下,您可能必须进行两次架构更改,一次是添加新列,另一次是在已知应用程序不引用后删除旧列旧专栏。

    我们使用冗余对数据库服务器进行升级和维护。每个数据库 master 都有一个副本,两个实例都配置在 master-master(循环)复制中。所以一个是主动的,另一个是被动的。应用程序只允许连接到活动实例。被动实例可以重启、升级等。

    通过更改内部 CNAME 并更新每个 MySQL 实例中的 read_only 选项,我们可以在 1 秒内切换活动实例。

    数据库连接在此切换期间终止。应用程序需要检测断开的连接并重新连接到 CNAME。这样,应用程序始终连接到活动 MySQL 实例,从而释放被动实例以进行维护。

    MySQL 复制是异步的,因此可以关闭和备份实例,并且它可以恢复复制更改并且通常会很快赶上。只要它的主人保留所需的二进制日志。如果副本关闭的时间超过二进制日志到期时间,则它会丢失其位置,并且必须从活动实例的备份中重新初始化。


    回复:

    数据访问代码是如何版本化的?即应用程序的v1 与DB 的v2 交谈?

    这取决于每个应用开发团队。我相信大多数人都在持续发布,而不是版本。

    SP、UDF、Triggers等是如何处理的?

    没有任何应用在使用这些。

    MySQL 中的存储例程实际上更像是一种负担而不是一种特性。不支持例程的包或库,没有编译器,没有调试器,可伸缩性差,而且 SP 语言不熟悉且文档记录不充分。我不建议在 MySQL 中使用存储例程,尽管它在 Oracle/Microsoft 数据库开发实践中很常见。

    我们的环境中不允许使用触发器,因为 pt-online-schema-change 需要创建自己的触发器。

    MySQL UDFs 是编译后的 C/C++ 代码,必须作为共享库安装在数据库服务器上。我从未听说过任何公司在 MySQL 的生产中使用 UDF。 C 代码中的错误可能导致整个 MySQL 服务器进程崩溃的风险太高了。在我们的环境中,出于 SOX 合规性的原因,不允许应用程序开发人员访问数据库服务器,因此他们无论如何都无法安装 UDF。

    【讨论】:

    • Bill:数据访问代码是如何版本化的?即应用程序的v1 与DB 的v2 交谈? SP's、UDF's、Triggers 等是如何处理的?
    猜你喜欢
    • 2013-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 2018-10-26
    • 1970-01-01
    • 2020-01-16
    相关资源
    最近更新 更多