云原生模式
译者序
- 云原生是一种行为方式和设计理念,究其本质,凡是能够提高云上资源利用率和应用交付效率的行为或方式都是云原生的
- 云原生应用追求的是快速构建高容错性、弹性的分布式应用,追求极致的研发效率和友好的上线与运维体验
ServiceMesher社区
第1部分 云原生上下文
1 什么是“云原生”
ChaosKong演习
- Netflix如何能够恢复得如此之快?答案是冗余
图1.1演示了3个区域,每个区域包含4个可用区
- 图1.1AWS将其服务划分为区域和可用区。区域对应地理地区,而可用区在单个区域内提供进一步的冗余和隔离
- 云原生软件的设计目的是预测故障,并且即使当它所依赖的基础设施出现故障,或者发生其他变化时,它也依然能够保持稳定运行
让面向失败的设计成为它们构建、交付和管理软件过程中的一个组成部分 失败是正常规律,而不是例外
可以容忍应用程序出现短暂不可用情况的日子已经一去不复返了。世界是始终在线的。没有人希望计划外的停机出现,其影响已经达到了惊人的水平。例如,2013年《福布斯》估计,亚马逊在一次13分钟的意外停机事故中损失了近200万美元。
- 通过部署冗余组件来应对不可避免的故障,并设置隔离机制来防止故障在整个系统中引起连锁反应。而且,还必须把软件设计成能够在不停机的情况下完成计划事件(例如,升级)
缩短反馈周期
- 同样至关重要的是频繁发布代码的能力。在激烈的竞争和不断增长的消费者期望的双重驱动下,应用程序更新已经从每月数次发展到每周数次,有时甚至一天数次。让用户感到兴奋毫无疑问是有价值的,但是持续发布新版本的最大动力是降低风险
- 今天的应用程序需要支持至少两种移动设备平台(iOS和Android)和桌面系统(仍然占很大一部分使用比例)
互联设备(物联网)
- 互联网不再仅仅将人类与系统连接起来,如今,数以亿计的设备通过互联网连接,使得它们能够被连接的其他实体监控甚至控制
- 数据量正在不断增加,数据源分布得更加广泛,而软件的交付周期正在缩短
- 如果没有人使用新的数据,那么这些数据就没有价值。今天的应用程序必须越来越多地使用数据,通过更智能的应用程序为客户提供更高的价值
- 你的软件需要7×24小时提供服务。你需要频繁地发布新版本,以便快速满足用户的新需求。用户的移动应用需求和始终处于连接的状态,促使你的软件需要处理比以前更多、数量波动更大的请求。而连接设备(物联网)形成了一个空前庞大的分布式数据结构,需要新的存储和处理方法。这些需求,以及对一个运行这些软件的新平台的需求,直接导致了一种新的软件架构风格的出现,即云原生软件
图1.4用户对软件的需求推动云原生架构和相应管理方式的发展
图1.5从架构和管理方面我们理解了云原生软件的核心特征:它是高度分布式的,必须在不断变化的环境中运行,并且软件本身也在不断地发展、变化
- 定义云原生软件是高度分布式的,必须在一个不断变化的环境中运行,而且自身也在不断地发生变化
- 核心特征
- 高度分布式
- 不断变化
AdrianCockcroft曾经是Netflix的首席架构师,现在是AWS云架构战略(CloudArchitectureStrategy)的副总裁,他曾经谈到过操作一辆汽车的复杂性:作为一名司机,你必须控制汽车在街道上穿行,并且确保不与执行同样复杂任务的其他司机相接触。[7]之所以能够做到这一点,是因为你已经形成了一个思维模型
2 在生产环境中运行云原生应用程序
- 即使是一个代码优秀、已经开发完成的软件,仍然很难做到以下两点:
- 部署软件
- 保持运行
- 如果没有一种机制来为从开发到测试、预发布和生产提供完全相同的环境,那么在一个环境中能够良好运行的软件,很容易在不经意间会依赖于另一个环境中缺少或者不同的东西
你们公司一般在什么时候发布软件?是在“休息时间”完成的吗,例如,周六凌晨2点?这种做法之所以普遍,是因为一个简单的事实:部署通常充满危险。在升级期间需要停机或者部署时引起意外停机都是很正常的,而停机的代价是昂贵的
据说平均每一秒amazon.com就会发布一次代码到生产环境中。你可能会质疑在自己的业务中是否需要进行如此频繁的发布。当然,你可能不需要每天进行86000次发布,但是频繁发布能够给业务带来更好的敏捷性和可实施性
- 何时进行下一次软件发布依赖于商业决策,而不是由一个复杂、不可预测的软件开发过程决定的。例如,假设你了解到一个竞争对手计划在两周内发布一个与你的新产品类似的产品,公司因此决定立即发布自己的产品
- 这种迭代式的流程还提供了另一个重要的好处。当可以将“准备部署”的软件版本经常提供给客户时,你就有机会收集反馈,并用来改进产品的后续版本
图2.7持续交付特性允许由业务部门(而不是IT部门)来决定何时交付软件
- 漫长的发布流程会给软件交付过程带来巨大的风险,业务部门缺少控制何时将产品发布到市场的能力,而企业则常常处于既要面对短期市场压力,又要实现提高软件质量、增强软件功能这一长期目标的两难境地
- 快速迭代为系统释放了大量的压力。持续交付的出现,使得业务部门可以决定如何以及何时将产品推向市场
- 在开发期间构建并通过回归测试的JAR文件,就应该是部署到测试环境、预发布环境和生产环境中的同一个JAR文件
图2.11我们期望的结果是能够让运行在标准化环境中的应用程序保持一致。注意,应用程序在所有环境中都是相同的,运行时环境在生命周期的各个阶段中都是标准的
- 安全部署的核心是并行部署
图2.13数据会告诉你如何并行部署应用程序的多个版本。你可以通过数据对访问应用程序的流量
- 进行控制,从而可以在生产环境中安全地部署新的软件
- 路由是并行部署的一个关键因素,而路由算法属于软件的一部分。有时算法很简单,比如将流量按照一定百分比发送到新的版本,也可以通过对基础设施的一些组件进行配置来实现路由
- 版本控制、指标、路由和组件化,都是开发人员在设计和构建应用程序时必须考虑的。云原生软件的要求远不止这些(例如,在架构中考虑降级以避免故障在整个系统中蔓延),但这些都是安全部署的关键因素
- 一个能够自我修复的系统,其正常运行的时间比每次出故障都需要人工干预的系统要长得多。将部署作为一种新的期望状态,可以极大地简化部署过程并降低风险。坚持“变化是一定的”的思维模式,可以从根本上改变在生产环境中管理软件的方式
- 企业需要具备持续交付的能力,才能在当今的市场竞争中获胜
3 云原生软件平台
- 所有对自治的讨论都包含两部分:团队自治,可以让团队避免烦冗的流程和大量协调工作,快速地迭代和部署应用程序;应用程序自治,即在应用程序自己的环境中运行多个微服务,同时支持独立开发并降低级联失败的影响。它们的确能带来这些好处,但是随之产生的是一个由分布式组件组成的系统
- 注意其中的两个地方:
- 每个团队负责的模块不重叠。这一点非常重要,也是平台能够支持更加频繁的部署的主要原因之一。但是,只有正确设计了各层边界上的合约,才能实现这种效果
- 每个团队“拥有”一个具体负责的产品,以及这个产品的整个生命周期
图3.12正确地抽象能够让平台团队和应用程序团队形成自治,每个团队都负责部署、配置、监控、伸缩和升级各自的产品
- 有了正确的合约之后,应用程序团队和平台团队都是自治的。每个团队都可以在不与其他团队进行大量协调的情况下,完成自己所负责的任务
- 只有实现部署到生产环境这个过程的自动化,才能实现持续交付。是否成功取决于软件开发生命周期的早期阶段
第2部分 云原生模式
6 应用程序配置:不只是环境变量
- 永远不要在查询字符串上传递密码,应该在HTTP头信息或者正文中传递
- 永远不要在日志文件中输出密码的值
- 在配置存储中,要对敏感的信息进行加密
- 使用环境变量进行配置非常适合于系统配置数据
- 可以使用Kubernetes等云原生平台,将环境配置的值传递给应用程序
- 配置服务器(例如,SpringCloudConfigurationServer)可以用来注入应用程序的配置值
7 应用程序生命周期:考虑不断的变化
图7.4最好在启动应用程序的时候应用配置。大多数应用程序的框架都是这样做的
- 从开发人员的角度来看,如果要更新运行中的应用程序的配置或者版本,蓝/绿升级应该是最简单的方法。运行中的版本称为“蓝色”版本,希望部署的新版本称为“绿色”版本
- 首先,有一个负载均衡器为所有蓝色实例分配流量
- 在下一步中,要部署相同数量的新的绿色版本实例,但是仍将所有生产环境的流量路由到蓝色实例
- 然后,可以向绿色实例分配一些流量来检查它们运行是否正常,通过验证之后,就可以将所有流量从蓝色版本切换到绿色版本
图7.5当应用程序无法同时运行多个版本时(即多个版本不能作为单个逻辑实体来运行),可以使用蓝/绿升级
图7.7在决定使用蓝/绿升级和滚动升级时需要考虑的一个因素是资源需求。请注意,在蓝/绿升级期间,帖子服务API所需要的资源翻了一倍,而滚动升级仅仅略微增加了一点点资源需求
- 日志和指标。作为一名软件开发人员,你需要确保日志和指标中能够包含足够诊断问题的信息,这一点至关重要
- 模拟可能的失败场景
8 如何访问应用程序:服务、路由和服务发现
- 优先考虑可用性而不是一致性
9 交互冗余:重试和其他控制循环
- 面向失败设计。这是云原生软件的口头禅,我希望你在阅读本书的过程中能够时刻谨记
- 面向失败设计最基本的模式之一,是实现回退的方法,即当主逻辑失败时执行的代码。当然,当软件无法正常工作的时候,正确的做法是返回一个错误信息
10 前沿服务:断路器和API网关
- 通过定义断路器的三种状态(闭合/Closed、打开/Open或者半开/HalfOpen)来理解这种行为
- 断路器的理想状态是“闭合”:流量正在通过断路器流向断路器所保护的服务
- 断路器位于流量途中,并寻找出现的故障。少量故障不是问题;实际上,对此类“漏洞”的抵御能力是云原生良好设计的一部分。当故障率变得过高时,断路器的状态将变为“打开
- 当断路器处于“打开”状态时,不允许流量通过该断路器所保护的服务。如果服务因为请求负载过多、不堪重负而开始出现故障,或者间歇性的网络中断引起故障,那么停止处理请求可能会使服务恢复到正常状态
- 经过一段时间后,如想再次尝试请求该服务,以查看其是否已经恢复,可以通过将断路器置于“半开”状态
- 在半开状态下,断路器将允许单个请求或者少量请求通过该服务,从而对服务进行测试
- 如果测试请求成功,则断路器将切换回闭合状态。如果测试失败,则断路器将切换回打开状态,并等待更长的时间
图10.2通过三个状态对断路器的操作进行建模,并定义它们之间相互转换的条件或者事件。当断路器闭合时,流量可以自由通过。当断路器断开时,请求将无法到达服务。半开状态是一种瞬时状态,表示断路器可以被重置为闭合状态
- 必须清楚任何类型的“成功”响应都要比完全失败的信息更好
图10.8API网关位于所有服务的前面,是配置和执行策略的地方
- 高度分布式的系统导致了新的弹性模式,例如我们刚刚介绍的重试,并且会对服务带来不同的负载配置文件。与以前相比,服务上的负载更加难以预测。你需要保护服务免受意外和极端流量的影响
- Zuul可以使用或者嵌入Netflix微服务框架中的其他几个组件,包括Hystrix(断路器)、Ribbon(负载均衡)、Turbine(指标度量)等
12 云原生数据:打破数据单体
- 云原生软件是冗余的、可适应的、模块化的和动态可伸缩的
- 事件载荷(payload)相关的几个方面
- 事件载荷的规则1一个被发布到事件日志中的事件,应该完整地进行描述
- 事件载荷的规则2对于事件日志来说没有标准的事件模型。生产者可以控制所传递事件的数据格式,而消费者应该适配该格式
- 事件载荷的规则3所有发布到事件日志的事件都必须有一个相关的结构(schema),供所有相关方访问,并且必须对该结构进行版本控制
书
- 《设计数据密集型应用程序》:作者是一名计算机科学研究员,也是ApacheKafka的创始人之一。我强烈推荐这本书!
相关文章
- 在 Go 里用 CGO?这 7 个问题你要关注!
- 9款优秀的去中心化通讯软件 Matrix 的客户端
- 求职数据分析,项目经验该怎么写
- 在OKR中,我看到了数据驱动业务的未来
- 火山引擎云原生大数据在金融行业的实践
- OpenHarmony富设备移植指南(二)—从postmarketOS获取移植资源
- 《数据成熟度指数》报告:64%的企业领袖认为大多数员工“不懂数据”
- OpenHarmony 小型系统兼容性测试指南
- 肯睿中国(Cloudera):2023年企业数字战略三大趋势预测
- 适用于 Linux 的十大命令行游戏
- GNOME 截图工具的新旧截图方式
- System76 即将推出的 COSMIC 桌面正在酝酿大变化
- 2GB 内存 8GB 存储即可流畅运行,Windows 11 极致精简版系统 Tiny11 发布
- 迎接 ecode:一个即将推出的具有全新图形用户界面框架的现代、轻量级代码编辑器
- loongarch架构介绍(三)—地址翻译
- Go 语言怎么解决编译器错误“err is shadowed during return”?
- 敏捷:可能被开发人员遗忘的部分
- Denodo预测2023年数据管理和分析的未来
- 利用数据推动可持续发展
- 在 Vue3 中实现 React 原生 Hooks(useState、useEffect),深入理解 React Hooks 的