@程序员,使用了 SQL 就不能用 DevOps?

640?wx_fmt=gif

自动化和适当地应用规则可以实现更高质量的测试、更短的产品发布周期并且能够降低业务风险。

640?wx_fmt=jpeg

作者 | Thomas A.Limoncelli

译者 | 彼得(王丰力)

责编 | 屠敏

出品 | CSDN(ID:csdnnews)

我的一位朋友最近对我说:“因为我们使用SQL数据库,所有我们不能应用DevOps方法”。我很奇怪人们会有这种观点,因为它在许多方面都是错误的。

他说,“你不了解我们的情况!DevOps意味着我们将更频繁地更新我们的软件。但是,我们也只是勉强维持,我们每年只能把我们的部署更新几次而已!”

我向他询问了他们目前的部署流程。

他解释说,“我们每隔几个月就会获得一个新的软件版本,但是将它们部署到生产环境需要大量的工作。因为我们使用SQL,所以我们的部署就是:首先,我们停止所有用户的访问。然后,我们停止应用程序的运行。接下来,DBA(数据库管理员)就开始修改数据库模式。当他们的工作完成以后,我们就开始安装和启用新版本的软件。这个过程需要花费很多的时间,所以,我们经常在周末进行升级。对于这一点,我也很讨厌。如果升级失败,我们就必须恢复备份磁带,并从头开始恢复所有内容,最后,重新启动。“。

他总结道:“仅仅安排这样的升级活动,我们就需要花费数周的时间进行协调。我们也经常协调失败。这就是为什么我们不得不在周末进行升级。每隔几个月就有一次这样的经历,真的让人感到很痛苦,这也是我们所有人最大的压力来源。如果我们每周发布一次,我们中的大多数人都会辞职。我们没有周末呀!我听说有些公司一天发布软件多次,如果我们这样做了,我们的应用程序就会一直处在停机、升级的状态!”

好多事情需要解决。我先澄清一些误解,然后,我们再讨论一些能使这些部署变得更加简单的技术。

首先,DevOps不是一种新技术,而是一种方法论。DevOps最简洁的定义是它将敏捷/精益生产(Agile/Lean)的方法贯穿于从源代码到生产环境的整个软件生命周期。这样做的目的是为了“更快地交付价值”,也就意味着缩短软件从构思到产品上线的周期。更频繁的发布意味着新实现的功能在投入生产环境前需要等待的时间更短。

DevOps不强制要求或禁止任何特定的数据库技术或任何其他的技术。因此,你没有任何理由说因为某一种特定的技术,使你能或者不能应用“DevOps”。同样,你也不能说在某个项目中因为你使用特定的语言,所以你不能应用敏捷开发。SQL可能是一个不应用“DevOps”的常见的理由,但是,这个理由经不起推敲。

我很理解在某些人的思维中,DevOps之所以能够使用,是因为对应的应用没有SQL数据库。在2000年代和2010年初,发明和普及DevOps的公司通常是大型网站,很凑巧的是,它们都使用NoSQL(键/值存储)数据库。 然而,将这没有因果关系的两者联系起来是没有道理的。这些公司也在向员工提供精美的免费午餐,但是,我们都知道这不是DevOps的先决条件。

其次,我不认为应该说有人可以“做DevOps”。你可以使用DevOps相关的任何技术和方法。人们经常使用说“做DevOps”,这就让我很难解释。

我和我的朋友进一步讨论了他的情况,很快他就意识到DevOps对他来讲并非不可能;这只是一个艰难的转变过程。然而,一旦转变完成,他就可以很容易地应对他的工作。

我的朋友还有一个疑问。他说,“你看,这些部署都有风险。我们每做一次,我都会冒着公司数据丢失的风险。说实话,做出这些改变是我份内的事,但是,我真不想这样做。每隔几个月经历一次就够让人紧张的了,如果还要更频繁地做这些事,太难了。“

正如我在之前的专栏(”小批量原则”,发布于acmqueue的14卷第2期:https://queue.acm.org/detail.cfm?id=2945077)中所说的那样,当我们觉得某些事情有风险时,我们自然会倾向于少做。但是,与我们的直觉相反,这样做,实际上增加了风险。因为下次你想做这样的事情时,你就更没有实践的机会,因为周围环境的变化会逐步累积,越来越大,几乎肯定会应为这些因素导致失败。相反,DevOps采取比较激进的立场,认为对于风险高的事情应该更加频繁地尝试。更高的试验频率都使我们能够更容易发现那些不容易重现的小问题。这些小问题有时候一年只发生一次。这些所谓的小问题其实并不小。为了解决这些问题,我们需要自动化我们的流程、自动化流程测试,并使流程能够顺利进地行,从而降低风险。它为参与者提供了更多的练习的机会,熟能生巧。它让我们不是逃避我们所害怕的事情,而是勇敢地承担风险并克服它。这就像任何经历过术后恢复的人一样,你需要重复练习直到它不再痛苦为止。

部署总是有一些固定的成本。从原则上讲,您应该始终努力降低部署的固定成本。你的目标应该是将它们降低为零。因为在不降低固定成本的情况下,盲目增加部署频率对公司是不利的,也是不负责任的。

本文的后面的部分描述了两种在使用SQL的环境中实现快速发布的经验。实现它们需要开发人员、质量保证和操作人员密切协作。这在某些组织中是闻所未闻的,但却也是DevOps的本质。这样做的结果将是一种更平稳、更轻松、当然也更少压力的业务模式。


640?wx_fmt=png

技术 1:自动化模式更新


按照以前的方法,任何数据库模式的变化都要求停止整个应用程序。只有在应用停止运行的时候,一组数据库专家(或者一个超时工作的数据库管理员)才能手动修改数据库结构。如果要进行全自动部署,那么你就需要完全自动化的数据库模式更新。

为此,应用程序应该能够自己管理自己的数据库模式。模式的每个版本都应该具有对应的版本号。应用程序从1开始命名模式版本号。该版本号存储在数据库中(请想像一下一个单行表,该表的某一个字段存储数值“1”)。当应用程序启动时,它知道它与模式版本1兼容,如果它在数据库中找不到该版本,该程序将不能启动。

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

按照这种方式运行的软件通常都有一个SQL模式更新的命令列表。该列表中的第n条命令将数组模式的版本号从n-1升级到n。因此,无论当前的数据模式是哪个版本,该软件都可以将数据模式升级到对应的版本。如果该软件发现未初始化的数据库(例如,在测试环境中),它可能会重复执行几十次数据模式更新,直到最新版本的数据模式才停止。并非每个版本的软件都有数据模式的更改,因此数据模式和软件需要使用不同的版本号。

现在,既有开源软件也有商业软件支持这种数据模式的自动更新。在这些软件中,有一些比其他产品逻辑更复杂,能够支持更多的语言和数据库系统、错误处理更复杂并且能够支持回滚。如果在Web上搜索“sql change automation”,可以找到很多相关的软件。我本人最熟悉的是.NET的开源项目Mayflower(https://github.com/bretcope/Mayflower.NET)和Go语言的Goose项目(https://bitbucket.org/liamstask/goose)。

为了修改数据模式,通常需要将数据库锁定几分钟甚至几小时。这将会导致应用程序超时失败。一些新型的SQL数据库因为实现了无锁模式更新和在线重新索引的功能,从而能够减少或彻底解决了这个问题。这些新功能在所有最新的SQL的产品中,都已经实现。像Mariadb、MySQL和PostgreSQL等开源产品,也已经支持。请查看相关文档,来了解在不影响应用运行的情况下,哪些操作能够执行,哪些不能执行。

一旦在软件开发中使用了这些技术,应用CI(持续集成)就会变得非常容易。自动化测试环境里可以包含一系列的自动测试脚本,这些自动测试脚本可以在旧的数据模式中创建数据库并进行升级,然后运行和测试新版本的软件。数据模式的升级过程在投入到生产环境之前,可以经过数百次的测试。这会给流程带来更多的信心,降低模式升级的风险,同时避免了DBA在升级过程中的人工参与。这些DBA也能够享受自己的周末时光了。

在这项技术中,我最喜欢的还是你的模式也被认为是代码。你再也不需要在控制台上进行的手工操作,而且可以在开发人员的沙箱(sandbox)环境、测试环境、用户认可测试环境(UAT)和生产环境中重复运行相同的流程。也可以不断地运行该流程,同时也可以对流程进行修改和调整。既然模式被认为是代码,那么就可以将最好的代码管理和软件工程技术应用到它上面。


640?wx_fmt=png

技术2:多个模式的编码


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

在一个典型的互联网应用中,在负载均衡器后面的服务器上,通常会有同一软件的许多实例(副本)在同时运行。每个实例分别处理它们收到的HTTP请求。这些实例会访问同一个数据库服务器。

如果软件与数据库模式是紧耦合的,就不可能在不停止服务的情况下,执行涉及到数据库模式改变的软件升级。如果首先更改模式,就会造成应用程序实例的停止或逻辑的混乱;当然也可以选择在停止服务的前提下,尽可能快地升级应用实例,但是在互联网时代,停止服务是不能够接受的。

且慢,能不能先升级应用实例呢?非常不幸,当你逐个升级应用实例时,刚刚升级后的实例是无法启动的,因为它们会检测到不匹配的数据模式。在模式更改之前,就会出现服务停止的情况。

这么看来,唯一的解决方案就是同时升级所有实例上的软件和数据库模式。如果你能做到这一点,一切问题都会迎刃而解。

可悲的是,就像大多数雇主一样,ACM也有一项不能够违反的规律。这就是为什么传统的方法是关闭整个应用程序,进行升级,然后将应用重启。在IEEE的朋友找到办法让时间暂停之前,这是我们唯一能做的事。

不管你是想挑战物理定律来让世界暂停还是被迫安排停机来进行升级,都面临着一个更大的问题:你已经改了很多东西,但是在系统重新运行之前,你都不知道其中任何一个改动的是否成功。如果出现问题,你也不知道是哪些改变引起的。

这样的“大爆炸”式的改变是有非常有风险的。如果一次只改变一部分并对其进行验证的话,面临的风险就会小很多。如果同时进行多个变更,在出现问题的时候,就必须进行二分法查找,以确定是哪个变更导致了问题。如果你一次只做一个更改就失败了,那么定位问题就很容易了。放弃一个变更也比放弃许多变更更容易。

Google拥有很多业界领先的测试技术和测试方法,他们也明白测试环境和生产环境之间的细微差别也可能导致部署失败。 他们采用金丝雀部署的方法来发布他们的软件产品:他们首先升级一个实例,在确认该实例能正常工作之后,再逐步升级其他的实例。 这本身不是一种新的测试方法论,这是在不完整测试的条件下,比较安全的做法。他们采用这种方法并不是因为他们的测试人员不优秀,而是因为人无完人,任何人都会犯错误。金丝雀部署方法现在是行业的最佳实践,它已经被包含在Kubernetes系统中。(金丝雀这个词来源于“煤矿中的金丝雀”。把第一个升级失败的实例作为警告标志,表明升级存在问题。这就像在以前矿井中,煤矿工人会带着鸟类下矿井。通常他们带着金丝雀,因为金丝雀比人类对有毒气体更敏感。如果金丝雀死了,表明矿井中存在毒气,煤矿工人们应该撤离。

产生这些问题的根本原因是因为软件紧耦合到特定的模式。要解决这个问题,就需要降低耦合的程度。 通过让软件同时支持多个数据模式可以降低它们耦合的程度。这就是区分开部署和激活这两个任务。

要做到这一点,首先在写代码的时候就不能对数据库表格中的字段做任何假设。这意味着SELECT相关的SQL语句应该指定所需的确切字段名称,而不是使用SELECT * 这种格式。如果你使用了SELECT *,也不要假设查询结果中字段的顺序是固定的。比如LAST_NAME这个字段的顺序今天可能是第三个,但明天就不一定还是。

按照这个规则,从模式中删除一个字段很容易。只有部署的新版本中不再使用该字段,那么就一切正常。你可以在所有运行的实例都更新到新的版本之后再更新模式。事实上,由于冗余字段会被程序忽略,所以你可以在稍晚一点(或更晚的时候)再删除它。你可以在进行下一个和该字段无关的模式更新的时候再删除它。

添加字段很简单,只需在使用它的第一个软件版本发布之前在模式中创建它就可以。我们使用1技术(由应用程序管理自己的模式)来部署一个修改模式的版本,但是在该版本中并不使用新字段。新版本的第一个实例启动之后,他会利用数据库的事务性锁进行模式更新。如果模式有问题,通过这个实例就会发现。你可以修改软件,用新的实例再进行试验。不一定非要还原模式的更改。

由于模式和软件是解耦的,开发人员可以在任何时候使用这个新字段。在过去,要进行升级就必须协调多个团队都能接受的维护窗口。现在,因为这个过程是松耦合的,所有各方都可以通过协调分别进行升级,并不需要互相之间的紧密依赖。

越是复杂的变化,越需要更好的规划。当你拆分一个字段、删除一些字段或者添加其他字段时,你就会发现更多的乐趣。

首先,你编写的软件必须能够同时在旧模式和新模式下面工作,同时它也需要在模式转换的状态下工作。假设你原来在一个字段中存储一个人的全名,现在需要将该字段分成几个字段,分别用来存储一个人的名字、中间名、姓氏、头衔等信息。你编写的软件必须能检测出当前有哪些相关字段并能够正确处理。当数据库处于转换状态并且两组字段都存在时,它也必须能够正确运行。一旦两组字段都存在,就可能会运行一个批处理程序来分割这些姓名相关的字段并存储各个部分信息,把旧字段为空。你的代码也必须能处理数据库表中的某些行还没有更新,但是其他行已经更新的情况。

进行这种转换的过程记录在下面的“实时模式更改的五个阶段”中。它包含创建新字段、更新软件、迁移数据和删除旧字段等阶段。在《云系统管理实践》一书中,它被称为McHenry技术。该书由我、Stratar R.Chalup和Christina J.Hogan合著。在《扩展/契约:设计和部署随时可以做产品发布的软件》一书中,他被称为扩展/契约。该书的作者是Michael T. Nygard。

实时模式更新的五个阶段

1.代码读写旧的模式,从表或视图中读取所需的字段。这就是原始状态。

2.扩展:添加新的字段,但是并不删除任何已有字段进行模式的修改。这时候,没有进行任何代码的更改。因为新字段并没有在代码中使用,如果需要回滚,这是很容易的。

3.修改代码来使用模式中新增加的字段并将改动的代码发布到生产环境中。如果需要回滚,就只能回滚到第2阶段。这时,任何数据转换都可以在系统运行的时后进行。

4.契约:删除引用原有但是现在不再使用字段的代码并将其发布到生产环境中。 如果需要回滚,就只能回滚到第3阶段。

5.将原有但是现在不再使用的字段从模式中删除。如果此时需要回滚,数据库将简单地回滚到第4阶段。

这项技术非常先进,它足以应对在最复杂的实时分布式系统上进行的模式更改。另外,每个改变都可以单独回滚。

对于特殊情况,可以减少阶段的数量。如果只是添加字段,因为没有要删除的内容,你可以跳过第5阶段。该流程就会被简化成为本文前面讲的那样。第4阶段和第5阶段可以组合在一起或者互相替代。你也可以将一个模式更改的第5阶段合并到下一个模式更改的第2阶段中。

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


640?wx_fmt=png

总结


使用SQL数据库并不是实行DevOps的障碍因素。自动化的模式管理和少量的开发人员规范会生成更加稳定和可重复的测试,同时也能缩短产品的发布周期,降低业务风险。

自动发布解放了我们双手。它将令人不放心的、有压力的手动升级过程变为无事故发生的常规事件。它降低了业务风险,但更重要的是创造了一个更可持续的工作环境。

当你可以充满自信地发布新的版本时,你就可以更加频繁地进行部署。以前几个星期或几个月未发布的新功能现在可以更快地让用户用上,错误修复得更快,安全漏洞也可以很快就被修复了。它使公司能够为客户提供更好的价值。

致谢

我要感谢以下人员对本文的大力帮助:Sam Torno, SRE, Stack Overflow Inc.; Mark Henderson, SRE, Stack Overflow Inc.; Steve Gunn, independent; Harald Wagener, iNNOVO Cloud GmbH; Andrew Clay Shafer, Pivotal; Kristian Köhntopp, Booking.com, Ex-MySQL AB.

相关文章

  • 《The Small Batches Principle》, Thomas A. Limoncelli :https://queue.acm.org/detail.cfm?id=2945077

  • 《Lean Software Development — Building and Shipping Two Versions》Kate Matsudaira:https://queue.acm.org/detail.cfm?id=2841311

  • 《Adopting DevOps Practices in Quality Assurance》,James Roche:https://queue.acm.org/detail.cfm?id=2540984

原文:https://queue.acm.org/detail.cfm?id=3300018

作者简介:Thomas A.Limoncelli 是纽约 Stack Overflow 公司的网站可靠性管理员。他的著作包括《系统和网络管理实践》、《云系统管理实践》和《系统管理员时间管理》。他在 everythingsysadmin.com 上写博客,在@yesthattom上发推文。他拥有德鲁大学计算机科学学士学位。

本文为 CSDN 翻译,如需转载,请注明来源出处。

 热 文 推 荐 

☞ 京东末位淘汰 10% 高管 ;聊天宝惊现大 Bug:用户可提现百万;斗鱼回应“人去楼空” | 极客头条

那些被遗忘的码农

告别相杀!面向对象和函数式编程共存

☞ 那些简历造假拿 Offer 的程序员,后来都怎么样了?

☞ 被V神点赞, 我是如何用五子棋打败以太坊排名最高的应用的? |人物志

☞ 50个最有价值的数据可视化图表(推荐收藏)

一键免费自动AI抠图,效果连PS大哥也点赞!

史上最难的一道Java面试题

 
 

print_r('点个好看吧!');
var_dump('点个好看吧!');
NSLog(@"点个好看吧!");
System.out.println("点个好看吧!");
console.log("点个好看吧!");
print("点个好看吧!");
printf("点个好看吧!\n");
cout << "点个好看吧!" << endl;
Console.WriteLine("点个好看吧!");
fmt.Println("点个好看吧!");
Response.Write("点个好看吧!");
alert("点个好看吧!")
echo "点个好看吧!"

640?wx_fmt=gif点击“阅读原文”,打开 CSDN App 阅读更贴心!

640?wx_fmt=png 喜欢就点击“好看”吧!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值