Release It! 第2版中译稿试读:赞誉、致谢、前言及第1章生产环境的生存法则

注:以下内容刚刚译完,尚未定稿,会与正式版有出入。仅供参考。本页试读内容的发布已经获得图灵公司相关编辑的许可。

Release It! 第2版目录

第2版赞誉

迈克是软件行业最深刻的思想家,也是最清晰的沟通者。与第1版相比,第2版不仅同样文笔优美,还用现代技术对内容进行了扩展(最显著的是持续部署、云基础设施和混沌工程),这将有助于我们构建和运维大规模软件系统。——Stitch Fix公司工程副总裁Randy Shoup

如果想要将任何类型的系统投入生产,本书应该是案头常备的最重要的一本书。作者将其在该领域所获得的丰富经验,通过易读的文字和紧凑的形式表现出来。本书第2版围绕系统韧性这个核心模式,很好地阐释了不同的系统结构上的真实世界的服务的开发、编排、安全和部署的新方法。——Neo4j公司开发者关系工程总监Michael Hunger

本书讨论了很多内容,包括有关应用程序的系统韧性、安全性、运维和架构的许多模式和反模式。即便有了这样宽的广度,本书同时对这些内容的讨论也颇具深度。所以本书不仅值得读,还值得研究。——8th Light公司CTO及《Mastering Clojure Macros》作者Colin Jones

对于那些想在生产环境运行软件,并且仍然能够在晚上睡个好觉的人来说,本书是必读书。它将助你建立信心,并学会期待和接受软件系统的失效。——《Deliver Audacious Web Apps with Ember 2》作者Matthew White

我会向专业从事于软件项目的人推荐这本书。鉴于第2版内容已全面更新,以涵盖每日所处理的技术和内容,我希望我的团队中的每个人都能人手一卷,以了解现代软件开发所必须考虑的广泛的内容。——软件工程师及团队负责人Andy Keffalas

对于任何想要构建真正健壮和容量可伸缩系统的人来说,本书是必读书。——软件程序员Peter Wood

致谢

我非常感谢许多阅读并分享本书第1版的读者!我很高兴能有这么多人发现本书很有用。

多年来,有不少人催我更新这本书。感谢Dion Stewart、Dave Thomas、Aino Corry、Kyle Larsen、John Allspaw、Stuart Halloway、Joanna Halloway、Justin Gehtland、Rich Hickey、Carin Meier、John Willis、Randy Shoup、Adrian Cockroft、Gene Kim、Dan North和Stefan Tilkov,以及所有其他那些看到软件开发方法已经不同于2006年之前的单块系统构建方法的人们。

感谢本书所有的技术审阅者:Adrian Cockcroft、Rod Hilton、Michael Hunger、Colin Jones、Andy Keffalas、Chris Nixon、Antonio Gomes Rodrigues、Stefan Turalski、Joshua White、Matthew White、Stephen Wolff和Peter Wood。你们的努力和反馈已使本书质量更好。

还要感谢Nora Jones和Craig Andera,你们允许我将你们的故事写入本书。本书中的那些"战争"故事一直是我的最爱,我知道许多读者都有同样的感受。

最后,非常感谢Andy Hunt、Katharine Dvorak、Susannah Davidson Pfalzer以及The Pragmatic Bookshelf的整个团队。感谢你们的耐心和毅力。

前言

本书将探究用来架构、设计和构建软件(特别是分布式系统)的方法,以应对艰险难测的现实世界。这需要我们做好准备,以对付做事疯狂、难以预料和不合逻辑的大批用户。从发布的那一刻起,软件就会遭受攻击。它既要承受像台风般袭来的“快闪族”{![“快闪族”(flash mob)原指一种行为艺术,其间许多人通过互联网或其他方式,在一个指定的时间和地点,出人意料地同时做一系列指定的动作,然后迅速离开。——译者注]}用户所带来的负载压力,也要因为不安全的物联网设备而承受DDoS(Distributed Denial-of-Service,分布式拒绝服务)攻击所带来的毁灭性压力。本书会仔细研究那些没能经受住这番考验的软件,并找到一些方法,以确保软件在上述攻击之下,仍能幸免于难。

读者对象

本书面向分布式软件系统的架构师、设计师和开发工程师。分布式软件系统包括网站、Web服务和EAI(Enterprise Application Integration,企业应用集成)项目。这些系统必须处于可用状态,否则公司就会赔钱。它们也许是通过销售以直接实现创收的商务系统,抑或是内部员工用于完成工作的关键系统。如果有人因为软件停止工作而不得不回家,那么本书就能派上用场。

内容结构

本书分为四个部分,每个部分都从一个案例研究说起。

第一部分展示如何使系统保持工作状态,从而维持系统的正常运行。尽管冗余设计保证了可靠性,但是分布式系统所表现出来的可用性,更像是“两个8”,而不是令人梦寐以求的“五个9”{![“两个8”和“五个9”分别指系统能在88%和99.999%的时间内可用。——译者注]}。稳定性是在考虑任何其他问题之前,都必须考虑的先决条件。如果系统每天都会崩溃和停机,人们就不会关心其他事情了。在这种情况下,主要的工作就是进行短期修复,目光也会变得短浅。没有稳定性,系统就没有可行性。所以,本书会从为系统打造稳定的基础开始讲起。

确保稳定性之后,下一个要考虑的是持续的运维。第二部分讨论系统在生产环境中运行究竟意味着什么。我们需要应对现代生产环境的复杂性——虚拟化、容器化、负载均衡和服务发现的各种细节。这一部分将描述一些良好的模式,以帮助物理数据中心和云环境实现可控性、明晰性和可用性。

第三部分讨论部署。对于将软件部署到服务器,市面上已经有了一些很棒的工具。但事实证明,这只解决了问题中很简单的那部分。在将小变更频繁地推送给消费者的同时,又不打扰他们,这让问题变得困难了许多。这一部分先讨论如何针对部署进行设计,以及如何在不停机的情况下进行部署,然后讨论在不同的服务之间如何进行版本控制——这总是一个棘手的问题!

第四部分从整个信息生态系统的视角,探究发生在其中的那些让系统持续运行的活动。如果1.0版本的发布意味着该系统的诞生,那么之后则需要考虑其成长和发展。这一部分将讨论如何构建能随着时间的推移不断成长、伸展和适应的系统。这包括进化式架构和跨系统进行共享的“知识”。最后会讨论如何通过新兴的“混沌工程”学科,以构建反脆弱系统。“混沌工程”使用随机性并通过故意地给系统施压以改善系统。

案例研究

本书会用几个扩展的案例研究,以刻画其所涉及的几个主题。这些案例研究来自我亲身观察过的真实事件和系统失效。这些系统失效导致了惨重的损失,并让那些参与其中的人们感到难堪。因此,本书特意对一些信息进行了模糊处理,以保护牵涉其中的公司和员工。另外,其中涉及的系统、类和方法的名字也做了改动。然而,所有的改动仅限于这些不重要的细节。每个案例所属的行业、事件的顺序、系统失效方式、差错的蔓延和后果,都原汁原味地保留下来。案例研究并没有夸大这些系统失效的损失。它们都发生在真实的公司身上,损失的都是一捆捆的钞票。之所以保留这些数字,就是为了强调本书的严肃性。当系统出现失效时,真金白银就悬了。

在线资源

在本书的网页{![https://pragprog.com/titles/mnee2/46]}上,可以阅读更详细的信息,下载源代码,在论坛上发帖,并可报告勘误信息(如笔误和对本书内容的建议)。如果想与其他兴趣相投的读者聊天,并分享对本书的评论,那么论坛就是理想的场所。

现在就开始介绍生产环境的生存法则。

第1章 生产环境的生存法则

在项目上努力工作了许久,看起来所有的特性都已实现,甚至大多数都有了自动化测试。可以松一口气了。完事儿了。

真的完事儿了吗?

“特性已实现”是否就意味着“就绪可上线”?系统是否真的万事俱备只待部署?是否真的可以放心地将系统移交给运维部门,并且任其面对现实世界中的大批用户?此时,内心深处是否开始泛起一股即将面临深夜紧急电话和系统告警的不详之感?事实证明,软件开发除了添加所需特性之外,要做的事情还多着呢。

如今,学校里的那些软件设计课程极其片面。这些课程只是讨论系统“应该”做什么,却没有解决相反的问题——系统“不应该”做什么。系统不应该崩溃、停止响应、丢失数据、侵犯隐私、损失金钱、摧毁公司,或者夺去顾客的生命。

项目团队的目标往往是通过QA{![QA是Quality Assurance的缩写,即质量保证,本书指软件测试。——译者注]}部门的测试,而不是通过生产环境的生存考验。也就是说,团队的大部分工作都是想方设法地通过测试。但即使是做了敏捷的、务实的和自动化的测试,也不足以证明软件已经为现实世界做好了准备。来自现实世界的压力和重负,伴随着亢奋狂热的真实用户、全球范围的网络流量和在闻所未闻的国家编写病毒软件的家伙,都远远超出了所能期望的测试范围。

请面对现实:计划再周详,仍会出状况。当然,尽可能防患于未然总是好的。但是,误以为自己已经预见和消除了所有可能的不良事件并能万事大吉,这是最要命的。一方面要采取行动以预防那些能够预防的事情,另一方面要确保系统在整体上能够从任何未曾预料到的重创中恢复过来。

1.1 瞄准正确的目标

大多数软件都是为软件开发实验室或QA部门的测试工程师设计的。其设计和构建的目的,是为了通过诸如这样的测试——“顾客的姓氏和名字都是必需的,但中间名的首字母是可选的”。这些软件的目标,是能在QA所营造的人工环境中(而不是在现实世界的生产环境中)运行正确。

今天的软件设计类似于20世纪90年代早期的汽车设计,它们都与现实世界脱节。那些汽车在凉爽舒适的实验室中被设计出来,模型和CAD图纸看起来都很绝妙。那些曲线完美的汽车,在巨型风扇前发亮,在稳定气流中低鸣。处在这种宁静空间里的设计师所做出的设计,既是那么地优雅、复杂、精巧,又是那么地脆弱、不中用,并且最终早早夭折。如今大多数的软件架构和设计,都在同样干净和不接地气的环境中进行着。

一辆汽车看起来很漂亮,但它能在路上行驶的时间却少于在店里陈设的时间,这种车有人要吗?当然没人要!人们想要的是专为现实世界设计的汽车,它的设计师应该知道:超过换油里程之后,司机会再继续行驶5000公里才会去换油;磨损到只剩下最后十六分之一胎纹厚度的旧胎,必须和新胎一样工作良好;当一手拿着鸡蛋麦满分三明治,另一手拿着手机时,司机会猛踩刹车。

当系统通过QA测试后,是否就能拍着胸脯说系统已为进入生产环境做好了准备?仅通过QA测试并不能证明系统在未来3~10年的适用性。这个系统可能是软件中的丰田凯美瑞,可以连续正常运行数千小时;或者可能是软件中的雪佛兰Vega(一款在公司自家测试道路上跑得断为两截的汽车);抑或是软件中的福特Pinto(一款连平常追尾都易引爆起火的汽车)。几天甚至几周的测试,不可能说明该系统未来几年会怎样。

制造业的产品设计师一直在追求“可制造性设计”。这种设计产品的工程方法能够让人们以低成本和高质量的方式制造产品。而在这个时代之前,产品设计师和制造商都各自生活在自己的世界里。那些无法拧动的螺钉、容易混淆的零部件,以及本可利用现成零件进行替代的定制零件,都是受这两个世界之间高墙影响的设计的具体体现。这些设计不可避免地导致了低质量和高成本。

今天,我们正面临类似的状况。我们无法交付合格的新系统,因为我们一直在接听请求技术支持的电话,试图解决之前匆忙交付的系统所遭遇的问题。软件行业的“可制造性设计”,就是“为生产环境而设计”。我们虽然不会将设计交给制造商,但会将完成的软件交给运维部门。我们既需要设计一个个彼此独立的软件系统,也需要设计由相互依赖的系统所组成的整个生态系统,从而以低成本和高质量的方式进行运维工作。

1.2 应对不断扩大的挑战范围

在客户机/服务器系统盛行的那段轻松悠闲的日子里,系统的用户也就几十或几百人,并发用户最多也只有几十个。今天,活跃用户的数量常常大于整个大洲的人口数量。这指的可不只是南极洲和大洋洲!第一个拥有10亿用户的社交网络已经诞生,而且这也绝对不会是最后一个。

对系统正常运行时间的要求也提高了。相比曾经专属于大型机及其管理员的著名的“五个9”(99.999%),现在即便是最普通的商务网站,也期望能达到“24乘7乘365”(这个说法一直困扰着我。作为工程师,我认为应该要么说“24乘365”,要么说“24乘7乘52”)。显然,考虑到软件如今的规模,我们已经取得了长足的进步。但是随着用户触点和系统规模的增加,系统遭到破坏的方式也会翻新,环境会变得更加恶劣,人们对缺陷的容忍度会变得更低。

这个正在不断扩大的挑战范围(即快速地构建软件,以达到低成本构建、低成本运维,并且对用户友好),要求我们持续改进架构和设计技术。当把适用于小型WordPress网站的设计,应用于大规模的事务性分布式系统时,会出现重大的系统失效问题。后面会谈一些重大的系统失效案例。

1.3 多花5万美元来节省100万美元

很多事情都岌岌可危:项目的成功、股票期权或分红、公司的生存,甚至手中的饭碗。那些以通过QA测试为目标的系统,通常都需要高昂的持续投入,这包括运维、停机和软件维护所带来的成本。这样的系统永远都无法实现盈利,更不要说帮助公司获得净利润(只有当系统所创造的收入超过其自身的构建成本时,才能实现)。这些系统所表现出的低可用性,会直接导致公司收益受损,并间接导致品牌形象受损。

在忙碌的软件开发项目中,轻易就能做出“用前期低成本开发,换取后期高成本运维”这样的决策。但只有在团队的预算和交付日期都固定的情况下,这样做才有意义;从甲方花钱开发软件的角度看,这是一个糟糕的决策。因为如果系统不被取消或报废,那么在其整个生命周期中,运维时间要远比开发时间长。为了节省一次性的开发成本,却要耗费无尽的运维成本,这样做没有意义。事实上,从财务角度看,反其道而行之会更有意义。假定系统每次发布时都需要5分钟的停机时间,该系统会使用5年,且每月发布一个新版本(虽然大多数公司希望能够更频繁地发布新版本,但此处仅作非常保守的假设),这样就可以计算一下该系统停机时间的预期成本,并考虑未来5年的货币利率。这样计算下来,成本大概为100万美元(300分钟的停机时间,保守地按每分钟产生3000美元的成本计)。

现在假设可以投资5万美元以创建构建流水线和部署流程,从而实现不停机发布。这样做至少可以避免100万美元的损失,而且可以提高系统部署频率,有利于占领更多市场份额。如果仅看其20倍的投资回报率,那么大多数首席财务官都不会介意花费区区5万美元!

设计决策和架构决策,也是财政决策。在做出选择时,必须着眼于实施成本和下游成本。能同时从技术和财政的视角看问题,是本书的一大要点。

1.4 让“原力”与决策同在

早期决策会对系统的最终形态产生巨大的影响。最早做出的决定可能是最难以反悔的。那些关于系统边界和子系统划分的早期决策,会影响团队结构、资金分配、项目集管理结构,甚至工时表代码。团队的任务分派决定了系统架构的雏形。非常具有讽刺意味的是,早期决策恰恰是在信息最不完备的时候做出的。团队在启动项目时,最不了解软件的最终架构,却偏偏要在那时必须做出一些最不可能更改的决定。

必须承认,我是敏捷开发的支持者。注重尽快交付和渐进式改进,能让软件快速上线。由于只能通过生产环境,才能了解软件如何响应来自现实世界的请求,因此应该提倡尽快发布软件,以获得反馈并从中学习。即使是在敏捷项目中,也需要有远见才能做出最好的决策。这好比设计师必须使用“原力”{![作者借用科幻电影《星球大战》所虚构的“原力”(一种超自然而又无处不在的神秘能量场),来比喻软件发布与现实世界的互动关系。——译者注]}去看未来,才能选择最稳健的设计。虽然不同的设计方案通常具有相近的实施成本,但这些方案在整个软件生命周期中的总成本,却截然不同。因此重点是要考虑每个方案对系统可用性、容量和灵活性的影响。本书会展示数十种能对开发阶段下游产生影响的设计方案,以及各种有益和有害方法的具体示例。这些例子都来自我所遇到过的真实系统。其中的大多数都曾让我辗转难眠。

1.5 设计务实的架构

一般来说,存在两种不同类型的架构。一种类型的架构侧重于更高层次的抽象,以便于跨平台移植,并且基本不会与诸如硬件、网络、电子和光子这些混乱的细节产生直接关系。这种架构的极端形式产生了下面描述的“象牙塔”。在极具库布里克风格的整洁的房间里,坐着冷漠的大人物,每面墙上都装饰着一个个方块和箭头。从象牙塔中传出来的命令降临到一个个辛劳的程序员头上:“中间件应该永远用JBoss!” “所有的UI都应该使用Angular 1.0来构建!” “现在的一切,以及过去和将来的一切,都要永远保存到Oracle中!” “你不应该搞Ruby!”如果有人曾经咬紧牙关编写符合“公司标准”的代码,而用其他技术来做却能轻松10倍,那么他就是象牙塔架构师的受害者。没心思倾听程序员心声的架构师,肯定也没心思听取用户的意见。这样的结果已经有目共睹:当系统崩溃时,用户会为此欢呼,因为至少他们可以有一段时间不必使用它了。

相比之下,另一种架构师不仅会和程序员打招呼,而且也把自己当作程序员。这种架构师会毫不犹豫地审视一个个抽象,如果发现不适用就会舍弃。这样务实的架构师更可能讨论诸如内存使用情况、CPU的需求、带宽的需求,以及超线程和CPU绑定的优缺点等问题。

象牙塔架构师最享受绝对完美的最终状态,但务实的架构师会不断思考变化中的状态:“如何在不重新启动的情况下进行部署?” “需要收集哪些指标?如何对它们进行分析?” “系统的哪个部分最需要改进?”

当象牙塔架构师的工作完成之后,系统不能再做任何改进,系统的每个部分都将完美地扮演自己的角色。与之相反,务实的架构师所设计的系统,其中每个组件都足以满足当前的负荷;并且,当负荷随着时间的推移发生变化时,架构师知道要替换哪些组件。

对于务实的架构师,本书为其备好了强大的武器。对于能坚持读到这里的象牙塔架构师,本书或许能吸引他们去掉几层抽象,以便重新获得软件、硬件和用户这三者之间重要的交集:生产环境的生存法则。当系统终于发布时,架构师、用户和公司都将会更加快乐!

1.6 总结

软件只有运行在生产环境中才能产生价值。开发、测试、集成和规划……这些在上线前所做的一切,都仅仅是前奏。从系统的最初发布,到持续成长,再到不断进化,本书会讨论这些阶段在生产环境中的生存法则。第一部分将讨论稳定性。为了更好地理解如何避免软件崩溃所导致的各种问题,让我们首先看看造成航空公司停飞的软件缺陷。

回到目录

你可能感兴趣的:(Release It! 第2版中译稿试读:赞誉、致谢、前言及第1章生产环境的生存法则)