之前写过关于微服务架构的文章,发现挺受欢迎的,所以今天打算再聊聊云原生和微服务架构。
图片来自 包图网
本篇分享主要围绕以下 4 个主题进行:
- 什么是云原生?
- 为什么要用云原生架构?
- 微服务的概念
- 微服务的技术选型
什么是云原生?
①云计算和云原生
云计算不同于传统的自建机房,云计算就是将计算的抽象为基础设施然后通过网络分发。
得益于云计算的无限扩展能力,使得“云计算”就像自来水厂一样,我们可以随时接水,并且不限量,按照自己家的用水量,付费给自来水厂就可以。
以下云计算的五个基本特征:
以下是一些目前比较主流的公有云厂商:
云原生顾名思义,就是基于云计算特性所设计的应用服务,得益于云计算快速发展,基于云计算特性所设计的云原生应用相比传统的单体应用在安全性,扩展性,快速迭代,运维等各方便都有巨大的领先优势。
云原生并不是指某一种技术,它是一种架构设计理念,只要符合这种架构设计理念的应用,都可以称为云原生应用。
看看 CNCF 官方对于云原生的定义:
②容器云技术的发展
虚拟化技术的发展历史
云原生是依赖容器作为技术技术来实现的,但是容器并不是什么新潮技术,以下是容器云技术的发展历史,其中有几个关键的历史节点:
早在 2006 年的时候 Amazon 基于容器技术构建的 IaaS 平台 AWS,成为所有云计算厂商的鼻祖,由于技术领先的优势 AWS 现在依然也是云计算行业老大。
2013 年 Docker 的诞生进一步简化容器技术的使用门槛,Docker 公司自以为掌握云时代的核心技术,开始野心勃勃的有意挑战传统的云计算大厂,例如 RedHat,Google 的江湖地位,公司股价也是一骑绝尘,却不料被 RedHat 联合 Google 发布的 Kubernetes 击溃,Kubernetes 的成功让大家以为容器技术并非云时代的核心技术,容器编排才是核心技术。(备注:2020 年 K8S 官方宣布只要满足 K8S CRI 接口的容器均可以被 K8S 进行编排,Docker 被时代抛弃)
2015 年借助 Kubernetes 的成功,Google 宣布成立 CNCF 基金会,这是云原生时代的代表性的组织。致力于完善云时代的基础设施,帮助开发者构建更出色的产品
下图是 CNCF 的全景图:
为什么用云原生架构?
主要从 4 个方面来聊聊:
- 自动恢复
- 服务安全
- 弹性扩展
- 快速发布
①自动恢复
早期刚参加工作的时候接手过一个年久失修的遗留系统,这个系统有一个很神奇的 Bug 每天晚上会自动宕机,谁也不知道什么原因。
只要重启就能恢复正常,当时为了保证业务系统的正常使用,我总是在半夜爬起来重启服务器,我当时就在想:要是有一种工具可以检测到系统宕机后,就自动重启恢复就好了,这样我就可以睡一个好觉了。
这就是云原生架构想要解决的第一个问题:应用系统挂掉后,无需人工的介入,可以自动在最短的时间恢复来保证系统的健壮性。
当然除了未知的 Bug,还有诡异的异常会导致服务崩溃了,例如:
- 代码没写好,系统发生 OOM
- 服务器本身的资源不足
- 死锁,磁盘,网络等问题
- 等等……
Kubernetes Pod 应用自动恢复的三种策略:
- Always:当容器终止退出后,总是重启容器,默认策略。
- OnFailure:当容器异常退出(退出状态码非 0)时,才重启容器。
- Never:当容器终止退出,从不重启容器。
- spec:
- restartPolicy: Always # 当容器终止退出后,总是重启容器,默认策略
- containers:
- - image: nginx
- name: web
②安全性
在微服务架构的大型分布式系统,服务和服务之间是通过熔断建立安全的保护隔离机制。
云原生架构保障系统的安全性主要体现 2 个方面:
- 服务隔离
- 资源隔离
服务隔离:先来看看服务调用的安全隔离,如图:
假如服务 A 和服务 B 之间存在依赖的调用关系,它的处理逻辑如下:
- 如果服务 B 宕机或者异常下线,注册中心会发送服务 B 的状态给服务 A,服务 A 就会启动熔断保护机制。
- 服务 A 采用降级策略或者不再发送向服务 B 发送请求,避免产生调用链雪崩,同时也保护服务 A 的可用性。
- 服务 B 再次被拉起的时候,服务 A 收到注册中心对服务 B 的健康检查,恢复对服务 B 的调用或者移除降级策略。
资源隔离:云原生架构对于服务的保护机制也体现在对资源的使用上,以前多套系统共享一台主机的资源,总是容易出现木桶的短板效应。
就是只要有一个系统把主机资源占满,那么其他的系统都会因为资源不足受到影响。进而产生连锁反应,同主机上的所有系统都会崩溃。
现在基于容器部署的微服务系统,你的系统在生产环境的真实部署情况就像被关进一个个小房间里面,预先安排的资源设置就是这个服务房间的大小。
它只能在指定的大小范围内活动,就算程序内部异常导致把资源全部占用,也不会影响其他房间的小伙伴的正常活动,从而保证整个系统的可用性。
通过 Kubernetes 指定内存请求和限制的 Pod 配置文件:
- spec:
- containers:
- - name: memory-demo-ctr
- image: polinux/stress
- resources:
- limits:
- memory: "200Mi" # 内存会被限制在 200 MiB 以内
- requests:
- memory: "100Mi" # 容器将会请求 100 MiB 内存
通过服务隔离,资源隔离的方式为云原生系统提供安全和可用性,这里仅仅做一个入门的介绍,如果展开来讲的话,内容还有很多,有兴趣的同学可以自行去研究和探索。
③弹性扩展
传统的单体的应用,往往部署在机房的服务器主机内,那么自购的服务器难以应对业务快速增长,存在以下问题:
- 时间成本:采购服务器需要事先填好配置清单,走各种流程,等物流,等机器送到接上电源,估计 1~2 周都过去了。
- 空间成本:要腾出很大的空间来放置这些大家伙。
- 其他成本:24 小时开空调,专人轮班值守,机器的维护,服务下线后服务器容易闲置,闲鱼不好出手等等。
在基于云计算的基本特征所设计的云原生系统,则不存在以上这些问题,在主流的公有云厂商提供 ECS 主机基本可以任意扩展和伸缩配置,在资源使用上也提供按量付费的运行模式,有效避免对于计算资源的限制和浪费。
如下图:
④快速发布
随着类似 Kubernetes 等云原生基础设置的完善,现代应用的部署方式也跟以前大不相同。
相比传统低效的停机发布,云原生服务提供的 Rolling Update 滚动升级帮我们实现不停机升级系统的目标,对于需要快速响应市场需求的企业,快速迭代的业务系统的功能对于企业取得市场竞争力显得来说尤为重要。
KubernetesRollingUpdate 策略用于解决不停机发布的问题:
另外,我们可以通过 kubectl rollout undo 将 deployment 回滚到指定的版本,来解决微服务的快速回滚的问题。
以上就是云原生架构相比传统系统所带来的巨大优势,我们目前也是处于云时代架构演进的早期。
我个人认为,我们程序员作为知识工作者非常值得投入时间去学习下一代的主流架构设计。这将为我们带来巨大的技术优势和技术领先。
微服务的概念
①微服务的理论基础
微服务并不特指某一种具体的技术,它是一个抽象的概念,只要满足它的所有规范,那么就可以理解为你的系统实现了微服务。
②何时用微服务?
关于你的项目何时应该引入微服务架构,行业一直有两种声音:
- 方案 A 单体优先:随着架构的演进逐渐替换为微服务架构
- 方案 B 微服务优先:避免后期的大范围架构重构
其实,早在 2015 年技术大牛 Martin Fowler 在博客文章 MicroservicePremium 中就给出了具备参考性答案:
早期(2015 年左右)微服务使用成本和上手门槛很高,生产效率不如单体应用。
但是伴随系统的业务复杂度逐渐上升,单体应用的生产效率逐渐降低,在到达临界点的时候微服务的优势逐渐出现,微服务的生产效率开始超过单体应用。
所以在 2015 年的时候结合成本和收益的权衡,大多数人会选择单体优先的架构方案,后续再逐步演化成为微服务。
③Netflix OSS 的诞生
早在 2015 年的 CNCF 基金会刚诞生,社区的微服务基础设置非常不完善,Netflix+Pivotal 公司作为微服务的实践的探索者,通过应用层面提供许多微服务的基础组件来实现微服务架构。
关于 Netflix 提供的微服务全家桶解决方案称作 Netflix OSS(Open Source Software Center)。
Netflix OSS 全景图如下:
④微服务优先
Martin Fowler 在 2015 年提出的观点,显然已经不再适用 2021 的现代系统架构。
这几年随着 CNCF 的快速发展,云原生的基础设施逐渐的完善和成熟,微服务的使用成本逐年降低,微服务的实现成本已经趋向于单体,甚至未来会优于单体。
我的个人看法是,微服务如果能够解决使用和学习成本的问题,那么未来微服务也将完全取代单体应用。
从长期主义来说,任何新项目都应该优先选择微服务架构,不仅可以保证业务系统的生产效率、扩展性,还可以避免未来产生大规模的重构。
微服务的技术选型
①微服务框架选择
市面上微服务框架很多,目前行业的大公司基本都会有自己的微服务框架。
我们只看几款主流并且具备代表性微服务框架:
- Dubbo(阿里巴巴)
- Spring Cloud(Netflix)
- Kubernetes(Google)
我们通过功能对比,看看都是如何根据自己的理解实现微服务的基本理论概念。
我们将主流框架从微服务的基础关注点,运维架构,产品背景进行三方面维度的比较:
通过横向对比,我们可以看到不论是 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 并非没有缺点,我们看看它的优缺点:
总结:RBAC 角色模型+JWT 鉴权方案是目前微服务主流的安全认证体系,也能应对大多数系统对于安全认证的需求,也是目前市面上大部分的企业应用生产中的最佳实践。
④微服务的运维监控
生产就绪系统 Production Ready:说完了开发环节,最后来说说微服务是怎么运维的。
我们知道仅仅只是完成功能(Feature-Complete) 只是软件开发流程中很少的一部分,那么从完成编码到生产就绪(Production Ready),还需要经历哪些环节?
我们可以参考上图:
- 集成测试:用户功能的准确性,性能和压力测试。
- 日志管理:日志要规范,要区分:Info,Wrong,Error 等不同的等级,日志格式统一,方便日志收集,监控和排查。
- 监控预警:包含业务指标监控,应用指标监控,CPU,内存,磁盘网络 IO 监控等等,设定合理的预警信息。
- 调用链监控:呈现分布式系统的调用关系,调用性能,找到性能瓶颈,快速定位问题。
- 高可用考量:双机备份,主从备份,异地多活,容灾策略,应用弹性机制等。
当我们确保应用满足生产就绪(Production Ready)的要求,我们就可以发布到生产,交付价值了。
基于 EFK 的日志采集方案:基于容器部署的微服务架构不可能像传统应用那样通过 SSH 登录服务器上扒日志信息,所以只能采取统一的收集机制。
Kubernetes 中推荐使用 EFK (Elasticsearch+Fluentd+Kibana)采集日志。
它的工作流程如上图:
- Fluentd 会将采集的日志直接发到 ElasticSearch,中间也可以增加 kafka 作为缓存层。
- ElasticSearch 通过 Log Parser 初步解析日志,可以过滤垃圾日志。
- 通过 Kibana Dashboard 查询 ElasticSearch 显示日志。
分布式系统的服务监控方案:目前主流的微服务监控体系是通过 Kubernetes + Prometheus 来搭建。
如上图:
- 通过 Prometheus 发现 Kubernetes 服务
- 通过 Alert Manager 监控和报警 Email,SMS
- 通过 Grafana 展现和监控服务的运行各项指标
基于 Skywalking 分布式链路跟踪监控:Skywalking 是无侵入分布式链路跟踪框架,可以在不添加一行代码的前提下完成对微服务分布式系统的链路跟踪,是目前主流的分布式链路跟踪的解决方案。
2019 年 SkyWalking 成为 Apache 顶级项目,SkyWalking 的作者吴晟也因此当选为 Apache 软件基金会首位华人董事,这里就不展开讲了。
SkyWalking 工作大致工作原理如下:
SkyWalking 对分布式调用链的展示:
总结
本文从云原生的发展历史,讲述了我们程序员为什么要拥抱选择云原生。讲解了基于云计算的基础底座所衍生出来的云原生系统对传统单体应用所带来的颠覆性改变,然后讲述一些微服务的工作原理,架构布局和运维方案。
但是在真正生产级云原生应用中,远远不止要要考虑以上的内容,还有更多需要考虑的因素。
例如:
- HTTPS
- 编码规范,测试覆盖率,E2E 测试
- 监控:Log/Trace/Metrics,业务指标监控
- 持续集成:CI/CD 流水线
- 完善的 README 帮助文档
更多细节就不展开讲了,期待跟大家共同学习和交流,谢谢大家。
作者:肖斌2
编辑:陶家龙
来源:转载自公众号小二十七(ID:drak-phoenix)