[TOC]
服务网格基础
我们这部分的内容大概有以下几个内容:
- 微服务的出现及治理方式演进
- 程序架构风格与微服务
- 单体架构
- 分布式架构:SOA、MSA 这两个为比较主流的微服务架构
- 分布式架构治理模式演进
- ESB → Microservices → Cloud Native
- 服务网格的迭代
- 微服务基础
- 康威定律
- 微服务及其生态系统
- 服务网格
- 基本功能及其演进简史
- 主流实现
- 云原生时代的服务网格
1 程序架构概述
- 架构(Architecture)一词源于建筑领域,用于指规划、设计和建造建筑物的过程及产物;引入计算机领域后,软件架构就成为描述软件规划设计的专有名词;
- 简言之,软件架构是有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计
- 架构的形式与特点
- 以文档和代码呈现:架构既包含设计过程,也包括设计的产物,可以是各类设计文档、设计图,也可是一些技术验证代码、Demo 或其它相关的程序;文档是设计的载体,而代码是系统功能实现的载体;
- 架构服务于业务:即架构的首要功能是服务于业务功能,因此,架构设计需要一定的前瞻性来容纳业务的变动;
- 架构影响团队的组织形式:业务的拆分方法和技术框架的选择必然会影响研发团队的组织形式,反过来,研发组织的结构和成熟度也会对最终所采取的技术架构产生重要的影响;
- 架构存在于每一个系统:每一个已经实现并运行的系统,必然是特定架构设计的载体;
- 每个架构都有特定的架构风格
- 架构需要不断地发展演进
1.2 架构风格
- 典型的企业级应用系统或互联网应用大多都是通过 Web 提供一组业务服务能力,它通常包括
- 运行于服务器端,以后端编程语言构建的业务逻辑处理部分;
- 用于存储业务数据的关系数据库或其它类型的存储系统;
- 提供给用户操作的、运行于浏览器或APP中具有UI的业务逻辑展示和输入部分;
- 根据软件系统在运行期的表现风格和部署结构,大体可以将其粗略地划分为两类
- 单体架构(巨石程序):整个系统的所有功能单元整体部署到同一进程(所有代码可以打包成一个或多个文件)
- 进一步细分:单体模式、MVC模式、前后端分离模式、组件模式和类库模式等;
- 分布式架构:整个系统的功能单元分散到不同的进程,然后由多个进程共同提供不同的业务能力;很显然分布式架构就是将一个大的程序系统进行分裂,放到多个不同的应用程序实例中实现,并且协同起来工作,这种就称为分布式架构,分布式架构中有两个非常典型的代表性产品
- 面向服务的架构(SOA)
- 微服务架构(MSA)
1.2.1 分布式应用的需求
Bilgin Ibryam 在其一篇文章中将分布式应用的需求分为生命周期、网络、状态和绑定四个方面
也就是说看上去很简单,把应用程序组建成一个团队把他研发出来运行即可。但是如果我们将该程序的功能分割出来放到不同的程序组件中运行,而这些每个程序组件如果做一个独立进程还需要跨网络协同的话,这件事将会突然变得复杂起来,也就是说他的复杂度和难度呈指数级上升
如果想要构建一个合理的生产能使用的分布式架构,大体上我们需要解决这么几个问题:
- 生命周期管理:
- 程序的研发、构建、打包、分发、部署、扩缩容、销毁、等等这些其实都是程序生命周期管理中的组成部分
-
编写业务功能时,编程语言会指定生态系统中的可用库、打包格式和运行时(runtime)等
-
例如,Java使用.jar打包格式,它将依赖到的所有Maven库视为生态系统,并使用JVM作为运行时
-
随着发布周期变得更短,生命周期中更为重要的是以自动化的方式部署的能力、从错误中恢复的
能力和扩展服务的能力
- 这组能力广泛地代表了应用程序生命周期的需求
- 网络:
- 从某种意义上说,如今几乎所有的应用程序都是分布式应用程序,它们都需要网络,但现代分布式系统需要从更广泛的角度去掌控网络
- 分布式应用在构建是会假设网络是可靠的,但事实上网络本身很不可靠,一共有 8 个关于网络的悖论,因此我们为了能够克服网络本身不可靠的特性,以及增强应用程序分布式部署中各种各样的功能和协同工作的特性,我们大体上也要解决网络以下几个问题
- 服务发现
- A/B 测试
- 金丝雀发布
- 抵抗局部故障解决方案
- 错误恢复
- 超时断路
- point-to-point(点对点通信),pus/sub(一对多通信)
- 网络安全和可观测性,在分布式架构中可观测性需要从三个维度来观察:1、指标监控;2、日志监控;3、性能监控,以及链路追踪等相关功能
- 为了满足需要,我们甚至会在这个类别中包含不同的消息交换模式、点对点和发布/订阅方式,以及智能路由机制等
- 只要是分布式应用网络必须实现这些功能,否则构建出来的分布式架构漏洞百出。
- 状态:(应用程序本身从单体角度来说共享内存很容易实现,但是如果跨进程则这个难度将面临挑战)
- 此处的状态是指服务的状态;一般我们认为,服务最好是无状态的,但管理服务的平台本身却是需要状态的(即有状态)
- 工作流管理
- 幂等性,无论多少次调用结构都是一样
- 调度
- 缓存
- 应用程序自身状态
- 因此我们必须要解决服务状态管理问题,尤其是各种需要内部通信的分布式应用,我们通常就需要一个底层的管理平台。
- 平台负责实现可靠的服务编排和工作流、分布式单例、临时调度(即周期式作业 cron job)、幂等性、状态的错误恢复、缓存等,这些功能都依赖于底层的状态,也都需要治理系统来帮我们解决
- 绑定:
- 分布式系统的组件不仅要相互通信,而且要和现代的或以往的旧式外部系统集成,这就要求连接器(connector)能够转换各种协议、支持不同的消息交换模式,如轮询、事件驱动、请求/应答、转换消息格式,甚至能够执行自定义的错误恢复过程和安全机制
- 连接器:应用程序组件和组件之间用于通信,至少说被访问端需要 API 接口
- 消息格式转换比如 web 服务一般接收 json 格式数据
- 消息路由,等等
基于以上需求,我们的分布式架构的治理模式大体上经历了 3 个非常具有典型性的 3 代:
- SOA/ESB
- MicroServices
- Cloud Native
1.2.2 一图了解分布式架构治理模式演进
SOA/ESB(企业服务总线):
- 为了让多个服务彼此之间通信的时候不至于在点对点,因此出现了类似于中心交换机,每一个服务都把自己需要调用或者能够调用的时候都基于总线来通信
- 这样虽然降低了多个服务之间的治理难度,但是总线自身却成为了瓶颈。而且也背离了分布式的初衷
Microsevices(微服务):
- 对微服务架构阶段来讲,我们依然要求每个服务点是(smart endpoints)智能端点也就是能够自动服务发现、服务注册、超时、重测等等不是通过链路来解决的而是靠每个服务点自身能力解决
-
而管道称为 (dumb pipes) 哑管道:也就是说通信、网络本身不需要太大的智能性
Cloud Native(云原生阶段):
- 到了云原生阶段就发生了改变,这时候称为智能平台(smart platform),用于处理微服务的 生命周期、网络、绑定、状态 这 4 个问题,这个时候所有需要智能实现的功能都通过一个有着智能性的网格自身来解决,而这就引出了所谓的服务网格
- 而服务被称为哑服务(dumb services):服务本身不需要处理 生命周期、网络、绑定、状态 这 4 个问题,而是将 4 个问题都寄托到了 smart platform(智能平台),而服务本身则只负责处理业务问题
1.2.3 SOA 提出的分布式系统的构建原则
- 各服务由规范定义的标准化 API 提供,这些 API 通过服务描述的定义将服务消费者的实现与服务提供者的实现进行分离
- 服务本身应该按照契约优先规则而不是代码优先规则来开发
- 服务之间的间通信基于面向文档的消息,而非特定语言的RPC协议,从而将服务同其实现语言解耦
- 各服务彼此独立,它们在时间、空间、技术和团队上是松散的耦合关系,其实在 SOA 阶段以及提出此概念
- 各服务应该是无状态的,这样就可以灵活调用它们,而无须关心不同上下文中的会话状态
- 各服务应该是自治和自包含的,以便它们可以独立部署、版本控制、自我管理和恢复
- 各服务可以被发现和组合,例如
- 可以通过使用服务注册中心来实现服务发现,从而可以将服务消费者动态绑定到服务提供者,让二体之间能够组合起来使用
- 比如单体架构由于多个服务在同一个代码中通过函数调用即可实现,但是对于分布式架构来说我们要将多个单体服务拼接起来完成一个统一的功能并流程的进行工作,那么这里面服务注册,服务消费、服务绑定 等等都是一个按需完成的功能
- 来自不同系统的业务服务可以在业务流程中进行编排和组装
1.2.3.1 SOA
SOA 是早期建设企业 IT 生态系统的架构指导思想中最典型的一种,它把服务视作基本的业务功能单元,由平台中立性的接口契约定义;SOA 目前的实现方式有两种:分布式服务化和集中式管理
- 分布式服务化:常见的实现服务有 Dubbo、Finagle 和 ICE 等;
- 集中式管理:以 ESB 为基础支撑技术,较流行的商业实现有 WMB (IBM)、OSB (Oracle),开源实现有Mule、ServiceMix 和 OpenESB 等;
无论是哪一种产品实现,SOA 当中都有两大基石,因为服务与服务之间通信对分布式来讲是最至关重要的,比如下面两个就是服务通信最关键的两个逻辑:
- RPC:远程过程调用,是一种通用目的系统通信手段,它把被调用者称为服务提供者(Provider),把调用者称为服务消费者(Consumer),并将对象转换为便于网络传输的二进制或文本数据的过程称为序列化(Serialization)
- 常见的 RPC 技术有 Cobra、RMI、WebService、JSON-RPC、XML-RPC、Thrift、Protocol Buffer 和 gRPC等;
- 按照调用方式,可分为四种模式:RR(Request-Response)、Oneway(单向调用)、Future(异步)和Callback(回调);
- MQ:N个系统之间互相通信时,利用MQ可以进行系统间解耦,并借助于失败策略、重试等机制完成错误处理;
- 点对点模式
- 发布订阅模式
1.2.4 传统的分布式中间件 ESB
图一:
图二:
图三:
早期的 SOA 系统的服务间通信多采用“点对点”模型,服务调用和集成逻辑也通常嵌入到了应用程序中实现,如上图
- 适合服务数量较少的系统,简单、高效
- 但是服务数量增多到一定程度时,连接路径和复杂度急剧增加,所以为应对这种治理挑战而引入了 ESB ,但是 ESB 是反分布式的如图二
ESB提供服务间的连接、转换和中介功能
- 而且 ESB 自己在某个程度上会成为问题如图三,因为 ESB 提供服务件的连接转换和中介把有些功能沉入到 ESB 总线当中去解决了,既容易导致 ESB 中的滥用
-
所以说将企业内部系统和各种服务连接到服务总线上以后,实现服务彼此之间是松散的,但是服务总线自己却变得越来越复杂了
1.2.4.1 ESB 的局限性
从技术上讲,ESB 架构将业务逻辑与服务集成分离,从而实现更好的集中式服务治理,但随着应用规模的增大和服务数量的增加,也暴露了严重的问题,因为刚才我在上面也提到过 ESB 是反分布式的
- 强调甚至过分强调业务系统的可重用性,结果导致大量的服务集成实现逻辑沉入了ESB,很难维护、迁移和扩展,进而成为 ESB 的沉重负担
- 基于集中式消息处理系统,主要挑战是单体架构以及业务逻辑和平台之间紧密的技术耦合,这反而又导致了技术和组织的中心化
- 开发并部署服务到这样的系统中时,它和分布性系统框架产生的紧密耦合,限制了服务的进一步演化
但是由于 ESB 是一个反分布式架构不符合分布式的初衷,所以最后又走到了 MSA 分布式微服务架构
1.2.5 分布式微服务架构MSA
Microsevices 简称为 MSA
随着互联网的快速大规模增长,企业IT架构的重点从传统的记录系统转变为参与系统,这类的参与系统必须支持快速迭代和低成本试错,因而“微服务”的概念甫一出现便甚得人心
- 记录系统的代表:企业资源规划ERP和供应链管理SCM等
- 参与系统的代表:在线电商系统、网上银行系统等
微服务的规范定义
- 最早出现于2011年的“微服务”在2014年由 Martin Fowler 通过一篇著名的文章发扬光大;该文章可抽象出以下几个关键点
- 由一些独立的服务共同组成应用系统
- 每个服务单独部署、独立运行在自己的进程中
- 每个服务都是独立的业务(通常实现一个功能所以这个叫做微服务)
- 分布式管理
- 遵循低耦合、高内聚的原则
微服务中的调用链路较之传统的分布式系统长了很多,于链路上发生故障的概率也必然随之增大,且存在性能损耗,于是,系统规划时必须考虑如何进行雪崩预防、功能降级、超时、重试、熔断、服务隔离等服务管理;
微服务强调的基本原则
- 核心思想是通过应用功能的拆分和解耦来简化业务系统的实现
- 强调将应用功能划分为一组松散耦合的服务,每个服务都遵循 单一职责(一个服务对应一个功能) 原则
- 每个服务都可以独立部署和交付,极大地提高了业务敏捷性
- 每个服务都可以独立伸缩,以适应互联网的规模
潜在的问题
- 将一个大的单一应用拆分成多个微服务,使得IT系统的研发协作、交付和维护变得更加复杂
- 幸运的是,容器技术、DevOps 和 微服务架构 的自然融合,使得微服务落地成为更加简便的实现可能,恰恰就是容器与编排技术的流行,才使得他成为这种可能
- 微服务虽然降低了开发难度,但是增加了运维难度
SOA 向 MSA 进化的代表产品
- Apache Dubbo (RPC 代表产品)
-
Spring Cloud (接口代表产品)
2 微服务实践细节
微服务落地过程中,必须要仔细解决如下问题
- 客户端如何访问这些微服务?所以需要服务发现的方式来解决
- 各服务的实现上可能是无状态的,因而需要统一进行用户的登录信息和权限管理(OAuth)
- 在服务和客户端之间提供一个代理(API GateWay)来统一管控流量,当然 API gateway 不是解决一个内部路由的问题,还包括日志、追踪、指标、统一对用户进行的建权 等等都可以通过 API gateway 来管理
- 服务彼此间如何通信?
- 同步调用:REST 或 RPC
- 异步消息调用:点对点、发布订阅等等
- 如何进行服务发现?
- 客户端发现
- 服务端发现
- 如何应对服务故障?
- 重试
- 限流
- 熔断
- 负载均衡
- 降级(本地缓存)
2.1 微服务治理框架
所以我们为了克服服务通信和治理的复杂性,例如服务发现、融合、节流和端到端跟踪的挑战,需要用到专门的微服务治理框架
- 微服务框架,如 HSF、Dubbo 或 Spring Cloud,将这些能力打包成代码库,形成SDK
- 程序员开发微服务时,将这些代码库或者框架内置于应用程序中,并随应用程序一起发布和维护
存在问题:库模型可能会抽象出满足微服务架构所需要的特性,但代码库本身仍然是一个需要维护的组件
- 学习和使用库需要相当程度的精力投入
- 本质上,服务通信和治理是横向连接不同部门的系统,因此与业务逻辑是正交的;但是,在微服务架构中,实现和生命周期是与业务逻辑耦合的,因为我们需要使用到 SDK 然而需要将 SDK 打包到程序本身,微服务框架 SDK 的升级会导致整个服务应用的重新构建和重新部署
- 代码库通常与特定语言绑定,因此难以支持企业应用程序的多语言实现
可以说微服务治理框架问题在早期就是通过 Dubbo 或 Spring Cloud 来进行解决的,既然 SDK 与业务逻辑二者之间是正交的,那么我们就将二者之间拆开,不需要放到同一个应用程序中间来完成,然后人们发现了问题试着通过 Sidecar 来解决问题,
2.2 Sidecar 边车
下一个合乎逻辑的步骤
- 将库中的功能整合进 Network Stack 是不可能的,许多从业者找到的解决方案是使用一个小巧的透明代理来实现
- 使用 Sidecar 以辅助进程的方式,在应用程序旁边提供高级网络功能
Sidecar
- 让服务集中解决业务逻辑的问题,网络相关的功能则与业务逻辑剥离,并封装为独立的运行单元并作为服务的反向透明代理,从而不再与业务紧密关联
- 换句话说,微服务的业务程序独立运行,而网络功能则以独立的代理层工作于客户端与服务之间,专门为代理的服务提供熔断、限流、追踪、指标采集和服务发现等功能
在 Sidecar 中就是要把那些服务功能的实现如微服务的 SDK 与业务逻辑既然是正交的;既然跟业务逻辑本身没有强耦合关系,那我们就将 Dubbo 或 Spring Cloud 独立成一个独立的进程来运行岂不是更好,那因此我们在每一个应用程序的周边都不是一个 sidecar , 并且让这个 Sidecar 专职从事来完成我们要想构建分布式应用当中那些高级的网络问题。
因此我们将这一部分独立出来,有一个单独的应用程序不管它使用什么语言,并且通过某一个特定的协议接口将他共享出来或暴露出来,比如就通过 http 协议暴露出来。
因此我们的业务逻辑当需要与微服务体系相互协同的时候,业务逻辑只需要与 Sidecar 模式运行的组件进行交互就可以了,也就是说无论业务逻辑去请求别人的时候,或者去响应客户端请求的时候都一律通过 sidecar 代理来完成
所以从某种角度来讲我们的 Sidecar 就成了专用的运行于每一个服务周边的代理应用程序,这个代理负责完成这个业务逻辑程序所需要完成的各种功能如:服务发现、熔断、限流、降级、超时 等等,全靠 Sidecar 一个组件来实现
而且业务程序与 Sidecar 二者之间的耦合关系是松耦合的,是基于 http 或者其他网络协议来协同的,这样一来就意味着只要业务程序支持该网络协议对外发起请求他就能够被这个 Sidecar 所代理,这些网络功能被作为一个独立的辅助进程来完成,运行在应用程序的旁边来提供高级网络功能,并让二者之间解耦这样一解耦就会发现刚才所面临的巨大问题都解决了
- 业务逻辑服务开发的时候不再需要 SDK,而是只专注于自己的业务逻辑即可
- 当需要使用 SDK 或者网络功能的时候只需调用 Sidecar 即可,只需调用代理
所以 熔断、限流、追踪、指标采集和服务发现等功能完全不需要业务逻辑服务实现,也不需要借助 SDK 完成,多种语言开发只需要遵循接口规范即可,不在被语言层面所绑定,也不需要每个程序员在开发微服务的时候去学习 SDK 反而只需要理解接口契约即可
因此各微服务框架的此类解决方案往往与基础设施组件一同使用,例如 Zookeeper(服务注册) 或者 Eureka(服务发现)等
那么既然能够借助 sidecar 的方式,在每个应用程序周边来部署这样的一个方案,由此就形成了所谓的服务网格
3 Service Mesh(服务网格) 的雏形
服务网格是处理服务到服务通信的专用基础结构层。它负责通过构成现代云本地应用程序的复杂服务拓扑可靠地交付请求。在实践中,服务网格通常实现为一组轻量级网络代理,这些代理与应用程序代码一起部署,而应用程序不需要知道
上图绿色格子:业务逻辑应用
上图蓝色格子:sidecar
服务网格是什么?如上图我们分布式应用中每一个应用都是有业务逻辑和负责高级网络功能的 sidecar 来协同部署完成,然后这些 sidecar 与 sidecar 之间才有通信,应用层于应用层之间不会直接通信而是都需要 sidecar 来代理通信,因此这个时候 sidecar 之间就形成了支撑应用程序各种高级网络功能的专用的网络或成为网格
将服务治理能力下沉到基础设施中,并将它们部署为服务消费者和服务提供者的独立流程:
- 每个服务都使用一个专用的代理Sidecar来完成高级网络功能
- 各服务间仅通过 Sidecar 代理互相通信
- 各代理之间形成了一个网状网络,2017年,William 为其创建一个专用定义,并称之为Service Mesh
3.1 新一代Service Mesh
如上图多个 sidecar 代理服务。需要知道每个 sidecar 的分发、流量发送等功能,这时候就需要一个叫做 control plane(控制平面)来实现集中管理
为 Service Mesh 中各独立工作的代理提供集中式的“控制平面”
- 实际的服务流量仍然直接在各代理之间完成,但控制平面知道每个代理实例
- 控制平面使代理能够实现诸如访问控制和指标收集之类的事情
- 控制平面负责下发配置
我们可以发现服务网格最早期其实是集中在这个 sidecar 身上,而有了控制平面以后这个 sidecar 通常所形成的网格叫做 data plane(数据平面)
istio:只是为 envoy 所组成的服务网格提供了一个 control plane(控制平面),所以 istio 有两个关键组件:
- envoy:用于实现 sidecar 的相关功能。也就是 data plane(数据平面)
- istio 本身
什么是服务网格:
流量管理依然都是在各个 sidecar 之间实现的,但是我们控制平面知道每个代理的实例,将来自定义配置的时候只需要在 control plane 所提供的 API 进行配置即可,然后将我们的目标配置提交给 control plane ,再由 control plane 向下自动发放,这就是所谓的服务网格,所以带有控制平面的服务网格我们成为新一代的 service mesh
4 康威定律
4.1 康威定律(1)
设计系统的组织由于受到约束,这些设计往往表现为组织内部沟通结构的副本。 ——Melvin Conway(1967)
- 换句话说,组织设计系统来反映他们自己的沟通结构;
目前康威定律被引申为四条定律:
- 组织设计的产品,等价于组织的沟通结构;
- 罗马并非一天建成的,学会先解决首要问题;
- 时间再充裕,也不可能将一件事情做完美,但总有时间做完一件事情;
- 忽略次要的需求,“先完成,再完善”;
- 线型系统和线型组织架构间有潜在的异质同态特性;
- 创立独立的子系统,减少沟通成本;
- “线性子系统”,或“分布式子系统”对应着不同的产品结构
- 演进中,较之小系统,大系统具有更强的分解倾向;
4.2 康威定律(2)
“线性子系统”,或“分布式子系统”对应着不同的产品结构
划分为前端团队、后端开发团队和DBA团队的组织,其最终产品形态通常表现如下,前端、应用逻辑、存储系统,这必然是一个单体应用
而基于业务边界划分为多个小团队的组织,各团队按照业务目标去构建小的系统或产品,其最终产品形态如下,每个团队分别有各自的 UI、应用逻辑、存储系统,所以可以想象在微服务当中每一个服务都有单独的存储系统,这和单体结构就大不相同,没有统一的集中系统
5 MSA架构
微服务如何体现“微”的特性?
- 体积小:微小的甚至不超过100行代码
- 开发周期短:必须在两周内完成开发或迭代
Netflix 的架构师 Adrian Cockcroft 认为,微服务架构是面向服务的架构,它们由松耦合和具有边界上下文的元素组成;
而世界知名的软件大师 Chris Richardson 在 “Microservices Patterns” 一书中通过一种三维可扩展模型“扩展立方体”给出了不一样的定义
- 把应用程序功能性分解为一组服务的架构风格,每一个服务都是由一组专注的、内聚的功能职责组成;
- 微服务的大小并不重要,更好的目标是将精心设计的服务定义为能够由小团队开发的服务,并且将会时间最短,与其它团队协作最少;
- 微服务架构应用程序通过一些小的、松耦合的服务组织在一起,从而提升开发效率、可维护性、可测试性和可部署性;
6 微服务逻辑
微服务与单体架构最显著的区别在于,单体应用程序只是单个应用程序,而微服务则是许多小的应用程序协同工作;
如上图,在微服务中有多个组件:
- Microservice: service 本身、每一个服务都有自己的前后端、都有自己的存储,也可能是调用其他的远程服务、也可能是服务彼此之间的调用
- Management:用于微服务的治理系统,负责在节点上放置服务、识别故障、跨节点重新平衡服务等;
- Service Discovery:用于服务发现
- API Gateway:用于将多个 Microservice(微服务) 暴露,客户端不能直接调用目标服务,而是调用API网关,并由API网关将调用转发到后端相应服务; API网关可能聚合来自多个服务的响应并返回聚合响应;
- ldentity Provider:用于实现用户的身份认证,鉴权等各个问题,从而实现辅助 API Gateway
- CDN
所以我们的微服务架构大概有以上几个组件组成
6.1 微服务架构的好处
微服务架构有如下好处
- 使大型的复杂应用程序可以持续交付和持续部署
- 每个服务都相对较小且容易维护
- 服务可以独立部署
- 服务可以独立扩展
- 微服务架构可以实现团队的自治
- 更容易实验和采纳新技术、
- 更好的容错机制
6.2 微服务架构的弊端
微服务构架也存在一些显著的问题和弊端
- 服务的拆分是一项挑战;
- 分布式系统带来的各种复杂性,使开发、测试和部署变得更困难;
- 跨服务的事务可能需要Saga来维护服务间的数据一致性,同时还要使用API组合或CORS视图实现跨服务查询
- 依赖高度自动化的基础设施
- 自动化部署工具,例如Netflix Spinnaker
- 产品化的PaaS平台
- Docker容器编排平台,例如Kubernetes或Docker Swarm
- 服务间通信存在不同程度地延迟
- 当部署跨越多个服务的功能时需要谨慎地协调更多团队
- 开发者需要思考到底应该在应用的什么阶段使用微服务构架
6.3 中台战略和微服务
在这个中台战略当中我们可以看到无论怎么来构建微服务,到今天为止我们的整个架构当中通常由是以下几个组成:
- iaas 云平台:解决底层的资源管理和按需分配问题
- Paas 云平台:解决持续交付、资源调度 等相关问题
- 核心业务层
- 应用
6.4 服务分层
7 微服务总体技术架构
如上图就是我们整个微服务的架构
7.1 微服务网关
微服务网关是微服务中的必要组件主要作用在于服务路由、反向路由、认证安全、限流熔断、日志监控等
7.2 服务发现和路由体系
7.3 同步通信机制 RPC vs REST
7.4 服务框架和治
7.5 监控体系和监控分类
7.6 基于环境治理和多环境的持续交付流水线
7.7 微服务架构面临什么样的问题?
对于分布式应用来讲我们通常需要解决 4 个维度问题,其中 K8S 给我解决了生命周期管理的问题,而服务网格解决的是和高级网络相关的问题
服务间通信管理将面临巨大挑战,网络通信其实是微服务架构的痛点
分布式计算存在 8 个谬论(Fallacies of Distributed Computing Explained) :
- 网络是可靠的
- 网络延迟是0
- 带宽是无限的
- 网络是安全的
- 网络拓扑从不改变
- 只有一个管理员
- 传输成本是0
- 网络是同构的
很显然这 8 个谬论决定了我们在分布式开发的时候,对于程序来讲无需考虑彼此之间通信网络数据包丢失,网络可能会有延迟等等,但是这些事情必然是存在的因此为了确保正在的达成微服务开发的述求、我们必须要解决这些问题,但是这些问题也不能一次性消除掉,只能通过一些辅助手段来降低他们之间的影响从而达成目标
所有服务网格设计的初衷就是在于帮组应用服务克服这些问题,比如在网络不可靠的情况下我们发出一个请求迟迟不能响应该怎么办,由此就有了所谓的超时重试等这样的技术
微服务体系下服务治理面临的挑战:
事实上,分布式环境中,网络的不可靠性无法忽略,可靠地解决如下问题,方能确保结果落地
- 服务注册和服务发现
-
客户端重试
-
可配置的超时机制
-
负载均衡
-
限速
-
熔断
-
服务间路由
-
异常点检测
-
健康状态检查
-
流量整型
-
流量镜像
-
边缘路由
-
按需路由
-
A/B测试
-
内部发布
-
故障注入
-
统计和度量
-
日志
-
分布式跟踪
服务网格,也正是这种需求下逐步演进而形成的新一代解决方案
8 服务网格
服务网格(Service Mesh)
- 概念源于Buoyant公司的CEO Willian Morgan的文章“What’s a service mesh? And do I need one?”;
- 是指专注于处理服务间通信的基础设施,它负责在现代云原生应用组成的复杂拓扑中可靠地传递请求;
- 治理模式:除了处理业务逻辑的相关功能外,每个微服务还必须实现此前单体应用模型中用于网络间通信的基础功能,甚至还包括分布式应用程序之间的通信环境中应该实现的其它网络功能,例如熔断、限流、应用跟踪、指标采集、服务发现和负载均衡等
- 实现模型经过演进三代:内嵌于应用程序、SDK和Sidecar
8.1 非侵入式“服务治理”
其实现在的服务治理分为下面三代:
第一代:服务治理能力内嵌在业务代码中典型技术:SOA、ESB:
第二代:服务治理能力抽象到统一 SDK 实现典型技术:Spring Cloud、Dubbo:
第三代:服务治理能力归一到服务网格:
8.2 服务网格的基本功能
- 控制服务间通信: 熔断、重试、超时、故障注入、负载均衡和故障转移等;
-
服务发现:通过专用的服务总线发现服务端点;
-
可观测:指标数据采集、监控、分布式日志记录和分布式追踪;
-
安全性:TLS/SSL通信和密钥管理;
-
身份认证和授权检查:身份认证,以及基于黑白名单或 RBAC 的访问控制功能;
-
部署:对容器技术的原生支持,例如Docker和Kubernetes等;
-
服务间的通信协议:HTTP 1.1、HTTP 2.0和gRPC等;
-
健康状态检测:监测上游服务的健康状态;
8.3 数据平面与控制平面(Control Plane & Data Plane)
数据平面组件:
- 数据平面就是 sidecar 代理的实现,目前来讲最主流的就是 envoy ,为网格中的所有正在运行的数据平面实例提供策略和配置,从而将所有数据平面联合构建成为一个分布式系统,但是数据平面本身不负责任何数据包的交换
-
数据平面:完成系统中的每个数据包或请求,负责服务发现、健康检查、路由、负载均衡、身份验证/授权和可观测性等;
- 控制平面:为网格中的所有正在运行的数据平面提供策略和配置,从而将所有数据平面联合构建为分布式系统,它不接触系统中的任何数据包或请求;
控制平面组件:
- 工作负载调度程序:借助于底层的基础设施(例如kubernetes)完成服务及其Sidecar运行位置的调度决策;
- 服务发现:服务网格中的服务发现;
- Sidecar 代理配置 API:各 Sidecar 代理以最终一致的方式从各种系统组件获取配置;
- 控制平面UI:管理人员的操作接口,用于配置全局级别的设置,例如部署、身份认证和授权、路由及负载均衡等;
8.4 服务网格特点
Service Mesh 解决方案极大降低了业务逻辑与网络功能之间的耦合度,能够快捷、方便地集成到现有的业务环境中,并提供了多语言、多协议支持,运维和管理成本被大大压缩,且开发人员能够将精力集中于业务逻辑本身,而无须再关注业务代码以外的其它功能
一旦启用Service Mesh,服务间的通信将遵循以下通信逻辑,只有理解了一下几点才知道 envoy 本身的配置是干嘛用的:
- 微服务彼此间不会直接进行通信,而是由各服务前端的称为 Service Mesh 的代理程序进行;所以我们能够明白在 sidecar 中既要配置正向代理可能还需要配置反向代理,
- 正向代理:代理自己的服务提供访问,ingressgateway(入站网关)
- 反向代理:代理其他服务访问自己,egressgateway(出站网关)
- Service Mesh 内置支持服务发现、熔断、负载均衡等网络相关的用于控制服务间通信的各种高级功能;
-
Service Mesh 与编程语言无关,开发人员可以使用任何编程语言编写微服务的业务逻辑,各服务之间也可以使用不同的编程语言开发;
-
服务间的通信的局部故障可由 Service Mesh 自动处理;比如超时、熔断、中断 等
-
Service Mesh 中的各服务的代理程序由控制平面(Control Plane)集中管理;各代理程序之间的通信网络也称为数据平面(Data Plane);
-
部署于容器编排平台时,各代理程序会以微服务容器的 Sidecar 模式运行;
8.5 典型企业应用云原生架构升级实践:容器+服务网格快速实现灰度发布与治理
传统服务网格痛点1:灰度发布
➢ 只能通过 LB 上对入口服务进行灰度发布,不方便对内部单个微服务进行灰度发布。
➢当基于 SDK 做微服务的灰度发布,为了支持某些规则,SDK和业务代码需要进行大量修改。
云原生服务网格收益1:
➢ 可以对入口和内部单个和多个微服务进行灰度发布
➢灰度发布不涉及业务代码修改
➢ 提供灵活的权重或者内容的流量规则
➢ 可以和流水线配合,完成新版本的灰度发布
传统服务网格痛点2:SDK 等治理能力升级
➢ SDK 版本升级时,需要所有微服务版本跟着升级,即使服务业务代码未涉及修改。
➢ 业务团队经常要陪着框架团队一起升级验证
云原生服务网格收益2:
➢ 治理能力升级只需基础设施升级即可,业务的镜像等发布件不受影响
➢ 在容器+网格集群上一键可以升级网格管理面和数据面
传统服务网格痛点3:多语言
➢ 服务中除了大量Java开发的微服务外,还包含大量C、C++和老的单体应用需要服务治理,无法使用SDK完成
云原生服务网格收益3:
➢ 服务网格与业务代码解耦,支持多种语言的治理
➢ 对老系统访问也可以进行治理,无需老系统改造,老系统可以分步骤改造。
传统服务网格痛点4:部署、运维需要额外开发
➢新增服务或更新环境信息时需要大量配置
➢ 需要自研不停机部署,需要对每个服务独立配置及频繁变更
➢ 发布件版本管理不便
➢ 扩缩容不便
云原生服务网格收益4:
➢ Kubernetes容器服务提供敏捷的部署运维能力
➢ Kubernetes 滚动升级保证业务不断服
➢ 基于容器镜像的软件分发(包含应用和环境依赖)
➢ 细粒度资源编排调度
➢ 极致弹性
9 服务网格和 K8S 间的关系
Kubernetes:
- 解决容器编排与调度的问题
-
本质上是应用的生命周期管理工具
-
为服务网格提供基础支撑
Service Mesh:
- 解决分布式应用间的通信问题
-
本质上服务通信治理工具
-
是对K8S在网络功能方面的扩展和延伸
10 Service Mesh 技术标准
10.1 Service Mesh 产品发展史
10.2 Service Mesh 代表产品
在实现上,数据平面的主流解决方案有Linkerd、Nginx、Envoy、HAProxy和Traefik等,而控制平面的实现主要有Istio、Nelson和SmartStack等几种
- Linkerd
- 由 Buoyant 公司于2016年率先创建的开源高性能网络代理程序(数据平面),是业界第一款Service Mesh 产品,引领并促进了相关技术的快速发展
- Linkerd使用Namerd提供控制平面,实现中心化管理和存储路由规则、服务发现配置、支持运行时动态路由等功能
- Envoy
- 核心功能在于数据平面,于 2016 年由 Lyft 公司创建并开源,目标是成为通用的数据平面
- 云原生应用,既可用作前端代理,亦可实现 Service Mesh中 的服务间通信
- Envoy 常被用于实现 API Gateway(如Ambassador)以及 Kubernetes 的 Ingress Controller(例如gloo等),不过,基于 Envoy 实现的 Service Mesh 产品 Istio 有着更广泛的用户基础
- Istio
- 相比前两者来说,Istio发布时间稍晚,它于2017年5月方才面世,但却是目前最火热的 Service Mesh 解决方案,得到了 Google、IBM、Lyft 及 Redhat 等公司的大力推广及支持
- 目前仅支持部署在Kubernetes之上,其数据平面由Envoy实现
10.3 服务网格的部署模式
如上图:
- 部署方式一:
- host 上我们部署一个 linkerd proxy ,然后里面的 pod 自己本身是没有 sidecar ,而是统一通过 linkerd Proxy 来管理进出该主机的流量,虽然这种部署方式更便捷更轻量,但是在流量管理上很难分辨
- 部署方式二:
- 对于第二种部署每个 pod 各自有各自的 proxy ,而 envoy 一设计出来就更倾向于这种
服务网格的部署模式有两种:主机共享代理及 Sidecar 容器
- 主机共享代理:
- 适用于同一主机上存在许多容器的场景,并且还可利用连接池来提高吞吐量
- 但一个代理进程故障将终止其所在主机上的整个容器队列,受影响的不仅仅是单个服务
- 实现方式中,常见的是运行为 Kubernetes 之上的 DaemonSet
- sidecar 容器
- sidecar 代理进程注入每个 Pod 定义以与主容器一同运行
- Sidecar进程应该尽可能轻量且功能完善
- 实现方案:Linkerd、Envoy和Conduit
11 云原生时代的微服务分布式体系究竟该怎么搞
生命周期:
- 容器和 Kubernetes 将打包、分发和部署应用程序的方法演化成了同编程语言无关的格式
- 对 Kubernetes 来说,需要管理的最小原子单元是容器,并且,它专注于在容器级别和流程模型上交付分布式原子单元
- Kubernetes 在管理应用程序的生命周期、健康检查、恢复、部署和扩展等方面都做得很出色,但是在运行于容器内的分布式应用的其他方面却没有做得很好,例如灵活的网络,状态管理和绑定
- 尽管 Kubernetes 拥有有状态的工作负载、服务发现、cron 作业及其他功能,但是所有这些原语都是在容器级别的,并且在容器内部,开发人员仍然必须使用特定于语言的库实现更高级的功能
- 这其实就是推动诸如 Envoy、Linkerd、Consul、Knative、Dapr 和 Camel-K 等项目的原因
- 换句话讲 K8S 只适合用来做部署编排和调度的功能
网络:
- Kubernetes 提供的围绕服务发现的基本网络功能打下了良好的基础,但这对于现代应用程序来说却仍嫌不足
- 随着微服务数量的增加和部署的加快,在不改动服务的情况下,对更高级的发布策略,管理安全性,指标,跟踪,从错误中恢复,模拟错误等等方面的需求变得越来越具有吸引力,并产生了一种新的软件类别,称为服务网格
- 服务网格将网络相关的关注点从包含业务逻辑的服务转移出来,放到一个单独的运行时中,该运行时可能是Sidecar 容器,也可能是节点级代理
- 服务网格可以执行高级路由、协助完成测试、处理某些方面的安全性问题,甚至可以支持特定于应用的协议(例如,Envoy支持Kafka、MongoDB、Redis和MySQL等)
- 除了典型的服务网格外,还有其它项目,例如Skupper等,它们证实了将网络能力放入外部运行时代理的趋势
- Skupper通过第7层虚拟网络解决了多集群通信的难题,并提供了高级路由及连接能力
- 但是,它没有将Skupper嵌入到业务服务运行时中,而是在每个Kubernetes名称空间中运行一个共享的Sidecar实例
状态:
- 状态的管理比较困难,因而应该将其委派给专门的存储软件和托管服务
- 缓存、工作流管理、单例、幂等、事务管理、cron作业触发器和状态化错误处理等都隶属状态管理范畴
- 对那些建立在云环境上的服务来讲,状态化工作流的管理是必备功能,例如AWS的Step函数、Azure的Durable函数等
- 在容器化的部署中,CloudState和Dapr都依赖Sidecar模型以提供分布式应用程序中状态化抽象更好的解耦
- 未来的发展趋势中,状态管理应该会通过一个专门的 Sidecar 应用来完成
绑定:
- 微服务体系下,从应用程序中解耦分布式需求同样也会伴随着“绑定”
- 尽管,连接器、协议转换、消息转换、错误处理和安全相关的中间层都可以从应用中转移出来,但目前尚未实现,但 Knative 和 Dapr 等项目正朝着这个方向努力
- Apache Camel-K项目采用了另一种有趣的方法
- 它借助于一个智能的 Kubernetes Operator 利用来自 Kubernetes 和 Knative 附加的平台能力来构建应用程序运行时,而非在主应用程序周边运行一个 Sidecar 形式的代理
- Operator 成了惟一的代理程序,它负责提供应用所需的各种分布式系统原语
- 不同之处在于,有些分布式原语添加到了应用程序运行时中,而有些则是在平台中实现(也可能包括Sidecar)
11.1 未来的云原生架构趋势
除了生命周期之外,现在我们已然可以直接使用网络监测、状态抽象、声明性事件以及端点绑定等功能,而EIP(企业集成模式)则是该列表中的下一个元素
如上图,在核心业务之外附加 3 个 sidecar :
第一个 sidecar:istio 、数据平面 envoy
第二个 sidecar:用于解决绑定问题的 knative、
第三个 sidecar:用于解决状态问题,dapr
也就以为这将来部署业务的时候业务程序是核心,然后还需要部署三个辅助容器
如果我们把不同领域进行创新的各种云原生项目进行叠加,那么最终将得到类似下图的组合形式
- 需要注意的是,上图只是用于说明,它有目的地选择了具有代表性的项目,并把它们映射为分布式原语的一种
- 实际上,我们不会同时使用所有这些项目,因为它们中的一些是重叠的,并且工作负载模型也并不兼容