目录
单体应用
互联网早期的技术栈通常为 LAMP(Linux + Apache + MySQL + PHP)或 MVC(Spring + iBatis/Hibernate + Tomcat)。这两种架构都是典型的单体应用架构。其优点是技术栈简单,因此学习上手快,部署也容易。
随着业务越来越复杂,开发团队规模不断扩张,单体应用架构就难以适应开发迭代节奏,主要有以下问题:
- 构建、部署效率低:代码越多,依赖资源越多,则构建、部署的耗费时间自然会越长。即使每次修改一个很小的功能点,也不得不全量构建、全部部署,耗时耗力。
- 团队协作成本高:单体应用的代码往往在一个工程中,而一个工程中的开发人员越多,显然沟通成本越高。
- 可用性差:因为所有的功能开发最后都部署到同一个 WAR 包里,运行在同一个 Tomcat 进程之中,一旦某一功能涉及的代码或者资源有问题,那就会影响整个 WAR 包中部署的功能。
微服务特点
微服务架构有以下 4 个特点:
- 服务拆分粒度更细:根据业务拆分。
- 独立部署:每个服务部署在物理上隔离,互不影响。
- 独立维护:根据组织架构拆分,分团队维护。
- 服务治理:服务数量变多,需要有统一的服务治理平台。
简单来说,微服务就是将庞杂臃肿的单体应用拆分成细粒度的服务,独立部署,并交给各个中小团队来负责开发、测试、上线和运维整个生命周期。
官方的定义:
1、一些列的独立的服务共同组成系统
2、单独部署,跑在自己的进程中
3、每个服务为独立的业务开发
4、分布式管理
5、非常强调隔离性
大概的标准:
1、分布式服务组成的系统
2、按照业务,而不是技术来划分组织
3、做有生命的产品而不是项目
4、强服务个体和弱通信( Smart endpoints and dumb pipes )
5、自动化运维( DevOps )
6、高度容错性
7、快速演化和迭代
何时需要微服务
应用微服务化架构前,要思考几个问题:什么时候进行服务化拆分?如何拆分服务?
当应用复杂度、开发团队膨胀到难以维护时,就该考虑服务化拆分了。
拆分服务的思考维度
- 业务维度:业务和数据关系密切的应该拆分为一个微服务,而功能相对比较独立的业务适合单独拆分为一个微服务。
- 功能维度:公共功能聚合为一个服务。标准是是否被多个其他服务调用,且依赖的资源独立不与其他业务耦合。
- 组织架构:根据实际组织架构,天然分为不同的团队,每个团队独立维护若干微服务。
但并不是说功能拆分的越细越好,过度的拆分反而会让服务数量膨胀变得难以管理,因此找到符合自己业务现状和团队人员技术水平的拆分粒度才是可取的。
拆分服务的原则
单一职责
高内聚,低耦合
先粗后细,逐渐细化
渐进式迭代
考虑扩展性
拆分服务的前置条件
- 服务如何定义?
- 对于单体应用来说,不同功能模块之前相互交互时,通常是以类库的方式来提供各个模块的功能。
- 对于微服务来说,每个服务都运行在各自的进程之中,无论采用哪种通讯协议,是 HTTP 还是 RPC,服务之间的调用都通过接口来约定如何交互。约定内容包括接口名、接口参数以及接口返回值。
- 服务如何发布和订阅?
- 单体应用由于部署在同一个 WAR 包里,接口之间的调用属于进程内的调用。
- 对于微服务来说,服务提供者需要向注册中心发布自己提供的服务(暴露接口信息以及接口地址);服务消费者向注册中心订阅哪些服务可用。
- 服务如何监控?通常对于一个服务,我们最关心的是 QPS(调用量)、AvgTime(平均耗时)以及 P999(99.9% 的请求性能在多少毫秒以内)这些指标。这时候你就需要一种通用的监控方案,能够覆盖业务埋点、数据收集、数据处理,最后到数据展示的全链路功能。
- 服务如何治理?可以想象,拆分为微服务架构后,服务的数量变多了,依赖关系也变复杂了。比如一个服务的性能有问题时,依赖的服务都势必会受到影响。可以设定一个调用性能阈值,如果一段时间内一直超过这个值,那么依赖服务的调用可以直接返回,这就是熔断,也是服务治理最常用的手段之一。
- 故障如何定位?在单体应用拆分为微服务之后,一次用户调用可能依赖多个服务,每个服务又部署在不同的节点上,如果用户调用出现问题,你需要有一种解决方案能够将一次用户请求进行标记,并在多个依赖的服务系统中继续传递,以便串联所有路径,从而进行故障定位。
应用微服务架构,必须要先解决以上问题
什么是微服务架构?
术语微服务没有通用的定义。微服务的最简单定义,也称为微服务架构,是一种使用松耦合服务构建应用程序的架构风格。这些集合或模块可以独立开发、部署和维护。
与传统上复杂的整体应用程序相比,它们以更快、更可靠的速度运行。使用微服务架构,任何规模的组织都可以发展为其能力量身定制的技术堆栈。
使用微服务有很多切实的好处,我们将在后面讨论,但是对于公司是否应该从单体架构转向微服务架构仍然存在一些争议。让我们检查一下两者之间的区别以了解辩论。
单体与微服务
单体架构是构建和部署应用程序的传统方式。这种结构基于一个单一的、不可分割的单元的概念,包括服务器端、客户端和数据库。所有方面都统一并作为一个单元和代码库进行管理。这意味着必须对同一代码库进行任何更新,因此必须更改整个堆栈。随着整体应用程序的扩展,它们会变得相当复杂,因此总体开发时间通常会更长。
另一方面,微服务架构将该单元分解为独立的单元,作为单独的服务运行。这意味着每个服务都有自己的逻辑和代码库。它们通过 API(应用程序编程接口)相互通信。
那么,您应该选择哪种架构?让我们分解一下。
选择单体架构
- 如果你的公司是一个小团队。 这样,您就不必处理部署微服务架构的复杂性。
- 如果你想要更快的启动。 单体架构需要更少的启动时间。该系统稍后需要更多时间来更新您的系统,但初始启动速度更快。
选择微服务架构
- 如果你想开发一个更具扩展性的应用程序。 扩展微服务架构要容易得多。可以非常轻松快速地添加新功能和模块。
- 如果您的公司更大或计划发展。 使用微服务对于计划发展的公司来说非常有用,因为随着时间的推移,微服务架构的可扩展性要高得多,也更容易定制。
微服务技术架构体系
下面我分享一下大部分公司都使用的微服务技术架构体系:
服务发现
主流的服务发现,分为三种:
第一种,开发人员开发了程序以后,会找运维配一个域名,服务的话通过 DNS 就能找到我们对应的服务。
缺点是,由于服务没有负载均衡功能,对负载均衡服务,可能会有相当大的性能问题。
第二种,是目前普遍的做法。可以参考 Zuul 网关,每一个服务都通过服务端内置的功能注册到注册中心,服务消费者不断轮询注册中心发现对应的服务,使用内置负载均衡调用服务。
缺点是,对多语言环境不是很好,你需要单独给消费者的客户端开发服务发现和负载均衡功能。当然了,这个方法通常都是用在 Spring Cloud 上的。
第三种,是将客户端和负载均衡放在同一个主机,而不是同一个进程内。
这种方法相对第一种第二种方法来说,改善了他们的缺点,但是会极大增加运维成本。
网关
微服务的网关是什么?我们可以联系生活实际想一下。每一个大的公司,都会有一偏属于自己的建筑区,而这建筑区内,都有不少的门卫。如果有外来人员进入公司,会先和门卫打好招呼,才能进去。
将生活实际联系到微服务上,就不难理解网关的意思了:
网关的作用如下:
- 反向路由:很多时候,公司不想让外部人员看到我们公司的内部,就需要网关来进行反向路由。即将外部请求转换成内部具体服务调用。
- 安全认证:网络中会有很多恶意访问,譬如爬虫,譬如黑客攻击,网关维护安全功能。
- 限流熔断:当请求很多服务不堪重负,会让我们的服务自动关闭,导致不能用服务。限流熔断可以有效的避免这类问题。
- 日志监控:所有的外面的请求都会经过网关,这样我们就可以使用网关来记录日志信息。
- 灰度发布,蓝绿部署。是指能够平滑过渡的一种发布方式。在其上可以进行 A/B testing。即让一部分用户继续用产品特性 A,一部分用户开始用产品特性 B,如果用户对 B 没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到 B 上面来。
开源网关 Zuul 架构:
Zuul 网关核心其实是一个 Servlet,所有请求都会经过 Zuul Servlet 传到 ZuulFilter Runner,然后分发到三种过滤器。
先说说架构图左半部分,分别是使用 Groovy 实现的前置路由过滤器,路由过滤器,后置路由过滤器。
一般请求都会先经过前置路由过滤器处理,一般的自定义 Java 封装逻辑也会在这里实现。
路由过滤器,实现的是找到对应的微服务进行调用。调用完了,响应回来,会经过后置路由过滤器,通过后置路由过滤器我们可以封装日志审计的处理。
可以说 Zuul 网关最大的特色就是它的三层过滤器。架构图右半部分,是 Zuul 网关设计的自定义过滤器加载机制。
网关内部会有生产者消费者模型,自动的将过滤器脚本发布到 Zuul 网关读取加载运行。
配置中心
以前,开发人员把配置文件放在开发文件里面,这样会有很多隐患。譬如,配置规范不同,无法追溯配置人员。
一旦需要大规模改动配置,改动时间会很长,无法追溯配置人员,从而影响整个产品,后果是我们承担不起的。
因此就有配置中心这个喽!现在的开源中心有百度配置中心 Disconf,Spring Cloud Config,Apollo。
今天重点说说现在应用质量不错的配置中心,携程开源的阿波罗(Apollo):
Apollo 的配置中心规模比较大,本地应用会有响应的配置中心客户端,可以定时同步配置中心里的配置。如果配置中心怠机,会使用缓存来进行配置。
通讯方式
关于通讯方式,一般市面也就是两种远程调用方式,我整理了一个表格:
监控预警
监控预警对于微服务很重要,一个可靠的监控预警体系对微服务运行至关重要。
一般监控分为如下层次:
从基础设施到用户端,层层有监控,全方位,多角度,每一个层面都很重要。
总体来说,微服务可分为 5 个监控点:
- 日志监控
- Metrics 监控
- 健康检查
- 调用链检查
- 告警系统
①监控架构
下面的图是大部分公司的一种监控架构图。每一个服务都有一个 Agent,Agent 收集到关键信息,会传到一些 MQ 中,为了解耦。
同时将日志传入 ELK,将 Metrics 传入 InfluxDB 时间序列库。而像 Nagios,可以定期向 Agent 发起信息检查微服务。
②调用链监控 APM
很多公司都有调用链监控,就譬如阿里有鹰眼监控,点评的 Cat,大部分调用链监控(没错,我指的 Zipkin)架构是这样的:
当请求进入 Web 容器的时候,会经过创建 Tracer,连接 Spans(模拟潜在的分布式工作的延迟,该模块还包含在系统网络间传递跟踪上下文信息的工具包,如通过 HTTP Headers)。
Spans 有一个上下文,其中包含 Tracer 标识符,将其放在表示分布式操作的树的正确位置。
当我们把图中的各种 Span 放到后端的时候,我们的服务调用链会动态的生成调用链。
下面是一些市场上用的比较多的调用链监控对比:
熔断、隔离、限流、降级
面对巨大的突发流量下,大型公司一般会采用一系列的熔断(系统自动将服务关闭防止让出现的问题最大化)、隔离(将服务和服务隔离,防止一个服务挂了其他服务不能访问)、限流(单位时间内之允许一定数量用户访问)、降级(当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,我们可以将一些不重要或不紧急的服务或任务进行服务的延迟使用或暂停使用)措施。
下面介绍一下 Hystrix 的运行流程:
每一个微服务调用时,都会使用 Hystrix 的 Command 方式(上图的左上角那个),然后使用 Command 同步的,或者是响应式的,或者是异步的,判断电路是否熔断(顺着图从左往右看),如果断路则走降级 Fallback。
如果这个线闭合着,但是线程资源没了,队列满了,则走限流措施(看图的第 5 步)。
如果走完了,执行成功了,则走 run() 方法,获取 Response,但是这个过程如果出错了,则继续走降级 Fallback。
同时,看图最上面有一个后缀是 Health 的,这是一个计算整个链路是否健康的组件,每一步操作都被它记录着。
容器与服务编排引擎
从物理机到虚拟机,从虚拟机到容器;从物理集群到 OpenStack,OpenStack 到 Kubernetes;科技不断的变化,我们的认知也没刷新。
我们从容器开始说起,它首先是一个相对独立的运行环境,在这一点有点类似于虚拟机,但是不像虚拟机那样彻底。
虚拟机会将虚拟硬件、内核(即操作系统)以及用户空间打包在新虚拟机当中,虚拟机能够利用“虚拟机管理程序”运行在物理设备之上。
虚拟机依赖于 Hypervisor,其通常被安装在“裸金属”系统硬件之上,这导致 Hypervisor 在某些方面被认为是一种操作系统。
一旦 Hypervisor 安装完成, 就可以从系统可用计算资源当中分配虚拟机实例了,每台虚拟机都能够获得唯一的操作系统和负载(应用程序)。
简言之,虚拟机先需要虚拟一个物理环境,然后构建一个完整的操作系统,再搭建一层 Runtime,然后供应用程序运行。
对于容器环境来说,不需要安装主机操作系统,直接将容器层(比如 LXC 或 Libcontainer)安装在主机操作系统(通常是 Linux 变种)之上。
在安装完容器层之后,就可以从系统可用计算资源当中分配容器实例了,并且企业应用可以被部署在容器当中。
但是,每个容器化应用都会共享相同的操作系统(单个主机操作系统)。容器可以看成一个装好了一组特定应用的虚拟机,它直接利用了宿主机的内核,抽象层比虚拟机更少,更加轻量化,启动速度极快。
相比于虚拟机,容器拥有更高的资源使用效率,因为它并不需要为每个应用分配单独的操作系统——实例规模更小、创建和迁移速度也更快。这意味着相比于虚拟机,单个操作系统能够承载更多的容器。
云提供商十分热衷于容器技术,因为在相同的硬件设备当中,可以部署数量更多的容器实例。
此外,容器易于迁移,但是只能被迁移到具有兼容操作系统内核的其他服务器当中,这样就会给迁移选择带来限制。
因为容器不像虚拟机那样同样对内核或者虚拟硬件进行打包,所以每套容器都拥有自己的隔离化用户空间,从而使得多套容器能够运行在同一主机系统之上。
我们可以看到全部操作系统层级的架构都可实现跨容器共享,惟一需要独立构建的就是二进制文件与库。
正因为如此,容器才拥有极为出色的轻量化特性。我们最常用的容器是 Docker。
①容器编排
过去虚拟机可以通过云平台 OpenStack 管理虚拟化,容器时代如何管理容器呢?这就要看看容器编排引擎了。
Apache Mesos:Mesos 是基于 Master,Slave 架构,框架决定如何利用资源,Master 负责管理机器,Slave 会定期的将机器情况报告给 Master,Master 再将信息给框架。Master 是高可用的,因为 ZK,也有 Leader 的存在。
下面是架构图:
Kubernetes 设计理念和功能其实就是一个类似 Linux 的分层架构,先说说每一个 Kubernetes 节点内部,kubelet 管理全局全局 pod,而每一个 pod 承载着一个或多个容器,kube-proxy 负责网络代理和负载均衡。
Kubernetes 节点外部,则是对应的控制管理服务器,负责统一管理各个节点调度分配与运行。
②服务网格化
关于服务网络化,后面会更加深入的为大家进行讲解。
微服务的基础架构
微服务架构下,服务调用主要依赖下面几个基本组件:
- 服务描述
- 注册中心
- 服务框架
- 服务监控
- 服务追踪
- 服务治理
服务描述
服务调用首先要解决的问题就是服务如何对外描述。比如,你对外提供了一个服务,那么这个服务的服务名叫什么?调用这个服务需要提供哪些信息?调用这个服务返回的结果是什么格式的?该如何解析?这些就是服务描述要解决的问题。
常用的服务描述方式包括 RESTful API、XML 配置以及 IDL 文件三种。
其中,RESTful API 方式通常用于 HTTP 协议的服务描述,并且常用 Wiki 或者Swagger (opens new window)来进行管理。下面是一个 RESTful API 方式的服务描述的例子。
XML 配置方式多用作 RPC 协议的服务描述,通过 *.xml 配置文件来定义接口名、参数以及返回值类型等。下面是一个 XML 配置方式的服务描述的例子。
IDL 文件方式通常用作 Thrift 和 gRPC 这类跨语言服务调用框架中,比如 gRPC 就是通过 Protobuf 文件来定义服务的接口名、参数以及返回值的数据结构。
注册中心
有了服务的接口描述,下一步要解决的问题就是服务的发布和订阅,就是说你提供了一个服务,如何让外部想调用你的服务的人知道。这个时候就需要一个类似注册中心的角色,服务提供者将自己提供的服务以及地址登记到注册中心,服务消费者则从注册中心查询所需要调用的服务的地址,然后发起请求。
一般来讲,注册中心的工作流程是:
- 服务提供者在启动时,根据服务发布文件中配置的发布信息向注册中心注册自己的服务。
- 服务消费者在启动时,根据消费者配置文件中配置的服务信息向注册中心订阅自己所需要的服务。
- 注册中心返回服务提供者地址列表给服务消费者。
- 当服务提供者发生变化,比如有节点新增或者销毁,注册中心将变更通知给服务消费者。
服务框架
服务消费者发起调用需解决以下问题:
- 服务通信采用什么协议?就是说服务提供者和服务消费者之间以什么样的协议进行网络通信,是采用四层 TCP、UDP 协议,还是采用七层 HTTP 协议,还是采用其他协议?
- 数据传输采用什么方式?就是说服务提供者和服务消费者之间的数据传输采用哪种方式,是同步还是异步,是在单连接上传输,还是多路复用。
- 数据压缩采用什么格式?通常数据传输都会对数据进行压缩,来减少网络传输的数据量,从而减少带宽消耗和网络传输时间,比如常见的 JSON 序列化、Java 对象序列化以及 Protobuf 序列化等。
服务监控
一旦服务消费者与服务提供者之间能够正常发起服务调用,你就需要对调用情况进行监控,以了解服务是否正常。通常来讲,服务监控主要包括三个流程。
- 数据收集。就是要把每一次服务调用的请求耗时以及成功与否收集起来,并上传到集中的数据处理中心。
- 数据处理。有了每次调用的请求耗时以及成功与否等信息,就可以计算每秒服务请求量、平均耗时以及成功率等指标。
- 数据展示。数据收集起来,经过处理之后,还需要以友好的方式对外展示,才能发挥价值。通常都是将数据展示在 Dashboard 面板上,并且每隔 10s 等间隔自动刷新,用作业务监控和报警等。
服务链路追踪
除了需要对服务调用情况进行监控之外,你还需要记录服务调用经过的每一层链路,以便进行问题追踪和故障定位。
服务链路追踪的工作原理大致如下:
- 服务消费者发起调用前,会在本地按照一定的规则生成一个
requestid
,发起调用时,将requestid
当作请求参数的一部分,传递给服务提供者。 - 服务提供者接收到请求后,记录下这次请求的
requestid
,然后处理请求。如果服务提供者继续请求其他服务,会在本地再生成一个自己的requestid
,然后把这两个requestid
都当作请求参数继续往下传递。
以此类推,通过这种层层往下传递的方式,一次请求,无论最后依赖多少次服务调用、经过多少服务节点,都可以通过最开始生成的 requestid
串联所有节点,从而达到服务追踪的目的。
服务治理
服务监控能够发现问题,服务追踪能够定位问题所在,而解决问题就得靠服务治理了。服务治理就是通过一系列的手段来保证在各种意外情况下,服务调用仍然能够正常进行。
在生产环境中,你应该经常会遇到下面几种状况。
- 单机故障。通常遇到单机故障,都是靠运维发现并重启服务或者从线上摘除故障节点。然而集群的规模越大,越是容易遇到单机故障,在机器规模超过一百台以上时,靠传统的人肉运维显然难以应对。而服务治理可以通过一定的策略,自动摘除故障节点,不需要人为干预,就能保证单机故障不会影响业务。
- 单 IDC 故障。你应该经常听说某某 App,因为施工挖断光缆导致大批量用户无法使用的严重故障。而服务治理可以通过自动切换故障 IDC 的流量到其他正常 IDC,可以避免因为单 IDC 故障引起的大批量业务受影响。
- 依赖服务不可用。比如你的服务依赖依赖了另一个服务,当另一个服务出现问题时,会拖慢甚至拖垮你的服务。而服务治理可以通过熔断,在依赖服务异常的情况下,一段时期内停止发起调用而直接返回。这样一方面保证了服务消费者能够不被拖垮,另一方面也给服务提供者减少压力,使其能够尽快恢复。
上面是三种最常见的需要引入服务治理的场景,当然还有一些其他服务治理的手段比如自动扩缩容,可以用来解决服务的容量问题。
技术栈和架构模式
了解微体系结构的工作原理是一回事,而实际构建和实施它又是另一回事。这就是为什么我们要专注于为整个微服务系统提供的各种技术。让我们通过一些不同的技术堆栈、模式和设计来创建可执行的微服务架构。
微观和宏观架构决策
建议将您的架构分为微观和宏观架构。微架构涉及为每个微服务做出的所有决策。宏架构涉及在全局级别做出的所有决策,这些决策适用于所有微服务。
可以将微观和宏观架构的概念扩展到技术决策。 技术决策可以在宏观或微观架构的框架内做出。例如,看看要在数据库的微观和宏观层面做出的技术决策:
- 微: 每个微服务都可以有自己的数据库实例。如果数据库是在微架构中定义的,那么一个数据库的崩溃只会导致一个微服务的崩溃。这使得整个应用程序更加健壮。
- 宏: 数据库也可以定义为宏架构的一部分。多个微服务不得共享数据库架构。
独立系统
自包含系统 (SCS) 是一种微服务架构,它指定了宏架构的元素。这意味着它们不代表整个系统。由于 SCS 是独立的,它提供了实现域逻辑的一部分所需的一切,例如日志数据和 UI。SCS 也有一个可选的 API。
例如,用于微服务支付的 SCS 会将与该支付相关的信息存储为有界上下文。它还将实现 UI 以显示支付历史记录,并且有关客户的数据将从其他 SCS 复制。
将这些视为最佳实践的集合;SCS 提供基于既定模式的精确规则,为如何构建微服务架构提供参考点。所有这些规则确保一个 SCS 实现一个域,因此添加的功能只会改变一个 SCS。
我们可以将 SCS 视为微服务架构,因为它可以独立部署并将系统划分为独立的 Web 应用程序。事实上,一个SCS甚至可以拆分成多个微服务。它们在三个主要方面与微服务不同:它们比微服务更大,它们专注于松散耦合,并且它们必须具有 UI。
前端整合
微服务也可以与 Web 前端集成。将前端划分为不同的模块有助于解决将其视为整体的一些问题。模块化前端由可单独部署的微服务组成。这可以为您的前端带来很多好处。
例如,模块化的前端可以有独立的领域逻辑,领域的改变可以通过只修改一个微服务来实现。要组合单独的前端,必须将它们集成,因此需要一个集成系统。
这可以通过链接来实现,其中一个前端显示另一个前端读取和处理的链接。这也可以通过重定向来完成,例如 OAuth2 如何处理前端集成。重定向将数据传输与前端集成相结合。
但是,当前端应作为整体部署时,也有一些例外。例如,本机移动应用程序应该是部署单体,或者如果有一个单独的团队负责前端开发。
异步微服务
同步微服务在处理请求并等待结果的同时向其他微服务发出请求。异步通信协议发送接收者做出反应的消息,但没有直接响应。如果一个微服务在处理时不向其他微服务发出请求,或者它发出请求但不等待结果,则可以定义为异步微服务。
异步微服务为同步微服务提供了几个显着的优势,并解决了分布式系统的许多挑战。处理微服务请求所需的逻辑不依赖于结果,使它们更加独立。
同样,如果通信伙伴出现故障,它不会使整个系统崩溃,从而为您的系统提供整体弹性。最重要的是,加工和交付几乎总是有保证的。
异步微服务技术的一些常见示例是 Kafka(一种常用于消息传递的 MOM)、REST 和 Atom 数据格式(用于附加基础设施)。
微服务平台
微服务平台,如 PaaS 和 Docker 调度程序,支持微服务的运行和通信。这些技术支持微服务之间的通信以进行部署、日志分析和监控。
例如,这些平台支持具有负载平衡和服务发现功能的 HTTP 和 REST。微服务的实现只需要有限的运维支持,可以快速部署,支持多种微服务。
微服务平台代表了常见问题的简化和解决方案。一些著名的平台是[Kubernetes]和 Docker,这对于微服务操作非常重要。PaaS 和 Cloud Foundry 也很有用,但没有那么流行。
值得注意的是,迁移到这些平台需要更改应用程序的操作和安装,这可以使微服务平台的使用成为一个重要且及时的步骤。这是微服务平台的主要缺点。
微服务的优点和缺点
微服务架构成为贵公司更好选择的原因有很多。让我们讨论最显着的好处,然后检查一些缺点。
好处
提高可扩展性和生产力
大型团队通常必须在复杂的项目上协同工作。借助微服务,项目可以划分为更小的独立单元。这意味着团队可以根据领域逻辑独立行动,从而最大限度地减少协调和工作量。最重要的是,负责每个微服务的团队可以根据自己的需要做出自己的技术决策。
例如,只要接口功能正常,每个单元或容器的内部结构并不重要。因此,任何编程语言都可以用来编写微服务,因此负责的团队可以为队友选择最好的语言。
与遗留系统很好地集成
单体系统很难维护。许多遗留系统结构不良、测试不当或依赖过时的技术。幸运的是,微服务可以与遗留系统一起工作以改进代码并替换系统的旧部分。集成很容易,并且可以解决许多使单一系统成为过去的问题。
可持续发展
微服务架构创建的系统从长远来看保持可维护性,因为各个部分都是可更换的。这意味着可以轻松地重写微服务,而不会影响整个系统。只要适当地管理微服务之间的依赖关系,就可以轻松地进行更改以优化团队需求和性能。
跨功能
微服务最适合分布式团队。如果您的团队或多个部门遍布世界各地,微服务可提供必要的自由和灵活性以自主工作。可以快速做出技术决策,并在瞬间与其他服务集成。跨功能从未如此简单。
缺点
部署需要更多努力
微服务系统的操作通常需要更多的努力,因为有更多的可部署单元必须每个都被部署和监控。必须实施对接口的更改,以便仍然可以独立部署各个微服务。
测试必须是独立的
由于所有微服务必须一起测试,一个微服务可以阻塞测试阶段并阻止其他微服务的部署。需要测试的接口比较多,接口两边的测试要独立。
难以更改多个微服务
影响多个微服务的更改可能更难实施。在微服务系统中,更改需要多个协调部署。
总结
1、微服务的优点:
关键点: 复杂度可控,独立按需扩展,技术选型灵活,容错,可用性高
① 它解决了复杂性的问题。它会将一种怪异的整体应用程序分解成一组服务。虽然功能总量 不变,但应用程序已分解为可管理的块或服务。每个服务都以 RPC 或消息驱动的 API 的形式定义了一个明确的边界;Microservice 架构模式实现了一个模块化水平。
② 这种架构使每个服务都能够由专注于该服务的团队独立开发。开发人员可以自由选择任何有用的技术,只要该服务符合 API 合同。当然,大多数组织都希望避免完全无政府状态并限制技术选择。然而,这种自由意味着开发人员不再有义务使用在新项目开始时存在的可能过时的技术。在编写新服务时,他们可以选择使用当前的技术。此外,由于服务相对较小,因此使用当前技术重写旧服务变得可行。
③ Microservice 架构模式使每个微服务都能独立部署。开发人员不需要协调部署本地服务的变更。这些变化可以在测试后尽快部署。例如,UI 团队可以执行 A | B 测试,并快速迭代 UI 更改。Microservice 架构模式使连续部署成为可能。
④ Microservice 架构模式使每个服务都可以独立调整。您可以仅部署满足其容量和可用性限制的每个服务的实例数。此外,您可以使用最符合服务资源要求的硬件。
2、微服务的缺点
关键点(挑战): ,系统部署依赖,服务间通信成本,数据一致性,系统集成测试,重复工作,性能监控等
① 一个缺点是名称本身。术语 microservice 过度强调服务规模。但重要的是要记住,这是一种手段,而不是主要目标。微服务的目标是充分分解应用程序,以便于敏捷应用程序开发和部署。
② 微服务器的另一个主要缺点是分布式系统而产生的复杂性。开发人员需要选择和实现基于消息传递或 RPC 的进程间通信机制。此外,他们还必须编写代码来处理部分故障,因为请求的目的地可能很慢或不可用。
③ 微服务器的另一个挑战是分区数据库架构。更新多个业务实体的业务交易是相当普遍的。但是,在基于微服务器的应用程序中,您需要更新不同服务所拥有的多个数据库。使用分布式事务通常不是一个选择,而不仅仅是因为 CAP 定理。许多今天高度可扩展的 NoSQL 数据库都不支持它们。你最终不得不使用最终的一致性方法,这对开发人员来说更具挑战性。
④ 测试微服务应用程序也更复杂。服务类似的测试类将需要启动该服务及其所依赖的任何服务(或至少为这些服务配置存根)。再次,重要的是不要低估这样做的复杂性。
⑤ Microservice 架构模式的另一个主要挑战是实现跨越多个服务的更改。例如,我们假设您正在实施一个需要更改服务 A,B 和 C 的故事,其中 A 取决于 B 和 B 取决于 C.在单片应用程序中,您可以简单地更改相应的模块,整合更改,并一次性部署。相比之下,在 Microservice 架构模式中,您需要仔细规划和协调对每个服务的更改。例如,您需要更新服务 C,然后更新服务 B,然后再维修 A.幸运的是,大多数更改通常仅影响一个服务,而需要协调的多服务变更相对较少。
⑥ 部署基于微服务的应用程序也更复杂。单一应用程序简单地部署在传统负载平衡器后面的一组相同的服务器上。每个应用程序实例都配置有基础架构服务(如数据库和消息代理)的位置(主机和端口)。相比之下,微服务应用通常由大量服务组成。例如,每个服务将有多个运行时实例。更多的移动部件需要进行配置,部署,扩展和监控。此外,您还需要实现服务发现机制,使服务能够发现需要与之通信的任何其他服务的位置(主机和端口)。传统的基于故障单和手动操作的方法无法扩展到这种复杂程度。因此,成功部署微服务应用程序需要开发人员更好地控制部署方法,并实现高水平的自动化。
微服务和 Docker
Docker和微服务几乎是同义词。微服务必须是可单独部署、可扩展的独立单元。但是,如果您为您的应用程序创建多个微服务呢?Docker 是用于部署微服务的轻量级解决方案。微服务可以打包到 Docker 镜像中,并作为 Docker 容器隔离。这样,您就可以构建独立于宿主环境的应用程序。
Docker 容器不是拥有自己的完整虚拟机,而是共享 Docker 主机上的操作系统内核。来自容器的进程出现在运行 Docker 容器的操作系统的进程表中。
要将 Docker 与微服务一起使用,您需要通过名为Dockerfile
. Dockerfile 易于编写,因此推出软件也很容易。查看 Java 微服务的 Dockerfile 示例。
FROM openjdk:11.0.2-jre-slim COPY target/customer.jar . CMD /usr/bin/java -Xmx400m -Xms400m -jar customer.jar EXPOSE 8080
一个典型的微服务系统包含多个 Docker 容器。协调多个 Docker 容器的系统需要配置虚拟网络。容器必须能够找到彼此才能进行通信。Docker Compose 环境可以通过链接联系另一台服务器,提供服务发现系统。
传统开发模式和微服务的区别
先来看看传统的 web 开发方式,通过对比比较容易理解什么是 Microservice Architecture。和 Microservice 相对应的,这种方式一般被称为 Monolithic(单体式开发)。
所有的功能打包在一个 WAR 包里,基本没有外部依赖(除了容器),部署在一个 JEE 容器(Tomcat,JBoss,WebLogic)里,包含了 DO/DAO,Service,UI 等所有逻辑。
优点:
①开发简单,集中式管理
②基本不会重复开发
③功能都在本地,没有分布式的管理和调用消耗
缺点:
1、效率低:开发都在同一个项目改代码,相互等待,冲突不断
2、维护难:代码功功能耦合在一起,新人不知道何从下手
3、不灵活:构建时间长,任何小修改都要重构整个项目,耗时
4、稳定性差:一个微小的问题,都可能导致整个应用挂掉
5、扩展性不够:无法满足高并发下的业务需求
常见的系统架构遵循的三个标准和业务驱动力:
1、提高敏捷性:及时响应业务需求,促进企业发展
2、提升用户体验:提升用户体验,减少用户流失
3、降低成本:降低增加产品、客户或业务方案的成本
基于微服务架构的设计:
目的: 有效的拆分应用,实现敏捷开发和部署
关于微服务的一个形象表达:
X 轴: 运行多个负载均衡器之后的运行实例
Y 轴: 将应用进一步分解为微服务(分库)
Z 轴: 大数据量时,将服务分区(分表)
SOA 和微服务的区别
1、SOA 喜欢重用,微服务喜欢重写
SOA 的主要目的是为了企业各个系统更加容易地融合在一起。说到 SOA 不得不说 ESB(EnterpriseService Bus)。ESB 是什么? 可以把 ESB 想象成一个连接所有企业级服务的脚手架。通过 service broker,它可以把不同数据格式或模型转成 canonical 格式,把 XML 的输入转成 CSV 传给 legacy 服务,把 SOAP 1.1 服务转成 SOAP 1.2 等等。它还可以把一个服务路由到另一个服务上,也可以集中化管理业务逻辑,规则和验证等等。它还有一个重要功能是消息队列和事件驱动的消息传递,比如把 JMS 服务转化成 SOAP 协议。各服务间可能有复杂的依赖关系。
微服务 通常由重写一个模块开始。要把整个巨石型的应用重写是有很大的风险的,也不一定必要。我们向微服务迁移的时候通常从耦合度最低的模块或对扩展性要求最高的模块开始,把它们一个一个剥离出来用敏捷地重写,可以尝试最新的技术和语言和框架,然 后单独布署。它通常不依赖其他服务。微服务中常用的 API Gateway 的模式主要目的也不是重用代码,而是减少客户端和服务间的往来。API gateway 模式不等同与 Facade 模式,我们可以使用如 future 之类的调用,甚至返回不完整数据。
2、SOA 喜欢水平服务,微服务喜欢垂直服务
SOA 设计喜欢给服务分层(如 Service Layers 模式)。我们常常见到一个 Entity 服务层的设计,美其名曰 Data Access Layer。这种设计要求所有的服务都通过这个 Entity 服务层来获取数据。这种设计非常不灵活,比如每次数据层的改动都可能影响到所有业务层的服务。而每个微服务通常有它自己独立的 data store。我们在拆分数据库时可以适当的做些去范式化(denormalization),让它不需要依赖其他服务的数据。
微服务 通常是直接面对用户的,每个微服务通常直接为用户提供某个功能。类似的功能可能针对手机有一个服务,针对机顶盒是另外一个服务。在 SOA 设计模式中这种情况通常会用到 Multi-ChannelEndpoint 的模式返回一个大而全的结果兼顾到所有的客户端的需求。
3、SOA 喜欢自上而下,微服务喜欢自下而上
SOA 架构在设计开始时会先定义好服务合同(service contract)。它喜欢集中管理所有的服务,包括集中管理业务逻辑,数据,流程,schema,等等。它使用 Enterprise Inventory 和 Service Composition 等方法来集中管理服务。SOA 架构通常会预先把每个模块服务接口都定义好。模块系统间的通讯必须遵守这些接口,各服务是针对他们的调用者。
SOA 架构适用于 TOGAF 之类的架构方法论。
微服务 则敏捷得多。只要用户用得到,就先把这个服务挖出来。然后针对性的,快速确认业务需求,快速开发迭代。
怎么具体实践微服务
要实际的应用微服务,需要解决一下四点问题:
1、客户端如何访问这些服务
2、每个服务之间如何通信
3、如此多的服务,如何实现?
4、服务挂了,如何解决?(备份方案,应急处理机制)
1、客户端如何访问这些服务
原来的 Monolithic 方式开发,所有的服务都是本地的,UI 可以直接调用,现在按功能拆分成独立的服务,跑在独立的一般都在独立的虚拟机上的 Java 进程了。客户端 UI 如何访问他的?
后台有 N 个服务,前台就需要记住管理 N 个服务,一个服务下线/更新/升级,前台就要重新部署,这明显不服务我们 拆分的理念,特别当前台是移动应用的时候,通常业务变化的节奏更快。
另外,N 个小服务的调用也是一个不小的网络开销。还有一般微服务在系统内部,通常是无 状态的,用户登录信息和权限管理最好有一个统一的地方维护管理(OAuth)。
所以,一般在后台 N 个服务和 UI 之间一般会一个代理或者叫 API Gateway,他的作用包括:
① 提供统一服务入口,让微服务对前台透明
② 聚合后台的服务,节省流量,提升性能
③ 提供安全,过滤,流控等 API 管理功能
其实这个 API Gateway 可以有很多广义的实现办法,可以是一个软硬一体的盒子,也可以是一个简单的 MVC 框架,甚至是一个 Node.js 的服务端。他们最重要的作 用是为前台(通常是移动应用)提供后台服务的聚合,提供一个统一的服务出口,解除他们之间的耦合,不过 API Gateway 也有可能成为单点故障点或者性能的瓶颈。
用过 Taobao Open Platform(淘宝开放平台)的就能很容易的体会,TAO 就是这个 API Gateway。
2、每个服务之间如何通信
所有的微服务都是独立的 Java 进程跑在独立的虚拟机上,所以服务间的通信就是 IPC(inter process communication),已经有很多成熟的方案。现在基本最通用的有两种方式:
同步调用:
①REST(JAX-RS,Spring Boot)
②RPC(Thrift, Dubbo)
异步消息调用(Kafka, Notify, MetaQ)
同步和异步的区别:
一般同步调用比较简单,一致性强,但是容易出调用问题,性能体验上也会差些,特别是调用层次多的时候。RESTful 和 RPC 的比较也是一个很有意 思的话题。
一般 REST 基于 HTTP,更容易实现,更容易被接受,服务端实现技术也更灵活些,各个语言都能支持,同时能跨客户端,对客户端没有特殊的要求,只要封装了 HTTP 的 SDK 就能调用,所以相对使用的广一些。RPC 也有自己的优点,传输协议更高效,安全更可控,特别在一个公司内部,如果有统一个 的开发规范和统一的服务框架时,他的开发效率优势更明显些。就看各自的技术积累实际条件,自己的选择了。
而异步消息的方式在分布式系统中有特别广泛的应用,他既能减低调用服务之间的耦合,又能成为调用之间的缓冲,确保消息积压不会冲垮被调用方,同时能保证调用方的服务体验,继续干自己该干的活,不至于被后台性能拖慢。不过需要付出的代价是一致性的减弱,需要接受数据最终一致性;还有就是后台服务一般要 实现幂等性,因为消息发送出于性能的考虑一般会有重复(保证消息的被收到且仅收到一次对性能是很大的考验);最后就是必须引入一个独立的 broker,如果公司内部没有技术积累,对 broker 分布式管理也是一个很大的挑战。
3、如此多的服务,如何实现?
在微服务架构中,一般每一个服务都是有多个拷贝,来做负载均衡。一个服务随时可能下线,也可能应对临时访问压力增加新的服务节点。服务之间如何相互感知?服务如何管理?
这就是服务发现的问题了。一般有两类做法,也各有优缺点。基本都是通过 zookeeper 等类似技术做服务注册信息的分布式管理。当服务上线时,服务提供者将自己的服务信息注册到 ZK(或类似框架),并通过心跳维持长链接,实时更新链接信息。服务调用者通过 ZK 寻址,根据可定制算法, 找到一个服务,还可以将服务信息缓存在本地以提高性能。当服务下线时,ZK 会发通知给服务客户端。
客户端做: 优点是架构简单,扩展灵活,只对服务注册器依赖。缺点是客户端要维护所有调用服务的地址,有技术难度,一般大公司都有成熟的内部框架支持,比如 Dubbo。
服务端做: 优点是简单,所有服务对于前台调用方透明,一般在小公司在云服务上部署的应用采用的比较多。
4、服务挂了,如何解决
前面提到,Monolithic 方式开发一个很大的风险是,把所有鸡蛋放在一个篮子里,一荣俱荣,一损俱损。而分布式最大的特性就是网络是不可靠的。通过微服务拆分能降低这个风险,不过如果没有特别的保障,结局肯定是噩梦。所以当我们的系统是由一系列的服务调用链组成的时候,我们必须确保任一环节出问题都不至于影响整体链路。相应的手段有很多:
①重试机制
②限流
③熔断机制
④负载均衡
⑤降级(本地缓存)
这些方法基本都很明确通用,比如 Netflix 的 Hystrix:https://github.com/Netflix/Hystrix
常见的设计模式和应用
有一个图非常好的总结微服务架构需要考虑的问题,包括:
1、API Gateway
2、服务间调用
3、服务发现
4、服务容错
5、服务部署
6、数据调用
六种常见的微服务架构设计模式:
1、聚合器微服务设计模式
这是一种最常见也最简单的设计模式:
聚合器调用多个服务实现应用程序所需的功能。它可以是一个简单的 Web 页面,将检索到的数据进行处理展示。它也可以是一个更高层次的组合微服务,对检索到的数据增加业务逻辑后进一步发布成一个新的微服务,这符合 DRY 原则。另外,每个服务都有自己的缓存和数据库。如果聚合器是一个组合服务,那么它也有自己的缓存和数据库。聚合器可以沿 X 轴和 Z 轴独立扩展。
2、代理微服务设计模式
这是聚合模式的一个变种,如下图所示:
在这种情况下,客户端并不聚合数据,但会根据业务需求的差别调用不同的微服务。代理可以仅仅委派请求,也可以进行数据转换工作。
3、链式微服务设计模式
这种模式在接收到请求后会产生一个经过合并的响应,如下图所示:
在这种情况下,服务 A 接收到请求后会与服务 B 进行通信,类似地,服务 B 会同服务 C 进行通信。所有服务都使用同步消息传递。在整个链式调用完成之前,客户端会一直阻塞。
因此,服务调用链不宜过长,以免客户端长时间等待。
4、分支微服务设计模式
这种模式是聚合器模式的扩展,允许同时调用两个微服务链,如下图所示:
5、数据共享微服务设计模式
自治是微服务的设计原则之一,就是说微服务是全栈式服务。但在重构现有的“单体应用(monolithic application)”时,SQL 数据库反规范化可能会导致数据重复和不一致。
因此,在单体应用到微服务架构的过渡阶段,可以使用这种设计模式。
在这种情况下,部分微服务可能会共享缓存和数据库存储。不过,这只有在两个服务之间存在强耦合关系时才可以。对于基于微服务的新建应用程序而言,这是一种反模式。
6、异步消息传递微服务设计模式
虽然 REST 设计模式非常流行,但它是同步的,会造成阻塞。因此部分基于微服务的架构可能会选择使用消息队列代替 REST 请求/响应,如下图所示:
思考:意识的转变
微服务对我们的思考,更多的是思维上的转变。对于微服务架构:技术上不是问题,意识比工具重要。
关于微服务的几点设计出发点:
1、应用程序的核心是业务逻辑,按照业务或客户需求组织资源(这是最难的)
2、做有生命的产品,而不是项目
3、头狼战队,全栈化
4、后台服务贯彻 Single Responsibility Principle(单一职责原则)
5、VM->Docker (to PE)
6、DevOps (to PE)
同时,对于开发同学,有这么多的中间件和强大的 PE 支持固然是好事,我们也需要深入去了解这些中间件背后的原理,知其然知其所以然,在有限的技术资源如何通过开源技术实施微服务?
最后,一般提到微服务都离不开 DevOps 和 Docker,理解 微服务架构是核心,devops 和 docker 是工具,是手段。