目录

云原生模式-设计拥抱变化的软件二

云原生模式–设计拥抱变化的软件(二)

目录


本文将手把手的展现一个应用的云原生改造过程,以便大家理解云原生开发模式。

一、云原生模式(帖子聚合网站为例)

帖子聚合网站是本文假设的一个项目,现在你是一个爱做饭的程序员,为了收集菜谱关注了很多的美食博主,为了及时了解博主的推文你设计了一个菜谱收集网站,这个网站由3个服务构成:帖子聚合服务、关注数据库、帖子收集服务。

https://i-blog.csdnimg.cn/blog_migrate/9ea761427d4b35dfd182723214f289ae.png

我们发现这个服务的调用流程非常简单,只需要6步即可完整展示这个服务的全部调用过程。

1、你访问帖子聚合服务

2、帖子集合服务向关注博主数据库发送查询请求,查询你关注了哪些博主

3、关注博主数据库响应帖子聚合服务的请求,返回你关注的博主列表

4、帖子聚合服务收到响应后,带着关注博主列表向帖子收集服务发出对这些博主主页列表的爬取请求

5、帖子收集服务爬取对应博主的菜谱主页,将爬取内容返回给帖子聚合服务

6、帖子聚合服务将帖子收集服务返回的内容返回给你

是吧,以上流程清晰明了而简单,但有没有发现其中存在诸多调用关系,任何一个服务异常都会导致最终的帖子聚合服务不可用,在生产环境这是无法现象的。

https://i-blog.csdnimg.cn/blog_migrate/72bbb4104c750e32ce8811d01ea7e35b.png

我不是危言耸听,上图便是Netflix( 网飞 )某服务的调用关系,当你点击Netflix( 网飞 )主页上的某个按钮一个巨大的嵌套调用任务便被触发,而我们从概论学的角度分析,假设一个服务必须要调用2个下游服务,每个下游服务的可用性的75%,此时这个前端服务的可用性是多少?

75%?

不!

是56.25%!!

以此类推,假设有4个后端服务的情况下,这个前端应用的可用性更劣化为31.64%!!!

所以我们知道在现代大型应用中保证每个应用的可用性是如何重要了吧?

二、正式开始我们的云原生应用设计

2.1事件驱动微服务:不只是请求/响应

https://i-blog.csdnimg.cn/blog_migrate/5593e8340da6b95d473ad07cc47a7398.png 如图所示,常见的调用关系有2种,请求/相应与事件驱动。

https://i-blog.csdnimg.cn/blog_migrate/9a2007218d7e3f79e7b59d9b47f2041f.png

请求 / 响应:请求响应模型使得服务间强依赖,任何一个下游故障都会导致请求返回异常,在这模式是强依赖于客户端与服务器的同时可用性,任何一方的工作异常都会导致请求无响应或无法发出请求。

https://i-blog.csdnimg.cn/blog_migrate/8d1a616409f2d77be28b7797aa2909dd.png

结合前文假设的例子我们知道,假设数据库的读取失败,那后续的帖子收集以及给客户段的相应就都无从谈起了。

https://i-blog.csdnimg.cn/blog_migrate/5ad1704cc3bde6100849332e239e2e8d.png

事件驱动:下游主动触发上游刷新,使得消费者与生产者解耦合,可以类比路由的触发更新机制,下游更新路由后主动向上游传递变更内容。我们更可以在事件的生产者与事件的消费者中间设置一个事件缓存,这样又可以实现事件驱动的异步化,无需同时关注事件生产者与事件生产者的同时可用性,假设某一方不可用时,由于事件存储的存在任何信息都不会被丢失直到事件消费者读取了相关事件日志。

2.2应用程序冗余:水平伸缩和无状态

https://i-blog.csdnimg.cn/blog_migrate/de782d86b4b02ea1ed4d7cd1c769dfc8.png

通过前文我们知道,单节点部署应用的缺陷所以我们痛改前非使用了多实例部署应用,如上图所示,不过你以为这就万事大吉了?不~还远远没有,一下我简单说明2个问题。

https://i-blog.csdnimg.cn/blog_migrate/84ba655c85188c097ad83ff3aa5c0e5f.png

为保证实例的实时多副本我们又需要引入健康检查与实例编排机制,避免譬如基础架构网络、超融合基础架构故障情况下某实例异常推出集群导致服务接入容量的下降,同时这个检测、重建过程又是全自动业务无关性的。 https://i-blog.csdnimg.cn/blog_migrate/d8f5bf0d3e7a2aea94d6683bd12bc1b4.png

云原生应用程序都会部署许多实例,而程序开发者需要保证多实例输出结果的一致性。需要关注请求历史、系统环境、应用配置等对输入的影响,因为这些输入变量都会导致输出结果的差异。

2.2.1应用程序冗余:云环境中的有状态服务

https://i-blog.csdnimg.cn/blog_migrate/5f5151949899ded4c447a24e6957f824.png

首先我们知道,状态一词在很多地方都会出现而本文主要描述的是数据的持久化,想要数据持久化既可以存储到服务本身也可以借助如图的外置token stron统一存储token,避免多次调用时前端token状态不一致的问题

https://i-blog.csdnimg.cn/blog_migrate/d1f604141f3961ec55d7544249dacc3a.png

常见解耦单体程序间的状态关系方案,使用外置数据库方式,数据库进行前端服务的状态持久化,前端服务无需存储任何业务数据,随存随用只需要保障数据库的高可用即可。

https://i-blog.csdnimg.cn/blog_migrate/f8050c7f6a4641dc5193e60dd82eda4a.png

2.2.2不可变的基础设施:应用程序配置

  • 为什么要讨论配置

动态伸缩 — 增加和减少应用程序实例的数量。应用程序实例的增减,应在不影响业务发布前提下完成,目的是实现应用程序实例的业务无关性上线配置。我们一定希望任何情况下我们扩容的应用实例的拿来就可以用的,而不是等人工是进入应用实例配置。

  1. 基础设施变化会导致配置变化

应用与基础设施解耦合,在基础设施故障、变更、升级场景下也要保障应用的可用性

https://i-blog.csdnimg.cn/blog_migrate/0387df654ae97c3776a87ed094b3bed0.png

https://i-blog.csdnimg.cn/blog_migrate/1b2c7cd9d1eac8d4009e8d410d05f321.png

上图便说明了如何在业务不停的场景下进行OS升级,具体流程我不在赘述。

2.2.3不可变的基础设施:不只是环境变量

零停机时间更新应用程序配置–引入应用程序配置层、环境中存储配置。在环境变量中配置应用程式无外乎是一个业务源代码无关性的很好方法,即实现了业务代码的0改动又配置了应用程序,一举两得。

https://i-blog.csdnimg.cn/blog_migrate/4d84525d250533af6e984916d079a77d.png

将属性文件打包入可部署的镜像中,为不同镜像编译不同的属性文件也是一个很好的主意。如下图,sprint框架提供@value注解简化从环境变量取值的过程。

https://i-blog.csdnimg.cn/blog_migrate/6125b1243cc74767947032729f8cd67f.png

2.2.4不可变的基础设施:程序配置层

为了满足零停机时间大前提下更新应用程序配置,程序员们引入应用程序配置层,在环境变量中存储配置。

结合K8S云原生平台,在应用程序实例启动前,K8S通过部署清单API为应用程序实例定义环境变量,使得固化在源代码中的方法获取到正确的值。如果结合sprint框架的其它方法,比如调用sprint cloud配置服务器的HTTP接口更可以配合源代码控制平台进行配置的版本管理。

将属性文件打包入可部署的镜像中,为不同镜像编译不同的属性文件。如下图,结合K8S云原生平台,在应用程序实例启动前,K8S通过部署清单API为应用程序实例定义环境变量,使得固化在源代码中的方法获取到正确的值。如果结合sprint框架的其它方法,比如调用sprint cloud配置服务器的HTTP接口更可以直接配合源代码控制平台进行配置的版本管理。

https://i-blog.csdnimg.cn/blog_migrate/3295fa84fe023e24a6480087c053ad89.png