Spring Cloud是一个基于Spring Boot的快速构建分布式系统的工具集。将Spring Boot开发单个微服务整合在一起。在微服务架构中,需要几个关键的组件,服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等。
Eureka Server作为一个独立的部署单元,提供了注册、管理和查询等操作。可以分为两种:Eureka Server和Eureka Client。Eureka Server也为我们提供了可视化的监控页面,可以直观地看到各个Eureka Server当前的运行状态和所有已注册服务的情况。spring.application.name设置的值作为注册的名字。
Eureka Server可以运行多个实例来构建集群,解决单点问题,EurekaServer是一种去中心化的架构,无master/slave区分。在这种架构中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的serviceUrl指向其他节点。每个节点都可被视为其他节点的副本。如果某台Eureka Server宕机,Eureka Client的请求会自动切换到新的Eureka Server节点,当宕机的服务器重新恢复后,Eureka会再次将其纳入到服务器集群管理之中。
自我保护模式(eureka.server.enable-self-preservation)
自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。
自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现以下几种情况:
- Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
- Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
- 当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。
使用Config Server,可以在所有环境中管理应用程序的外部属性。Spring Cloud缺省配置使用GIT中。所有Web服务均从GIT中获取这些配置文件。由于GIT服务器与具体Web服务器之间不需要共享存储, 只要网络可达就行,从而可以实现Web服务于配置信息的存放位置的解耦。原理图如下:
其中,Webhook作为一个轻量的事件处理应用,向集群中的任何一台机器的/bus/refresh发起post请求,就会同步刷新其它所有节点。
Ribbon是Netflix发布的开源项目,主要功能是为客户端实现负载均衡。Ribbon和RestTemplate一起使用,只需要在RestTemplate的bean上加@LoadBalanced。
分配策略:
(1)选择一个最小的并发请求的server
(2)过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server
(3)根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。
(4)轮询
(5)随机选择
Netflix创建了一个名为Hystrix的库,实现了断路器的模式。“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
在请求失败频率较低的情况下,Hystrix还是会直接把故障返回给客户端。只有当失败次数达到阈值(默认在20秒内失败5次)时,断路器打开并且不进行后续通信,而是直接返回备选响应。当然,Hystrix的备选响应也是可以由开发者定制的。需要在启动类添加@EnableCircuitBreaker。
Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。它整合了Ribbon和Hystrix(Feign.hystrix.enabled=true),从而让我们不再需要显式地使用这两个组件。Feign还提供了HTTP请求的模板,通过编写简单的接口和插入注解,我们就可以定义好HTTP请求的参数、格式、地址等信息。接下来,Feign会完全代理HTTP的请求,我们只需要像调用方法一样调用它就可以完成服务请求。
需要在启动类加上@EnableFeignClients。
主要功能是路由和过滤器
启动类添加@EnableZuulProxy。
继承ZuulFilter类,包括4个方法:
(1)filterType()
filterType返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型:
pre:路由之前,在请求被路由之前调用;
routing:路由之时,将请求路由到微服务;
post: 路由之后,在路由到微服务以后执行。
error:发送错误调用
(2)filterOrder()
过滤器的执行顺序,返回值越小越先执行。
(3)shouldFilter()
是否需要执行此过滤器,可以写逻辑判断,是否要过滤,为true表示永远过滤。
(4)run()
过滤器的具体逻辑