微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务。但若是要将微服务架构运用到生产项目上,而且可以发挥该架构模式的重要做用,则须要微服务框架的支持。前端
在Java生态圈,目前使用较多的微服务框架就是集成了包括Netfilix OSS以及Spring的Spring Cloud。它包括:git
Spring Cloud Config:配置管理工具,支持使用Git存储配置内容,能够实现应用配置的外部化存储,支持客户端配置信息刷新、加密/解密配置内容等。
Spring Cloud Netflix:对Netflix OSS进行了整合。其中又包括:算法
当一个系统的微服务数量愈来愈多的时候,咱们就须要对服务进行治理,提供统一的服务注册中心,而后在其框架下提供发现服务的功能。这样就避免了对多个微服务的配置,以及微服务之间以及与客户端之间的耦合。spring
Spring Cloud Eureka是对Netflix Eureka的包装,用以实现服务注册与发现。Eureka服务端即服务注册中心,支持高可用配置。它依托于强一致性提供良好的服务实例可用性,并支持集群模式部署。Eureka客户端则负责处理服务的注册与发现。客户端服务经过annotation与参数配置的方式,嵌入在客户端应用程序代码中。在运行应用程序时,Eureka客户端向注册中心注册自身提供的服务,并周期性地发送心跳更新它的服务租约。json
搭建服务注册中心bootstrap
服务注册中心是一个独立部署的服务(你能够认为它也是一个微服务),因此须要单独为它建立一个项目,并在pom.xml中添加Eureka的依赖:后端
建立Spring Boot Application:缓存
注册服务提供者安全
要让本身编写的微服务可以注册到Eureka服务器中,须要在服务的Spring Boot Application中添加 @EnableDiscoveryClient 注解,如此才能让Eureka服务器发现该服务。固然,pom.xml文件中也须要添加相关依赖:性能优化
同时,咱们还须要为服务命名,并指定地址。这些信息均可以在application.properties配置文件中配置:
说明:Spring更推荐使用yml文件来维护系统的配置,yml文件能够体现出配置节的层次关系,表现力比单纯的key-value形式更好。若是结合使用后面讲到的Spring Cloud Config,则客户端的配置文件必须命名为bootstrap.properties或者bootstrap.yml。与上述配置相同的yml文件配置为:
服务发现与消费
在微服务架构下,许多微服务可能会扮演双重身份。一方面它是服务的提供者,另外一方面它又多是服务的消费者。注册在Eureka Server中的微服务可能会被别的服务消费。此时,就至关于在服务中建立另外一个服务的客户端,并经过RestTemplate发起对服务的调用。为了更好地提升性能,能够在服务的客户端引入Ribbon,做为客户端负载均衡。
如今假定咱们要为demo-service建立一个服务消费者demo-consumer。该消费者自身也是一个Spring Boot微服务,同时也可以被Eureka服务器注册。这时,就须要在该服务的pom.xml中添加eureka与ribbon的依赖:
而后在主应用类 ConosumerApplication 中注入 RestTemplate ,并引入 @LoadBalanced 注解开启客户端负载均衡:
假设消费demo-service的客户端代码写在demo-consumer服务的其中一个Controller中:
经过 RestTemplate 就能够发起对demo-service的消费调用。
声明式服务调用
经过Ribbon和Hystrix能够实现对微服务的调用以及容错保护,但Spring Cloud还提供了另外一种更简单的声明式服务调用方式,即Spring Cloud Feign。Feign实际上就是对Ribbon与Hystrix的进一步封装。经过Feign,咱们只需建立一个接口并用annotation的方式配置,就能够完成对服务供应方的接口(REST API)绑定。
假设咱们有三个服务:
服务之间的依赖关系以下图所示:
要使用Feign来完成声明式的服务调用,须要在做为调用者的服务中建立Client。Client经过Eureka Server调用注册的对应服务,这样能够解除服务之间的耦合。结构以下图所示:
为了使用Feign,须要对应微服务的pom.xml文件中添加以下依赖:
同时,还须要在被消费的微服务Application中添加 @EnableFeignClients 注解。例如在Statistics服务的应用程序类中:
因为Account服务须要调用Statistics服务,所以须要在Account服务项目中增长对应的client接口:
StatisticsServiceClient接口的 updateStatistics() 方法会调用URI为 /statistics/{accountName} 的REST服务,且HTTP动词为put。这个服务其实对应就是Statistics Service中StatisticsController类中的 saveStatistics() 方法:
在Account服务中,若是要调用Statistics服务,都应该经过StatisticsServiceClient接口进行调用。例如,Account服务中的AccountServiceImpl要调用 updateStatistics() 方法,就能够在该类的实现中经过 @autowired 注入StatisticsServiceClient接口:
Notification服务对Account服务的调用如法炮制。
在微服务架构中,微服务之间可能存在依赖关系,例如Notification Service会调用Account Service,Account Service调用Statistics Service。真实产品中,微服务之间的调用会更加寻常。假若上游服务出现了故障,就可能会由于依赖关系而致使故障的蔓延,最终致使整个系统的瘫痪。
Spring Cloud Hystrix经过实现断路器(Circuit Breaker)模式以及线程隔离等功能,实现服务的容错保护。
仍然参考前面的例子。如今系统的微服务包括:
假设上游服务可能会出现故障,为保证系统的健壮性,须要在下游服务中加入容错包含功能。首先须要在demo-consumer服务中添加对hystrix的依赖:
而后在demo-consumer的应用程序类中加入 @EnableCircuitBreaker 开启断路器功能:
注意:Spring Cloud提供了 @SpringCloudApplication 注解简化如上代码。该注解事实上已经包含了前面所述的三个注解。 @SpringCloudApplication 注解的定义以下所示:
接下来,须要引入一个新的服务类来封装hystrix提供的断路器保护功能,主要是定义当故障发生时须要执行的回调逻辑,即代码中指定的fallbackMethod:
微服务架构将服务的粒度分解的足够细,这使得它在保证服务足够灵活、足够独立的优点下,也带来了管理和监控上的挑战,服务与服务之间的依赖也变得愈来愈复杂。所以,对服务健康度和运行指标的监控就变得很是重要。
Hystrix提供了Dashboard用以监控Hystrix的各项指标信息。为了监控整个系统的微服务,咱们须要为Hystrix Dashboard创建一个Spring Boot微服务。在该服务项目的pom文件中,添加以下依赖:
服务的Application类须要添加 @EnableHystrixDashboard ,以启用Hystrix Dashboard功能。同时,可能须要根据实际状况修改application.properties配置文件,例如选择可用的端口号等。
若是要实现对集群的监控,则须要加入Turbine。
理论上,客户端能够直接向每一个微服务直接发送请求。可是这种方式是存在挑战和限制的,调用者须要知道全部端点的地址,分别对每一段信息执行http请求,而后将结果合并到客户端。
通常而言,针对微服务架构模式的系统,采用的都是 先后端分离 的架构。为了明显地隔离开前端与后端的边界,咱们一般能够专门为前端的消费者定义更加粗粒度的Open Service。这些Open Service是对外的RESTful API服务,能够经过F五、Nginx等网络设备或工具软件实现对各个微服务的路由与负载均衡,并公开给外部的客户端调用(注意,内部微服务之间的调用并不须要经过Open Service)。这种对外公开的Open Service一般又被称为边缘服务(edge service)。
若是这些Open Service须要咱们本身去开发实现并进行服务的运维,在系统规模不断增大的状况下,会变得愈来愈困难。例如,当增长了新的微服务又或者IP地址发生变更时,都须要运维人员手工维护这些路由规则与服务实例列表。又例如针对全部垂直分隔的微服务,不可避免存在重用的横切关注点,例如用户身份认证、受权或签名校验等机制。咱们不能在全部微服务中都去添加这些相同的功能,由于这会形成横切关注点的冗余。
解决的办法是引入API网关(API Gateway)。它是系统的单个入口点,用于经过将请求路由到适当的后端服务或者经过调用多个后端服务并聚合结果来处理请求。此外,它还能够用于认证、insights、压力测试、金丝雀测试(canary testing)、服务迁移、静态响应处理和主动变换管理。Spring Cloud为API网关提供的解决方案就是Spring Cloud Zuul,它是对Netflix Zuul的包装。
在此我向你们推荐一个架构学习交流群。交流学习群号:575745314 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
路由规则与服务实例维护
Zuul解决路由规则与服务实例维护的方法是经过Spring Cloud Eureka。API Gateway自身就是一个Spring Boot服务,该服务自身被注册为Eureka服务治理下的应用,同时它会从Eureka中得到全部其余微服务的实例信息。这样的设计符合DRY原则,由于Eureka已经维护了一套服务实例信息,Zuul直接重用了这些信息,无需人工介入。
对于路由规则,Zuul默认会将服务名做为ContextPath建立路由映射,基本上这种路由映射机制就能够知足微服务架构的路由需求。假若须要一些特殊的配置,Zuul也容许咱们自定义路由规则,能够经过在API网关的Application类中建立PatternServiceRouteMapper来定义本身的规则。
横切关注点
诸如受权认证、签名校验等业务逻辑自己与微服务应用所要处理的业务逻辑没有直接关系,咱们将这些可能横跨多个微服务的功能称为“横切关注点”。这些横切关注点每每会做为“装饰”功能在服务方法的先后被调用。Spring Cloud Zuul提供了一套 过滤器机制 ,容许开发者建立各类过滤器,并指定哪些规则的请求须要执行哪一个过滤器。
自定义的过滤器继承自ZuulFilter类。例如咱们要求客户端发过来的请求在路由以前须要先验证请求中是否包含accessToken参数,若是有就进行路由,不然就拒绝,并返回401 Unauthorized错误,则能够定义AccessFilter类:
要让该自定义过滤器生效,还须要在Zuul服务的Application中建立具体的Bean:
Zuul一共提供了四种过滤器:
下图来自官网,它展示了客户端请求到达Zuul API网关的生命周期与过滤过程:
经过starter添加Zuul的依赖时,自身包含了spring-cloud-starter-hystrix与spring-cloud-starter-ribbon模块的依赖,所以Zuul自身就拥有线程隔离与断路器的服务容错功能,以及客户端负载均衡。可是,假若咱们使用path与url的映射关系来配置路由规则,则路由转发的请求并不会采用HystrixCommand来包装,于是这类路由是没有服务容错与客户端负载均衡做用的。因此在使用Zuul时,应尽可能使用path和serviceId的组合对路由进行配置。
为何要引入一个分布式配置中心?一个微服务就须要至少一个配置文件,怎么管理分散在各个微服务中的配置文件呢?若是微服务采用的是不一样的技术栈,如何来统一微服务的配置呢?微服务是部署在不一样的节点中,显然咱们没法在单机中实现对分布式节点的配置管理。这就是引入Spring Cloud Config的目的。
Spring Cloud Config提供了服务端和客户端支持。服务端是一个独立的微服务,一样能够注册到Eureka服务器中。每一个须要使用分布式配置中心的微服务都是Spring Cloud Config的客户端。Spring Cloud Config默认实现基于Git仓库,既能够进行版本管理,还能够经过本地Git库起到缓存做用。Spring Cloud Config不限于基于Spring Cloud开发的系统,而是能够用于任何语言开发的程序,并支持自定义实现。
配置中心服务端
Spring Cloud Config Server做为配置中心服务端,提供以下功能:
创建一个Config服务,须要添加以下依赖:
服务的Application类须要添加 @EnableConfigServer 注解:
配置服务的基本信息和Git仓库的信息放在application.yml文件中:
在Config服务中配置了Git服务器以及Git库的信息后,咱们就能够在git库中提交配置文件。存储在git库中配置文件的名字以及分支名(默认为master分支)会组成访问Config服务的URI。假设有一个服务为Notification服务,则它在配置中心服务端的配置文件为notification-dev.yml,内容以下:
配置中心客户端
须要读取配置中心服务端信息的微服务都是配置中心的客户端,为了可以读取配置服务端的信息,这些微服务须要:
例如,Account服务的配置是由Spring Cloud Config进行管理的。在它的资源目录下,提供了bootstrap.yml配置文件,内容以下所示:
注意,该配置文件除了配置了该Account服务应用的name以外,主要是支持该应用得到配置服务端的信息。微服务自身的配置信息则统一放到配置中心服务端的文件中,并由Git库进行管理。例如,Account服务的详细配置在配置中心服务端的account-dev.yml文件中:
Spring Cloud Config经过Git实现分布式的配置管理。当配置中心服务端的配置信息发生变动时,各个做为配置客户端的微服务会向Git库提交pull更新,得到最新的配置信息。
固然,Spring Cloud Config还可使用SVN库进行配置管理,也支持简单的本地文件系统的存储方式。此时须要将 spring.profiles.active 设置为native,并设置搜索配置文件的路径。若是不配置路径,默认在 src/main/resources 目录下搜索。以下配置文件:
搜索路径放在classpath下的shared目录下,那么在代码中,目录就是 resources/shared 。若是使用本地文件系统管理配置文件,则没法支持分布式配置管理以及版本管理,所以在生产系统下,仍是推荐使用Git库的方式。
在此我向你们推荐一个架构学习交流群。交流学习群号:575745314 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
在实施微服务时,咱们能够将微服务视为两个不一样的边界。一个是与前端UI的通讯,称为Open Service(Edge Service),经过引入API Gateway来实现与前端UI的通讯。另外一个是在边界内业务微服务之间的通讯,经过Feign实现微服务之间的协做。全部的微服务都会经过Eureka来完成微服务的注册与发现。一个典型的基于Spring Cloud的微服务架构以下所示:
微服务的集成能够经过Feign+Ribbon以RESTful方式实现通讯,也能够基于RPC方式(能够结合Protocol Buffer)完成服务之间的通讯,甚至能够经过发布事件与订阅事件的机制。事件机制可使微服务之间更加松散耦合。这时,咱们能够引入RabbitMQ或Kafka来作到服务与服务之间的解耦。事件机制是异步和非阻塞的,在某些业务场景下,它的性能会更加的好。Spring Cloud也提供了相关的组件Spring Cloud Stream来支持这种事件机制。
对于微服务之间的协做,到底选择Feign这种REST方式、事件机制或者RPC方式,取决于业务场景是否须要同步方式,仍是异步方式;是高性能高并发,仍是普通方式;是要求完全解耦,仍是作到通常的松散耦合。咱们须要针对实际状况做出实际的判断,做出正确的选择。没有谁坏谁好之分,而是看谁更加的适合。