什么是微服务
微服务架构模式(Microservice Architet Pattern)是近几年在软件架构模式领域出现的一个名词,其在各种演讲、文章、书籍中出现的频率已经让很多人意识到它对软件领域所带来的影响。
那么什么是微服务?
其实,很难对微服务下一个准确的定义。而实际上,从业界的讨论来看,微服务本身也没有一个十分严格的定义。不过,ThoughtWorks的首席科学家——马丁·福勒(Martin Fowler)先生,对微服务的这段描述,似乎更加通俗易懂∶
微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于 HTTP的 RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。
摘自马丁·福勒先生的博客:Microservices (martinfowler.com)
- 单体应用
- 集群
- 微服务
我所理解的微服务的本质其实就是**“解耦”**,提高各个服务的内聚,减小服务与服务之间的耦合。
单一职责
对于每个服务而言,我们希望它处理的业务逻辑能够单一,在服务架构层面遵循单一职责原则。也就是说,微服务架构中的每个服务,都是具有业务逻辑的,符合高内聚、低耦合原则以及单一职责原则的单元,不同的服务通过"管道"的方式灵活组合,从而构建出庞大的系统。
轻量级通讯
服务之间应通过轻量级的通信机制,实现彼此间的互通互联,互相协作。所谓轻量级通信机制,通常指语言无关、平台无关的交互方式。譬如,某些复杂的系统,由 Java、Ruby以及 Node 等不同开发语言实现的部分组成,不同部分之间能够采用语言无关、平台无关的方式进行交互,如下图所示:
对于微服务而言,通过使用语言无关、平台无关的轻量级通信机制,使服务与服务之间的协作变得更加标准化,也就意味着在保持服务外部通信机制轻量级的情况下,团队可以选择更适合的语言、工具或者平台来开发服务本身。
独立性
独立性指在应用的交付过程中,开发、测试以及部署的独立。
在传统的单体应用中,所有功能都存在于同一个代码库中。当修改了代码库中的某个功能,很容易出现功能之间相互影响的情况。尤其是随着代码量、功能的不断增加,风险也会逐渐增加。换句话说,功能的开发不具有独立性。
除此之外,当多个特性被不同小组实现完毕,需要经过集成,经过回归测试,团队才有足够的信心,保证功能相互配合、正常工作并且互不影响。因此,测试过程不是一个独立的过程。
当所有测试验证完毕,单块架构应用将被构建成一个部署包,并标记相应的版本。在部署过程中,单块架构部署包将被部署到生产环境或者类生产环境,如果其中某个特性存在缺陷,则有可能导致整个部署过程的失败或者回滚。
在微服务架构中,每个服务都是一个独立的业务单元,当对某个服务进行改变时,对其他的服务不会产生影响(理想情况下^_^)。换句话说,服务和服务之间是独立的。 对于每个服务,都有独立的代码库。当对当前服务的代码进行修改后,并不会影响其他服务。从代码库的层面而言,服务与服务是隔离的。 对于每个服务,都有独立的测试机制,并不必担心破坏其他功能而需要建立大范围的回归测试。也就是说,从测试的角度而言,服务和服务之间是松耦合的。
进程隔离
在单体应用中,虽然应用也会划分模块,划分层次,但他们并不是物理隔离的。这就意味着所有的模块都是运行在一个进程中的,这就导致某个模块的修改,必须停掉整个应用,然后再重新部署。同时某个模块的修改,可能会在某些不为人察觉的情况下,影响到其他的模块。
但在微服务架构中,应用程序由多个服务组成,每个服务都是一个具有高度自治的独立业务实体。通常情况下,每个服务都能运行在一个独立的操作系统进程中,这就意味着不同的服务能非常容易地被部署到不同的主机上。由于服务与服务之间是物理隔离的,因此服务部署之间是没有影响的(业务逻辑会有影响,但物理层面可以没有影响)。
微服务的本质
服务作为组件
技术多样性
业务数据独立
基础设施自动化
演进式架构
微服务不是银弹
微服务的优势,解决了传统的单块架构系统随着业务需求的快速变化而面临的挑战,使得其看起来像一个完美的解决方案。然而,获取这些优势也是有代价的,微服务在实施过程中,主要面临这下面这样一些问题。
分布式系统的复杂性
微服务架构是一种基于分布式的系统,从交付的角度出发,构建分布式系统必然会带来额外的开销。通常,分布式系统的复杂度主要包括以下几点。
- 性能 同传统的单块架构相比,分布式系统由于组件与组件的调用是跨进程、跨网络的调用,因此必然要考虑网络延迟以及带宽的影响。尤其要考虑,当某业务场景需要多个服务相互协作时,响应时间以及性能对系统的影响。
- 可靠性 在分布式系统中,由于网络、带块、节点自身的可靠性等因素,任何一次组件间的远程调用都有可能失败。而且,随着微服务数量的增多,还会出现更多的潜在故障点。因此,如何提高系统的可靠性,降低由于网络、组件等引起的单点故障率,也增加了系统构建的挑战。
- 异步 对于跨网络的调用,需要考虑异步的通信机制。我们知道,同步通信的过程一般是发送请求,接收响应并处理,整个过程实现简单,但会造成阻塞。异步通信的过程则是发送请求后立即返回,不会造成阻塞,一般适用于耗时操作的处理。但异步通信在享受非阳塞的优势的同时,也大大增加了功能实现的复杂度,并且当出现缺陷时,定位问题、调试问题的难度也更大。
- 数据一致性 在分布式系统中,为了保证数据的一致性,通常我们会考虑使用分布式事务管理。但由于分布式事务管理需要跨多个节点来保证数据的瞬时一致性,因此比起传统的单块架构的事务,成本要高得多。另外,在分布式系统中,通常也会考虑通过数据的最终一致性来解决数据瞬时一致带来的系统不可用。
- 工具 虽然现有的 IDE 以及开发工具对单块架构系统的开发支持较好,但并没有为开发分布式系统提供足够的支持。因此,相比传统的单块架构,分布式架构的开发、调试存在较大的复杂度。
运维成本
相对于单体应用或集群应用,微服务在服务较多的情况下,运维成本将会增加很多。主要包括以下一些方面:
- 配置: 主要包括应用相关的配置信息,譬如参数、依赖部分、数据库地址、缓存地址等。
- 部署 :主要包括将应用部署到指定的环境中。
- 监控与告警: 主要包括对应用的健康状况进行监控,并当发现故障时能及时告警。
- 日志收集 :主要包括日志收集,并提供搜索等方式,帮助团队通过日志快速定位问题。
相比传统的单体应用,微服务将系统分成多个独立的部分,每个部分都是可以独立部署的业务单元。这就意味着,原来适用于单块架构的集中式的部署、配置、监控或者日志收集等方式,在微服务架构下,随着服务数量的增多,每个服务都需要独立的配置、部署、监控、日志收集等,因此成本呈指数级增长。
部署自动化
对于单体应用系统而言,部署通常都比较简单,操作成本低。而对于微服务而言,每个服务都是一个独立可部署的单元,每个服务的修改,都要独立部署。所拆分的服务越多,部署的难度就越大。在这样的情况下,手动部署显然是不能够满足交付的需求。因此,需要有效地构建自动化部署的流水线,降低部署成本,提高部署频率,这也是微服务架构的一个比较大的考验。
服务间的测试依赖
单体应用的测试相对比较简单。而对于微服务架构而言,由于系统被拆分成多个可独立部署的、分布式的业务单元,因此,服务之间的交互主要通过接口完成。在服务数量逐渐增多的情况下,如何有效地保证服务之间能有效按照接口的约定正常工作,成为微服务实施过程中,测试面临的主要挑战。
服务间的依赖管理
对于传统的单块架构而言,功能实现比较集中,大部分功能都运行在同一个应用中,同其他系统依赖较少。
对于微服务架构而言,当把传统的系统拆分成多个相互协作的独立服务后,随着微服务个数的增多,如何清晰有效地展示服务之间的依赖关系,逐渐成为挑战。这也直接影响着团队对系统的理解和对其维护的信心。
微服务架构
微服务是独立运行的、可被访问的服务单元。微服务架构是一种应用架构,架构中每个微服务可以独立部署,彼此之间是松耦合的。它集成了面向服务架构的诸多优点,且更注重以服务为单元的低复杂度、小体积形态,每个微服务代表一个较小的业务能力,多个不同的微服务可以被组织成可实现更复杂功能的集合。
微服务适应了客观社会环境,能够有效满足敏捷开发的需求。Spring Cloud 是一套完整的微服务架构实践方案,它利用 Java 语言 Spring Boot 框架的开发便利性,使开发人员的开发项目与其提供的各微服务组件可以很方便地进行集成,使微服务架构的项目可以快速实施。本节便以 Spring Cloud 集成的常见的微服务架构组件为例,介绍微服务架构的技术特点。微服务架构的主要技术特点如下。
服务网关
微服务架构中,每个微服务都提供了一个小的应用功能,对于客户端来讲,要想完成一个较复杂的功能需要调用不同的微服务。为了便于客户端的访问及访问管理,在客户端和服务端之间增加了服务网关组件。
服务网关为所有的微服务提供了一个唯一的入口,通过不同的路径将客户端的请求路由到不同的内部服务。通过服务网关还可以提供统一的用户鉴权、跨域访问、流量管控及数据整形等功能,既方便了微服务之间的访问,又减轻了开发工程师的工作量。
常见的服务网关组件有 Spring Cloud Zuul、Kong(基于 OpenResty)及 Gravitee。
服务注册发现
微服务架构中,为确保每个服务的高可用性,每个微服务都由多个部署相同代码的节点构成,每个微服务都会把自己的所有节点注册到注册中心。对于服务调用方,可以通过注册中心查询并发现期望调用服务的节点调用地址,以实现服务访问通信。注册中心会提供相应的检测机制,以确保被发现的节点地址是可用的。
常用的服务注册与发现组件有 Spring Cloud Euraka、ZooKeeper、etcd、Consul。
配置中心
在传统模式下,每个应用都会存在对运行时的数据库、Redis等组件或不同硬件配置下的运行参数进行修改的需求,这些修改都以配置文件的形式保存在代码包中。当每个微服务被拆分为更小的体积并独立部署时,部署节点的数量急剧增加,每个节点配置的修改也变得非常复杂。为了方便配置的修改,配置中心提供了一种配置文件与应用代码分离、集中修改的方法实现配置修改操作。每个服务将配置存储在配置中心,在每次启动时按需读取配置内容,完成配置加载的需求。
常见的组件有 Spring Cloud Config、Apollo 及 Disconf。
服务容错保护
微服务架构将原有的单体应用拆分为多个可独立运行的服务,使很多以前在单应用内存级的调用变成了网络调用。由于网络调用的不确定性或被调用方的可用性等因素极大地增加了访问响应延迟等问题的发生,相应地,调用方自身在等待期间无法响应上级服务的当前调用,若此时仍不断有相同的请求被发送过来,便会造成请求积压,甚至导致服务瘫痪。
基于这种考量,Spring Cloud 在微服务架构中提供了断路器、线程隔离等一系列服务容错保护机制,以对调用的请求进行监控,当下游请求出错达到阈值时,将自动启动熔断,不再调用下游服务直接返回错误信息,当检测到下游服务器恢复时,则继续向下游服务器发送请求。
常见的服务容错保护组件有 Spring Cloud Hystrix、Linkerd、Istio。
分布式链路跟踪
在单体应用拆分为多个可独立运行服务的微服务架构中,服务节点不断增加,服务间的调用关系变得越发复杂。通常一个客户端请求会引发多个及多层级服务的调用,期间除了需要对容错保护机制进行监控,还需要对因调用关系而引发的链路性能进行分析监控。分布式链路跟踪会对客户端访问的每个请求创建一个唯一的跟踪标识,当请求在访问链路中流转时,跟踪系统将根据该跟踪标识实现对每个请求链路的监控。这些监控信息可以包括访问路径中的服务名称、请求耗时、方法错误等。
常见的分布式链路跟踪组件有 Spring Cloud Sleuth、Skywalking、Jaeger 和 Zipkin。
微服务进程间的通信
微服务是通过网络实现通信的,服务的相互调用是进程间的通信调用。对于进程间的通信在通信机制上有两种,一种是 IPC(Inter-Process Communication)机制,其以 REST 风格为代表,并完全通过 HTTP 协议实现,相对更加通用、规范;另一种是 RPC(Remote Procedure Call)机制,典型应用是 Google 开源的 gRPC 框架,它基于 HTTP/2 协议,使不同服务间的进程可以像调用本地方法一样调用远程方法。还有在国内使用比较多的dubbo框架。
很多语言都支持这两种机制的实现,不同语言编写的服务都可以实现跨语言的进程间通信。在通信模式上有同步和异步之分,在同步模式下,服务间调用需要被调用方即时响应,在高并发场景下会出现阻塞;在异步模式下,服务间通过消息组件实现间接通信,可有效避免阻塞,同时还支持一对多的通信实现,常用的消息组件有 RabbitMQ、Kafka等。
支撑平台
碎片化是微服务的主要特征,因而微服务及微服务架构的运维变得更加复杂。容器化技术以进程级别虚拟化使每个微服务运行在传统物理机上,基于容器的管理系统 Kubernetes 为微服务提供了自动化的管理解决方案。Kubernetes 提供了包括自动化部署、运维、监控、负载均衡、灰度访问等功能,有效解决了碎片化微服务的运维管理问题。
微服务的实现
基于Spring Cloud的微服务架构
Spring Cloud Alibaba
spring-cloud-alibaba/README-zh.md at master · alibaba/spring-cloud-alibaba (github.com)
一文带您读懂什么是Spring Cloud与Spring Cloud Alibaba - 知乎 (zhihu.com)
微服务进化
微服务架构技术仍在不断创新,人们围绕微服务不断提出不同的部署和使用方式,使得微服务架构技术不断进化。
服务网格
服务网格(Service Mesh)是一种微服务架构形式,它将微服务独立运行时所依赖的服务组件功能与业务进程分离,使其作为一种可配置的基础设施层存在,每个微服务都包含一个基础设施,并在微服务间为业务进程提供快速、可靠、安全的通信保障。
被分离的基础设施叫作 Sidecar,它实现了服务发现、负载均衡、链路跟踪、访问日志、身份验证、授权及容错保护等功能,使业务进程只关注于具体业务的实现即可。服务网格起源于开源项目 Linkerd,并因 Google 联合 IBM、Lyft 发起的 Istio 项目得到广泛推广。
Istio 是基于 Kubernetes 容器管理框架实现的,并与 Kubernetes 系统实现了紧密的结合,它使用了 Kubernetes 的服务名及服务发现机制。Istio的Sidecar 可实现自动注入 Pod,并使集群内服务间的通信完全可被 Istio 监控。
- Istio 分为控制面板(Control Plane)和数据面板(Data Plane)。
- 控制面板负责实现与用户间的交互,实现监控数据的展示和数据面板相关配置的修改及存储。
- 数据面板由每个微服务的基础设施(Sidecar)组成,其负责与控制面板间的通信及具体微服务进程间的通信基础功能的实现,Istio 的 Sidecar 是通过 Envoy 实现的。
- 在 Kubernetes 中部署 Istio 后,Service 间的通信将不再通过 Kube-proxy,而是被 Istio 通过 iptables 规则转由 Sidecar 接管。
服务网格将 Spring Cloud 微服务架构中诸多组件通过基础设施层利用 Kubernetes 系统的特点注入微服务每个节点的 Pod 中,该方式对业务代码无侵入性,使开发工程师可以更专注于业务功能的实现,极大地减轻了进行软件开发的工作量,提高了软件生产效率。
无服务器化
无服务器化(Serverless)并不代表没有服务器,服务器作为底层资源仍是软件运行的基础,它并不是不需要服务器,而是共享服务器资源。每个用户只需要考虑自己业务应用所需要的计算资源,而不需要关心其运行在什么样的服务器上。无服务器化是公有云产品的一个延伸,它极大地改变了程序设计的方法,对于非无服务器化下的程序开发,开发工程师需要对实现的业务代码加载诸多基础函数、进行打包编译和部署发布等一系列的操作。
无服务器化则使开发工程师只需考虑具体代码的实现,甚至可以仅提供一段函数代码,就可以由无服务器化云平台完成一系列部署、发布、运行等操作。开源无服务器化应用 Kubeless 是基于 Kubernetes 系统实现的,它支持 Python、Node.js、Ruby、PHP、Go、.NET 等语言的运行时(runtime),也支持自定义运行时的方法。
当用户提交一段函数代码或文件后,它会将这段函数与其依赖的运行时封装成可运行的服务,并以 Pod 的形式运行在 Kubernetes 集群中,调用方只需要通过 Kubernetes 提供的 Service 及 Ingress 提供的端口,使用基于 HTTP 的 REST 方式即可实现相应函数方法的调用。
无服务器化架构方式更细粒度地拆解了微服务,它使每个函数都可成为一个微服务的最小功能单元,极大减少了开发工程师所需考虑的非业务类额外因素,更包括代码可复用的公共组件等,使开发工程师们更专注于业务功能的实现,可以更快速地完成开发任务。
持续进化
微服务概念自出现以来,大家一直在思考什么是“微”,就是微服务到底有多小、如何对现有的单体应用进行拆分。这个问题似乎很复杂,也让初识微服务的人对其望而却步,但无论是 Spring Cloud 架构、服务网格还是无服务器化都是将软件生产过程中可被重用的部分与业务代码分离,其本质上仍是结构化程序设计思想的延续,就是将复杂任务按照功能进行拆分,逐步细化并通过模块化的方式提高代码的可重用性,可将这类微服务架构统一称为结构化微服务架构。
在我们的认知中,我们周围所有客观存在的都是物质,每个物质都有它的物理属性和化学属性,分子、原子、离子是构成物质最基本的微粒。在自然界,物质的种类形态万千,物质的性质多种多样,但它们都有其特性,那就是客观存在,并能够被观测。我们可以将微服务架构中的微服务看作一个物质对象,微服务的名称、分类、接口地址、参数说明被定义为它的物理属性,微服务的接口被传递不同参数时产生的不同返回结果被定义为它的化学属性。
对象类是组成微服务物质的分子,具有网络服务接口能力的一个或多个对象类构成一个微服务。这是以面向对象的思想构建微服务架构,多个对象类达到一定的规模就变成了单体应用,多个微服务之间被按照微服务架构的规则自动注册、彼此发现、共享数据、进行统一路由管理等则构成了更复杂的服务。
微服务在我们的现实世界里还需要不断进化,它已经变成客观存在,但以面向对象微服务架构的思想来看,它还不具备可被观测的特性,每个微服务的物理及化学属性应该形成一种标准和规范,可以在一定的授权范围内被用户观测和使用。例如 REST 风格或 gRPC 都是微服务化学反应的一种进程通信机制,无论使用哪一种,都应是物理属性中被声明的一部分,可以被外部用户直接观测。
人工智能技术已渗透到我们每个人的生活之中,未来计算机科学的各种应用都将以人工智能技术的方式体现。可被观测是微服务的一种基本特性,能够主动交流才是智能的体现,在具有智能特征的微服务架构体系中,每个微服务都应该可以智能地告诉服务中心:我是谁、我能做什么、如何和我交流并产生化学反应以及我的进化史。
以公司为实体范围的内部用户将共享每个微服务提供的功能,用户通过服务中心检索每个分类的微服务,并按照自己的需求组装更复杂的功能。当网络中不存在符合功能的微服务时,工程师们可以根据需求添加新的微服务或对相似的微服务进行升级。服务中心管理着每个微服务的版本,并根据智能算法和微服务提供的测试声明确保其化学属性的可用性。
每个微服务均以对象类为最小粒度进行构建,当功能扩展的版本升级后,被智能中心扫描发现所包含的对象类达到技术体系约定的数量时,便会被要求拆分为多个独立的微服务。由于微服务的体量足够小、更加便于阅读,所以每个工程师将不再受传统部门或项目组的约束,其可自由地添加或更改自己所需要的微服务版本,包括更换为自己熟悉的编程语言。每个微服务接口名称将像物质分类一样被社会标准统一制定,即便开发人员遇到跨领域的开发需求,也只需在服务中心检索通用类目获得相应解释和定义,并按照约定的名称定义接口。
总之,自然界中的物质形态万千,同样,微服务应用的功能也是无穷无尽的,所以按照应用的功能进行拆分是无法找到固定拆分方法的,只要以对象类为最小维度构建,并确保其有物理和化学属性的特征,就可以构建一个微服务。笔者认为面向对象的微服务架构将是微服务进化的方向,微服务的粒度也只应与包含对象类的数量有关。