本篇分享主要围绕以下 4 个主题进行:
云计算和云原生
云计算不同于传统的自建机房,云计算就是将计算的抽象为基础设施然后通过网络分发,得益于云计算的无限扩展能力,使得“云计算”就像自来水厂一样,我们可以随时接水,并且不限量,按照自己家的用水量,付费给自来水厂就可以。以下云计算的五个基本特征。
以下是一些目前比较主流的公有云厂商:
云原生顾名思义,就是基于云计算特性所设计的应用服务,得益于云计算快速发展,基于云计算特性所设计的云原生应用相比传统的单体应用在安全性,扩展性,快速迭代,运维等各方便都有巨大的领先优势。云原生并不是指某一种技术,它是一种架构设计理念,只要符合这种架构设计理念的应用,都可以称为 云原生应用, 看看 CNCF 官方对于云原生的定义:
容器云技术的发展
云原生是依赖容器作为技术技术来实现的,但是容器并不是什么新潮技术,以下是容器云技术的发展历史,其中有几个关键的历史节点
下图是 CNCF 的全景图:
主要从 4 个方面来聊聊:
自动恢复
早期刚参加工作的时候接手过一个年久失修的遗留系统,这个系统又一个很神奇的 Bug 每天晚上会自动宕机,谁也不知道什么原因。只要重启就能恢复正常,当时为了保证业务系统的正常使用,我总是在半夜爬起来重启服务器,我当时就在想:要是有一种工具可以检测到系统宕机后,就自动重启恢复就好了,这样我就可以睡一个好觉了。
这就是云原生架构想要解决的第一个问题:应用系统挂掉后,无需人工的介入,可以自动在最短的时间恢复来保证系统的健壮性。
当然除了未知的 BUG,还有诡异的异常会导致服务崩溃了,例如:
Kubernetes Pod 应用自动恢复的三种策略:
spec:
restartPolicy: Always # 当容器终止退出后,总是重启容器,默认策略
containers:
- image: nginx
name: web
Always
:当容器终止退出后,总是重启容器,默认策略OnFailure
:当容器异常退出(退出状态码非 0)时,才重启容器Never
:当容器终止退出,从不重启容器安全性
在微服务架构的大型分布式系统,服务和服务之间是通过熔断建立安全的保护隔离机制。
云原生架构保障系统的安全性主要体现 2 个方面:
服务隔离
先来看看服务调用的安全隔离,如图:
假如服务 A 和服务 B 之间存在依赖的调用关系,它的处理逻辑如下:
资源隔离
云原生架构对于服务的保护机制也体现在对资源的使用上,以前多套系统共享一台主机的资源,总是容易出现木桶的短板效应,就是只要有一个系统把主机资源占满,那么其他的系统都会因为资源不足受到影响。进而产生连锁反应,同主机上的所有系统都会崩溃。
现在基于容器部署的微服务系统,你的系统在生产环境的真实部署情况就像被关进一个个小房间里面,预先安排的资源设置就是这个服务房间的大小,它只能在指定的大小范围内活动,就算程序内部异常导致把资源全部占用,也不会影响其他房间的小伙伴的正常活动,从而保证整个系统的可用性
通过 Kubernetes 指定内存请求和限制的 Pod 配置文件:
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
limits:
memory: "200Mi" # 内存会被限制在 200 MiB 以内
requests:
memory: "100Mi" # 容器将会请求 100 MiB 内存
通过服务隔离,资源隔离的方式为云原生系统提供安全和可用性,这里仅仅做一个入门的介绍,如果展开来讲的话,内容还有很多,有兴趣的同学可以自行去研究和探索。
弹性扩展
传统的单体的应用,往往部署在机房的服务器主机内,那么自购的服务器难以应对业务快速增长,存在以下问题:
在基于云计算的基本特征所设计的云原生系统,则不存在以上这些问题,在主流的公有云厂商提供 ECS 主机基本可以任意扩展和伸缩配置,在资源使用上也提供 按量付费 的运行模式,有效避免对于计算资源的限制和浪费。如下:
快速发布
随着类似 Kubernetes 等云原生基础设置的完善,现代应用的部署方式也跟以前大不相同。相比传统低效的停机发布,云原生服务提供的 Rolling Update 滚动升级帮我们实现不停机升级系统的目标,对于需要快速响应市场需求的企业,快速迭代的业务系统的功能对于企业取得市场竞争力显得来说尤为重要。
KubernetesRollingUpdate 策略用于解决不停机发布的问题:
另外,我们可以通过kubectl rollout undo
将 deployment 回滚到指定的版本,来解决微服务的快速回滚的问题。
以上就是云原生架构相比传统系统所带来的巨大优势,我们目前也是处于云时代架构演进的早期。我个人认为,我们程序员作为知识工作者非常值得投入时间去学习下一代的主流架构设计。这将为我们带来巨大的技术优势和技术领先。
微服务的理论基础
微服务并不特指某一种具体的技术,它是一个抽象的概念,只要满足它的所有规范,那么就可以理解为你的系统实现了微服务。
何时用微服务 ?
关于你的项目何时应该引入微服务架构,行业一直有两种声音:
其实,早在 2015 年技术大牛 Martin Fowler 在博客文章 MicroservicePremium 中就给出了具备参考性答案:
早期(2015 年左右)微服务使用成本和上手门槛很高,生产效率不如单体应用,但是伴随系统的业务复杂度逐渐上升,单体应用的生产效率逐渐降低,在到达临界点的时候微服务的优势逐渐出现,微服务的生产效率开始超过单体应用。
所以在 2015 年的时候结合成本和收益的权衡,大多数人会选择 单体优先 的架构方案,后续再逐步演化成为微服务。
Netflix OSS 的诞生
早在 2015 年的 CNCF 基金会刚诞生,社区的微服务基础设置非常不完善,Netflix + Pivotal 公司作为微服务的实践的探索者,通过应用层面提供许多微服务的基础组件来实现微服务架构。关于 Netflix 提供的微服务全家桶解决方案称作 Netflix OSS(Open Source Software Center)
关于组件的详细介绍,我在 一文了解基于 Netflix OSS 的微服务架构 中也有介绍,这里就不再赘述了。
Netflix OSS 全景图如下:
微服务优先
Martin Fowler 在 2015 年提出的观点,显然已经不再适用 2021 的现代系统架构,这几年随着 CNCF 的快速发展,云原生的基础设施逐渐的完善和成熟,微服务的使用成本逐年降低,微服务的实现成本已经趋向于单体,甚至未来会优于单体,我的个人看法是,微服务如果能够解决使用和学习成本的问题,那么未来微服务也将完全取代单体应用。从长期主义来说,任何新项目都应该优先选择微服务架构,不仅可以保证业务系统的生产效率、扩展性,还可以避免未来产生大规模的重构。
微服务框架选择
市面上微服务框架很多,目前行业的大公司基本都会有自己的微服务框架,我们只看几款主流并且具备代表性微服务框架:
我们通过功能对比,看看都是如何根据自己的理解实现微服务的基本理论概念
我们将主流框架从微服务的基础关注点,运维架构,产品背景进行三方面维度的比较:
通过横向对比,我们可以看到不论是 Dubbo 还是 Spring Cloud 对比 Kubernetes 都有诸多缺点。相比阿里巴巴的 Dubbo、Netflix 的 Spring Cloud, Google 提供的 Kubernetes 才是具备完整的一站式的微服务解决方案的技术方案。如图:
如果使用住房来比喻的话,前者就像毛坯房,还要自己装修,Kubernetes 则是精装修的商品房,帮你解决所有问题,拎包入驻即可。另外,自建 Kubernetes 集群成本比较高,推荐使用公有云厂商提供的 Kubernetes 服务。
微服务和网关
如果把分布式的微服务系统比喻成一家公司的话,那么网关就是该公司的前台,当有用户要访问公司必须在前台登记确认身份,疫情期间可能还需要量一下体温什么的。这一步骤就叫 网关鉴权,根据用户描述的任务和身上携带的证明,网关用户的业务类型将用户带到所属业务范围内办公室,这一步骤就叫做 网关路由。如果用户太多一个前台处理不过来,就会多开设几个窗口来分流,这一步骤就叫做 网关层面的负载均衡。网关是微服务的大门,对于微服务至关重要。
以下是网关常见的工作方式:
除了上述的鉴权,动态路由,负载均衡,通过网关还可以实现以下高级特性:
网关是微服务的大门,因为网关对于对微服务来说至关重要,是微服务弹性伸缩的能力来源。并且网关的开发成本其实并不高,所以市场面有很多单独的网关产品,我们可以简单看看,如图:
微服务和安全认证
早期分布式单体应用的会话管理
早期的单体应用用户会话方案都是通过服务端存储 sessionid + cookid + filter 来保存和管理用户状态会话,但是这种有状态服务有很多弊端,例如服务重启用户状态丢失,难以横向扩展等等,后单体应用时代大家开始把用户会话状态放在类似 Redis 等存储中间件中,来解决系统的横向扩展和重启后会话不丢失的问题。
架构如图:
微服务中基于 Auth 的认证方案
在的微服务体系中,身份认证模块将被统一抽取出来交给单独的服务处理,该服务通常称为 Auth Service。访问令牌通常由 Auth 颁发,由网关统一鉴权,AuthService 身份认证职责的分离,可以让微服务本身更加关注业务。
基于 Auth Service 的工作逻辑如图:
不过这种基于 Auth 认证服务的方案会将所有请求发往 Auth 进行验证,认证服务承受的压力大,架构方案重,造成不必要的性能损失。其实大部分的应用系统都不需要这么严格的安全认证等级。那么有没有一种轻量级的技术是可以由认证服务颁发令牌后,不在需要依赖 Auth 鉴权,由服务自行验证令牌的有效性,这样就可以大大减少对 Auth 的鉴权请求。答案是有的。它就是目前非常流行的 JWT 鉴权方案。
JWT 结合 RBAC 角色权限模型是目前非常主流的轻量级认证方案。它的工作流程如下:
JWT 备受推崇,广泛使用的原因,是因为它在由 Auth 服务颁发令牌后,在网关即可验证令牌合法性,无需再请求认证服务,请求少,性能好。令牌本身还可以自包含少量的用户信息,JWT 大概是一串这样的编码,它由三个部分组成,你可以通过 JWT IO 这个网站对 JWT 进行解码,从而获取 JWT 中的信息:
JWT 的详细生成和解码过程就这里不在赘述了,JWT 并非没有缺点,我们看看它的优缺点:
优点 | 缺点 |
---|---|
紧凑轻量 | 一旦颁发无法吊销,只能自动过期 |
减轻 Auth 压力,简化 Auth 实现 | 包含信息越多,传输开销越大 |
总结
RBAC 角色模型 + JWT 鉴权方案是目前微服务主流的安全认证体系,也能应对大多数系统对于安全认证的需求,也是目前市面上大部分的企业应用生产中的最佳实践
微服务的运维监控
生产就绪系统 Production Ready
说完了开发环节,最后来说说微服务是怎么运维的。我们知道仅仅只是 完成功能(Feature-Complete) 只是软件开发流程中很少的一部分,那么从完成编码到 生产就绪(Production Ready),还需要经历哪些环节 ?我们可以参考下图:
集成测试:用户功能的准确性,性能和压力测试
日志管理:日志要规范,要区分:Info,Wrong,Error 等不同的等级,日志格式统一,方便日志收集,监控和排查
监控预警:包含业务指标监控,应用指标监控,CPU,内存,磁盘网络 IO 监控等等,设定合理的预警信息
调用链监控:呈现分布式系统的调用关系,调用性能,找到性能瓶颈,快速定位问题
高可用考量:双机备份,主从备份,异地多活,容灾策略,应用弹性机制等
当我们确保应用满足生产就绪(Production Ready)的要求,我们就可以发布到生产,交付价值了
基于 EFK 的日志采集方案
基于容器部署的微服务架构不可能像传统应用那样通过 SSH 登录服务器上扒日志信息,所以只能采取统一的收集机制。
Kubernetes 中推荐使用 EFK (Elasticsearch + Fluentd + Kibana)采集日志,它的工作流程如图:
分布式系统的服务监控方案
目前主流的微服务监控体系是通过 Kubernetes + Prometheus 来搭建,如图:
基于 Skywalking 分布式链路跟踪监控
Skywalking 是无侵入分布式链路跟踪框架,可以在不添加一行代码的前提下完成对微服务分布式系统的链路跟踪,是目前主流的分布式链路跟踪的解决方案,2019 年 SkyWalking 成为 Apache 顶级项目,SkyWalking 的作者吴晟也因此当选为 Apache 软件基金会首位华人董事,这里就不展开讲了,SkyWalking 工作大致工作原理如下:
SkyWalking 对分布式调用链的展示:
本文从云原生的发展历史,讲述了我们程序员为什么要拥抱选择云原生。讲解了基于云计算的基础底座所衍生出来的云原生系统对传统单体应用所带来的颠覆性改变,然后讲述一些微服务的工作原理,架构布局和运维方案。但是在真正生产级云原生应用中,远远不止要要考虑以上的内容,还有更多需要考虑的因素,例如: