acm-header
登录

ACM通信

实践

SQL不是逃避DevOps的借口


卷起的路,说明

信贷:Palto

回到顶部

一个朋友最近对我说:“我们不能做DevOps,我们使用SQL数据库。”我差点从椅子上摔下来。这种说法在许多层面上都是错误的。

“但你不了解我们的处境!”他断然拒绝。“DevOps意味着我们将更频繁地部署新版本的软件!我们现在几乎不能处理部署,而且我们一年只做几次!”

我问他目前的部署流程。

“每隔几个月我们就会发布一个新的软件,”他解释道。“将其投入生产需要大量工作。因为我们使用SQL,所以部署看起来像这样:首先,我们踢出所有用户并关闭应用程序。接下来dba(数据库管理员)修改数据库模式。一旦他们的工作完成了,新的软件版本就被安装和启用了。这个过程要花好几个小时,所以我们倾向于在周末做,我讨厌这样。如果它失败了,我们就必须恢复到备份磁带,从头恢复一切,然后重新开始。”

他总结道:“仅仅安排这样的活动就需要数周的谈判。我们通常会在谈判中失败,这就是为什么我们最终会在周末进行谈判。每隔几个月就这么做是很痛苦的,也是这里最大的压力来源。如果我们必须在每周发行的游戏中这么做,我们中的大多数人便会选择放弃。我们就没有周末了!我听说有些公司一天要发布好几次软件。如果我们这么做了,我们的应用程序就会一直宕机等待升级!”

哇。那里有很多东西要拆。首先让我澄清一些误解,然后让我们讨论一些使这些部署变得非常非常容易的技术。

首先,DevOps不是一种技术,而是一种方法论。DevOps最简洁的定义是,它将敏捷/精益方法从源代码一直应用到生产。这样做是为了“更快地交付价值”,这是一种减少功能从想法到生产所需时间的华丽方式。更频繁的发布意味着一个新编写的特性闲置等待投入生产的时间更短。

DevOps并不要求或禁止任何特定的数据库技术或任何技术。因为你使用了一种特定的技术而说你能或不能“做DevOps”,就像说你不能将敏捷应用到一个使用特定语言的项目。SQL可能是一个常见的“当月借口”,但它是一个薄弱的借口。

我理解DevOps和SQL数据库的缺乏在某些人的心目中是如何不可避免地联系在一起的。在21世纪初和21世纪初,发明和推广DevOps的公司通常都是大型网站,巧合的是,它们也在推广NoSQL(键/值存储)数据库。然而,将两者联系起来,就会混淆相关性和因果关系。这些公司还普及了免费为员工提供美食午餐的做法。我们都同意这不是DevOps的先决条件。

其次,我不确定是否有人能做到。”DevOps。”您可以使用DevOps技术、方法等。也就是说,人们经常使用这个短语,我想我已经输掉了这场战斗。

我和我的朋友进一步讨论了他的情况,很快他就意识到DevOps并非不可能;这将是一个艰难的过渡。然而,一旦转变完成,生活实际上会容易得多。

我的朋友还有一个顾虑。“听着,”他坦白说,“这些部署是有风险的。每次我们这样做,我都在拿公司的数据冒险,说实话,还有我的工作。我只是不想做。每隔几个月做一次就已经很有压力了。做得更频繁吗?不,先生,那是不负责任的。”

正如我在前一篇文章(“小批量原则”)中所讨论的,通信(2016年7月),当某件事有风险时,人们会自然地倾向于尽量少做。与直觉相反,这实际上增加了风险。下次你做有风险的事情时,你会更加缺乏实践,对周围环境的累积变化变得越来越大,几乎保证了未知副作用的失败。相反,DevOps采取了激进的立场,认为应该做有风险的事情更频繁。较高的频率暴露了那些被掩盖在地毯下的次要(和主要)问题,因为“这种情况一年只发生一次”。它迫使我们自动化过程,自动化过程的测试,并使过程如此顺利,从而降低了风险。它给参与的人更多的练习。熟能生巧。它不是逃避我们所害怕的,而是勇敢地直面风险并克服它。就像任何经历过术后恢复的人一样,你重复这个练习,直到不再疼痛。

总有一些固定的成本需要部署。原则上,您应该始终将部署的固定成本降低到零。增加部署频率而不降低固定成本对业务是有害的,也是不负责任的。

本文的其余部分将描述在使用SQL的环境中支持快速发布的两种实践。实现它们需要开发人员、质量保证人员和运营人员走出各自的竖井并进行协作,这在一些组织中是闻未闻的,但却是DevOps的本质。结果将是一种更顺利、更少痛苦、当然也更少压力的经营方式。

回到顶部

技术1:自动架构更新

在旧的方法中,任何模式更改都需要关闭整个应用程序,由专家团队(或一个非常劳累的DBA)手动修改模式。如果要进行完全自动化的部署,就需要有完全自动化的模式更新。

为此,应用程序应该管理模式。模式的每个版本都应该编号。应用程序从模式版本1开始。该值存储在数据库中(想象一个单行表,其中只有一个字段存储值“1”)。当应用程序启动时,它应该知道它与模式版本1兼容,如果在数据库中找不到该版本,它将拒绝运行。

然而,为了自动化模式更新,该软件的下一个版本知道它需要版本2的模式,并且知道将版本1的模式升级到版本2的SQL命令。在启动时,它看到版本是1,运行适当的模式升级命令,将存储在数据库中的版本号更新为2,然后继续运行应用程序。

执行此操作的软件通常有一个SQL模式更新命令表。数组索引中的命令n从版本升级模式n1到n。因此,无论找到哪个版本,软件都可以将数据库调整到所需的模式版本。事实上,如果发现一个未初始化的数据库(例如,在测试环境中),它可能会循环进行数十次模式更改,直到得到最新版本。不是每个软件版本都需要模式更改;因此,模式和软件使用不同的版本号。

有一些开源和商业系统实现了这个过程。其中一些产品比其他产品更复杂,支持各种语言、数据库系统、复杂的错误处理,以及是否支持回滚。在网上搜索“sql change automation”会找到很多。我最熟悉的开源项目是。net的Mayflower代码(https://github.com/bretcope/Mayflower.NET)和Goose for Go (https://bitbucket.org/liamstask/goose).

用于锁定数据库数分钟甚至数小时的模式修改。这将导致应用程序超时并失败。由于无锁模式更新和在线索引功能,现代SQL数据库已经减少或消除了这类问题。这些特性可以在所有最新的SQL产品中找到,包括MariaDB、MySQL和PostgreSQL等开源产品。查看文档,了解在没有中断的情况下可以做什么和不能做什么。

一旦您的软件使用了这些技术,采用持续集成(CI)就会变得非常容易。您的自动化测试环境可以包括在旧模式中构建数据库、升级数据库并运行新软件版本的测试。在投入生产之前,您的模式升级过程可能要测试数百次。这应该会给流程带来新的信心,减少模式升级的风险,并将dba对升级的个人参与分离开来。他们会很高兴能重新享受周末。

这种技术中我最喜欢的部分是,您的模式现在被视为代码。控制台的手工工作已经被消除了,您已经获得了在开发人员沙箱、测试环境、用户验收测试(UAT)环境和生产环境中反复执行流程的能力。您可以多次运行该流程,对其进行修复和微调。既然它是代码,您就可以对它应用最好的代码管理和软件工程技术。

回到顶部

技术2:为多个模式编码

如何在分布式计算环境中升级数据库模式?

想象一个典型的基于Web的应用程序,它是运行在Web负载平衡器后面的同一软件的许多实例(副本)。每个实例接收它的HTTP流量份额。这些实例访问相同的数据库服务器。

当软件与数据库模式紧密耦合时,就不可能执行需要更改数据库模式的软件升级。如果您首先更改模式,实例将全部死亡,或者至少会被更改弄糊涂;您可以尽可能快地升级实例,但由于中断,您已经失去了游戏。

啊哈!为什么不先升级实例呢?不幸的是,当您逐个升级实例的软件时,新升级的实例将无法启动,因为它们检测到错误的模式。在模式更改为与软件相匹配之前,您最终会遇到停机的情况。

显而易见的解决方案是无视物理定律,在升级所有实例上的软件的同时更改数据库模式。如果你能那样做,一切都会好起来的。

遗憾的是,ACM有一个政策,禁止违背物理定律,就像大多数雇主一样。这就是为什么传统的方法是关闭整个应用程序,升级所有内容,然后让它重新联机。这是我们能做的最好的,直到我们的IEEE的朋友想出如何暂停时间。

无论您是通过违背物理原理来停止世界,还是通过安排停机时间来停止世界,您都引入了一个更大的问题:您已经进行了许多单独的更改,但在系统重新运行之前,您不知道其中是否有任何更改成功。您也不知道是哪些累积的更改导致了中断。

这种“大爆炸”式的改变是有风险的。每次进行一个更改并验证更改的风险较小。如果您同时进行多个更改,并且出现了问题,那么您必须开始二进制搜索,以找出是哪个更改导致了问题。如果您每次只做一个更改,并且出现了失败,那么搜索就变得无需考虑了。取消一个更改比取消许多更改更容易。

Heck,即使是拥有高度复杂的测试技术和方法的谷歌,也明白分期环境和生产环境之间的细微差异可能会导致部署失败。他们“监测”他们的软件发布:升级一个实例,等待它是否正常启动,然后随着时间的推移慢慢升级剩余的实例。这不是一种测试方法,这是一种针对不完整测试的保险政策,并不是说他们的测试人员不优秀,而是没有人是完美的。金丝雀技术现在是行业最佳实践,甚至被嵌入到Kubernetes系统中。(这个词金丝雀出自"煤矿里的金丝雀"第一个被升级的死亡是一个警告信号,表明有问题,就像过去煤矿工人带鸟,通常是金丝雀,它们对有毒气体比人类更敏感。如果金丝雀死了,那就是撤退的信号。)

由于这些问题是由于软件与特定模式紧密耦合造成的,因此解决方案是放松耦合。通过编写同时适用于多个模式的软件,可以将这些问题解耦。这是将推出和激活分开。

第一个阶段是编写不对表中的字段进行假设的代码。在SQL术语中,这意味着SELECT语句应该指定所需的确切字段,而不是使用SELECT *。如果使用SELECT *,不要假定字段的顺序是特定的。LAST_NAME可能是今天的第三个字段,但明天可能不是。

有了这个规则,从模式中删除字段就很容易了。部署了不使用该字段的新版本,一切都可以正常工作。在所有实例运行更新的版本之后,可以更改模式。事实上,由于残留字段被忽略了,您可以延迟并在以后删除它,可能要等到下一次(其他不相关的)模式更改。

添加新字段很简单,只需在使用它的第一个软件发行版之前在模式中创建它。我们使用技术1(应用程序管理它们自己的模式)并部署一个修改模式但不使用字段的版本。使用正确的事务锁定hullabaloo,使用新软件重新启动的第一个实例将干净地更新模式。如果出了问题,金丝雀就会死。你可以修复软件,试试新的金丝雀。恢复模式更改是可选的。

由于模式和软件是分离的,开发人员可以轻松地开始使用新字段。在过去,升级需要找到一个与多个团队兼容的维护窗口,而现在这个过程是解耦的,所有各方可以以协调的方式工作,但不是步调一致的。

更复杂的变化需要更多的计划。当分割一个字段、删除一些字段、添加其他字段等等时,乐趣就真正开始了。

首先,必须编写能够同时使用新旧模式的软件,最重要的是还必须处理转换阶段。假设您正在从将一个人的全名存储在一个字段中迁移到将其拆分为名、名、姓、头衔等单独的字段。软件必须检测哪些字段存在,并采取适当的行动。当数据库处于转换状态且这两组字段都存在时,它还必须正确工作。一旦这两组字段都存在,可能会运行批处理作业,拆分名称并存储各个部分,将旧字段空化。代码必须处理某些行未转换而其他行已转换的情况。

在附带的侧栏中记录了进行此转换的过程“动态模式改变的五个阶段。”它有许多阶段,包括创建新字段、更新软件、迁移数据和删除旧字段。这叫做麦克亨利技术云系统管理实践(我与Strata R. Chalup和Christina J. Hogan共同撰写了这本书);也被称为在发布中扩展/收缩它!:设计和部署可生产的软件作者:迈克尔·t·尼加德

该技术足够复杂,可以处理实时分布式系统上最复杂的模式更改。另外,每一个突变都可以单独回滚。

在特殊情况下,可以减少相的数量。如果只添加字段,则跳过阶段5,因为没有要删除的内容。这个过程简化为本文前面所描述的。阶段4和阶段5可以合并或重叠。或者,一个模式更改的阶段5可以合并到下一个模式更改的阶段2中。

使用这些技术,您可以在不停机的情况下完成最复杂的模式更改。

回到顶部

总结

使用SQL数据库并不是进行DevOps的障碍。自动化的模式管理和少量的开发人员规程可以实现更有力和可重复的测试,更短的发布周期,并降低业务风险。

自动化发布解放了我们。它将一个令人担忧的、有压力的手动升级过程变成了一个正常的事件,不会发生意外。它降低了商业风险,但更重要的是,它创造了一个更可持续的工作场所。

当您可以自信地部署新版本时,您可以更频繁地部署它。以前需要数周或数月才能发布的新功能现在可以更快地到达用户手中。bug修复得更快。安全漏洞很快就被堵上了。它使公司能够为客户提供更好的价值。

回到顶部

致谢

感谢Sam Torno, Mark Henderson和Taryn Pratt, SRE, Stack Overflow Inc.;史蒂夫•甘恩独立;Harald Wagener, iNNOVO Cloud GmbH;Pivotal的安德鲁·克莱·谢弗(Andrew Clay Shafer);克里斯蒂安Kohntopp,Booking.com, Ex-MySQL AB。

ACM队列的q戳相关文章
queue.acm.org

小批量原则
托马斯·a·Limoncelli
https://queue.acm.org/detail.cfm?id=2945077

在质量保证中采用DevOps实践
詹姆斯罗氏
https://queue.acm.org/detail.cfm?id=2540984

回到顶部

作者

托马斯·a·Limoncelli是纽约Stack Overflow公司的SRE经理。他的著作包括系统与网络管理实务,云系统管理实务,系统管理员的时间管理。他的博客EverythingSysadmin.com和微博@YesThatTom

回到顶部


版权归所有者/作者所有。授权ACM出版权利。
请求发布的权限permissions@acm.org

数字图书馆是由计算机协会出版的。版权所有©2019 ACM, Inc.


没有发现记录

Baidu
map