微服务架构——SpringCloud理论学习

SpringCloud学习记录

一、集群和分布式

1.1 什么是集群

计算机集群简称集群是一种计算机系统,它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作。在某种意义上,他们可以被看作是一台计算机。集群系统中的单个计算机通常称为节点,通常通过局域网连接,但也有其它的可能连接方式。集群计算机通常用来改进单个计算机的计算速度和/或可靠性。一般情况下集群计算机比单个计算机,比如工作站或超级计算机性能价格比要高得多。

集群的特点:

  • 通过多台计算机完成同一个工作,以达到更高的效率
  • 两台或多台计算机工作内容、过程完全一样。如果一台死机,其他的也不会有任何影响。

就相当于把一个服务部署到了多个服务器上在运行,用户可以访问到不同的服务器,这样我们每台服务器的压力就会小很多。而且其中一台出问题,另一台依旧可以正常运行。

总结:多个服务器运行一套相同的代码。

1.2 什么是分布式

分布式系统是一组计算机,通过网络相互连接传递消息与通信后并协调它们的行为而形成的系统。组件之间彼此进行交互以实现一个共同的目标

特点:

  • 将一个业务按照不同功能拆分成多个模块,各模块之间协同工作,一起实现某个具体功能。
  • 模块之间独立,各自运行,便于扩展,复用性高

因此,分布式的概念就是将具体任务进行拆分,不同模块部署在不同的服务器上,各自实现一个小功能,多个模块组合起来就能实现我们想要的功能。

总结:不同服务器运行不同的代码,多台服务器协同工作以实现一个共同的目标。

1.3 分布式集群

集群和分布式并不冲突,可以由分布式集群。即做相同的事情多台服务器可以看做是集群的,做不同事情的多台服务器可以看做是分布式的。

参考资料:

  • 分布式与集群的区别是什么?www.zhihu.com/question/20…
  • 分布式、集群、微服务、SOA 之间的区别blog.csdn.net/heatdeath/a…

二、CAP理论

在分布式概念中,我们一般把拆分的一个子业务称作是一个节点。CAP理论主要是指以下三个方面:

  • C:数据一致性(consistency)
    • 所有节点拥有数据的最新版本
  • A:可用性(availability)
    • 数据具有高可用性
  • P:分区容错性(partition-tolerance)
    • 容忍网络出现分区,分区之间网络不可达

下面这个集群有三个节点,此时三个节点都能够互相通信:

微服务架构——SpringCloud理论学习_第1张图片

由于我们的系统是分布式的,节点之间的通信是通过网络来进行的,因此可能会出现因为某些故障使得节点之间不能通信的情况,此时的整个网络就分成了几块区域。数据分散在网络的这些不连通的区域中,这就叫做分区。

微服务架构——SpringCloud理论学习_第2张图片

例如,在出现了网络分区后,有一个注册账户的请求过来了,此时我们节点一和节点三是不可通信的。

微服务架构——SpringCloud理论学习_第3张图片

于是就有了抉择:

  • 如果允许当前用户注册一个账户,此时注册的记录数据只会在节点一和节点二或者节点二和节点三之间同步,而节点一和节点三之间无法实现数据的同步。
    • 这种情况其实就是选择了可用性,抛弃了数据一致性
  • 如果不允许当前用户注册一个账户,必须等到节点一和节点三恢复通信之后才允许注册,这样我们就能保证各节点之间的数据始终是最新版本。
    • 这种情况其实就是抛弃了可用性,选择了数据一致性
CAP理论小结

一般来说,我们的分布式系统要求P:分区容错性是必须的,CAP无法完全兼顾,从上面的例子可以看出,我们可以根据实际情况决定是选择AP还是选择CP。

但是要注意的是,不是说选择了A就完全抛弃了C,选择了C就完全抛弃A。

在CAP理论中,C所表示的一致性是强一致性,即要求每个节点的数据都必须是最新版本,其实一致性还有其他级别:

  • 弱一致性:相对于强一致性而言,他不保证总能得到最新的值。
  • 最终一致性:放宽对时间的限制,在被调完成操作响应后的某个时间点,被调多个节点的数据最终达到一致。

可用性的值域可以定义成**0到100%**的连续区间:

可用性分类 可用水平(%) 年可容忍停机时间
容错可用性 99.9999 <1 min
极高可用性 99.999 <5 min
具有故障自动恢复能力的可用性 99.99 <53 min
高可用性 99.9 <8.8 h
商品可用性 99 <43.8 h

所以CAP理论定义的其实是在容忍网络分区的条件下,“强一致性”和“极致可用性”是无法同时达到的。

参考资料:

  • CAP理论中的P到底是个什么意思?www.zhihu.com/question/54…
  • 浅谈分布式系统的基本问题:可用性与一致性:m.aliyun.com/yunqi/artic…
  • 分布式系统的CAP理论:www.hollischuang.com/archives/66…
  • 为什么CAP理论在舍弃P的情况下,可以有完美的CA?www.zhihu.com/question/28…
  • 不懂点CAP理论,你好意思说你是做分布式的吗?www.yunweipai.com/archives/84…

扩展阅读:

  • 浅谈分布式事务:m.aliyun.com/yunqi/artic…

三、SpringCloud简介

3.1 为什么需要SpringCloud?

从分布式和微服务的角度来看,我们把一个大的项目,分解成多个小的模块。这些小的模块组合起来,共同完成某些功能。注:这些模块是独立成一个子系统的(即部署在不同主机上的)

拆分出多个模块后,就会出现各种各样的问题,而SpringCloud提供了一整套完整的解决方案!

SpringCloud是一个全家桶式的技术栈,包含了很多组件。最核心的几个是Eureka、Ribbon、Feign、Hystrix、Zuul这几个组件

微服务架构——SpringCloud理论学习_第4张图片

3.2 SpringCloud基础功能
  • 服务治理: Spring Cloud Eureka
  • 客户端负载均衡: Spring Cloud Ribbon
  • 服务容错保护: Spring Cloud Hystrix
  • 声明式服务调用: Spring Cloud Feign
  • API网关服务:Spring Cloud Zuul
  • 分布式配置中心: Spring Cloud Config
3.3 SpringCloud的高级功能
  • 消息总线: Spring Cloud Bus
  • 消息驱动的微服务: Spring Cloud Stream
  • 分布式服务跟踪: Spring Cloud Sleuth

四、Eureka详情

像上面提到的,当我们将项目划分为多个模块后,很可能会遇到子系统之间的通信问题。子系统与子系统之间不是在同一个环境下,那么就需要远程调用

远程调用就必须要知道IP地址,此时我们可以通过显示IP地址调用,但是如果很多服务之间都存在着远程调用,并且其中某一个服务的IP地址发生了变化,那么我们所有使用到这个IP地址的地方都要进行手动更新

在服务多的情况下,手动维护这些静态配置简直就是噩梦!

于是为了解决微服务架构中的服务实例维护问题(IP地址),产生了大量的服务治理框架和产品。这些框架和产品的实现都围绕着服务注册服务发现机制来完成对微服务应用实例的自动化管理

在SpringCloud中使用的服务治理框架就是Eureka。针对上面提到的服务间的通信问题,Eureka是这样来解决的:

  • 创建一个服务E,将A、B、C、D……等服务的信息都注册到服务E上,服务E负责维护这些已经注册进来的信息。

微服务架构——SpringCloud理论学习_第5张图片

A、B、C、D四个服务都可以拿到Eureka(服务E)上的那份注册清单。A、B、C、D四个服务相互调用不在通过具体的IP地址,而是通过服务名来调用

  1. 拿到注册清单
  2. 注册清单上有服务名
  3. 从而拿到对应的具体服务的IP地址

其实本质上就是:在代码中通过服务名去Eureka服务器获取到对应的IP地址(IP地址会变,但服务名一般是不会变的)。

Eureka是 Netflix 出品的用于实现服务注册和发现的工具。 SpringCloud 集成了Eureka,并提供了开箱即用的支持。其中,Eureka又可细分为 Eureka Server 和 Eureka Client。

微服务架构——SpringCloud理论学习_第6张图片

上图是来自eureka的官方架构图,他是基于集群配置的eureka。

  • 处于不同节点的eureka通过Replicate进行数据同步
  • Application Service 是服务提供者
  • Application Client 是服务消费者
  • Mark Remote Call 完成一个服务调用

Spring Cloud Eureka是Spring Cloud Netflix微服务套件中的一部分,它基于Netflix Eureka做了二次封装。主要负责完成微服务架构中的服务治理功能。

4.1 服务注册

在服务治理框架中,通常都会构建一个注册中心,每个服务单元向注册中心登记自己提供的服务,包括服务的主机与端口号、服务版本号、通讯协议等一些附加信息。

注册中心按照服务名分类组织服务清单,同时还需要以心跳检测的方式去监测清单中的服务是否可用,若不可用需要从服务清单中剔除,以达到排除故障服务的效果。

服务提供者在启动的时候会通过REST请求的方式将自己注册到Eureka Server上,同时带上自身服务的一些元数据信息。Eureka Server接收到这个Rest请求之后,将元数据信息存储在一个双层结构的Map中,其中第一层的key是服务名。第二层的key 是具体服务的实例名。

在服务注册时,需要确认一下eureka.client.register-with-eureka=true参数是否正确,该值默认为true。若设置为fasle将不会启动注册操作。

4.2 服务发现

在服务治理框架下,服务间的调用不再通过指定具体的实例地址来实现,而是通过服务名发起请求调用实现。服务调用方通过服务名从服务注册中心的服务清单中获取服务实例的列表清单,通过指定的负载均衡策略取出一个服务实例位置来进行服务调用。

Eureka专门用于给其他服务注册的称为Eureka Server(服务注册中心),其余注册到Eureka Server的服务称为Eureka Client。

微服务架构——SpringCloud理论学习_第7张图片

4.3 Eureka服务端

Eureka服务端,即服务注册中心,他支持高可用配置。依托强一致性提供良好的服务实例可用性,可以应对多种不同的故障场景。

Eureka服务端支持集群模式部署,当集群中有分片发生故障时,Eureka会自动转入自我保护模式。它允许在分片发生故障时继续提供服务的发现和注册,当故障恢复时,集群中的其他分片会把他们的状态再次同步回来。集群中的不同服务注册中心通过异步模式互相复制各自的状态,这也意味着在给定的时间点上每个实例关于所有服务的所有服务状态可能存在不一致的情况。

4.3.1 失效剔除

有些时候,我们的服务实例并不一定会正常下线,可能由于内存溢出、网络故障等原因使服务不能正常运作。而服务注册中心并未收到“服务下线”的请求,为了从服务列表中将这些无法正常提供服务的实例剔除掉,Eureka Server在启动的时候会创建一个定时任务(默认60s),默认每隔一段时间将当前服务清单中超时(默认90s)的服务剔除出去

4.3.2 自我保护

服务注册在Eureka Server之后,会维护一个心跳连接,告诉Eureka Server自己还活着。Eureka Server在运行期间会统计心跳失败的比例在15分钟内是否低于85%,如果低于,Eureka Server会将当前的实例注册信息保护起来,让这些实例不会过期,这样的做法会导致客户端很容易拿到那些实际已经不存在的服务实例,出现调用失败的情况。因此客户端要有容错机制,比如请求重试、断路器等。

关于自我保护相关的属性配置:

#可以设置改参数值为false,以确保注册中心将不可用的实例删除
eureka.server.enableSelfPreservation=true
4.3.3 安全验证

当我们启动了Eureka Server,然后在浏览器中输入http://localhost:8761/后,直接回车,就进入了SpringCloud的服务治理页面,这么做在生产环境是极不安全的,下面我们就给Eureka Server加上安全的用户认证:

(1) pom文件中引入依赖

<dependency> 
   <groupId>org.springframework.bootgroupId> 
   <artifactId>spring-boot-starter-securityartifactId> 
dependency> 

(2) serviceUrl中加入安全校验信息

eureka.client.serviceUrl.defaultZone=http://:@${eureka.instance.hostname}:${server.port}/eureka/
4.4 Eureka客户端

Eureka客户端,主要处理服务的注册和发现。客户端服务通过注册和参数配置的方式,嵌入在客户端应用程序的代码中。应用程序启动时,Eureka客户端向注册服务中心注册自身提供的服务,并周期性地发送心跳来更新他的服务租约。同时,他也能从服务端查询当前注册的服务信息,并把他们缓存在本地,并周期性地刷新服务状态。

在服务治理框架中,通常每个客户端服务单元向注册中心登记自己提供的服务,包括服务的主机和端口号、服务版本号、通信协议等附加信息。注册中心按照服务名分类组织服务清单,同时还需要以心跳检测的方式去检测清单中的服务是否可用,若不可用需要从服务清单中剔除,以达到排除故障服务的效果。

Eureka Client分为服务提供者和服务消费者

  • 但很可能,某服务既是服务提供者又是服务消费者
  • 如果SpringCloud的某个服务配置没有"注册"到Eureka-Server也是正常的,很可能只是该服务只是作为单纯的服务消费者,而无需对外提供服务,也就无须注册到Eureka中了
4.4.1 服务提供者
服务注册

服务提供者在启动的时候会通过REST请求的方式将自己注册到Eureka Server上,同时带上自身服务的一些元数据信息。Eureka Server接收到这个Rest请求之后,将元数据信息存储在一个双层结构的Map中,其中第一层的key是服务名。第二层的key 是具体服务的实例名。

在服务注册时,需要确认一下eureka.client.register-with-eureka=true参数是否正确,该值默认为true。若设置为fasle将不会启动注册操作

服务同步

从eureka服务治理体系架构图中可以看到,不同的服务提供者可以注册在不同的服务注册中心上,它们的信息被不同的服务注册中心维护。

此时,由于多个服务注册中心互相注册为服务,当服务提供者发送注册请求到一个服务注册中心时,它会将该请求转发给集群中相连的其他注册中心,从而实现服务注册中心之间的服务同步。通过服务同步,提供者的服务信息就可以通过集群中的任意一个服务注册中心获得。

服务续约

在注册服务之后,服务提供者会维护一个心跳用来持续高速Eureka Server,“我还在持续提供服务”,否则Eureka Server的剔除任务会将该服务实例从服务列表中排除出去。我们称之为服务续约。

下面是服务续约的两个重要属性:

(1)eureka.instance.lease-expiration-duration-in-seconds

leaseExpirationDurationInSeconds,表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则将移除该instance。

  • 默认为90秒
  • 如果该值太大,则很可能将流量转发过去的时候,该instance已经不存活了。
  • 如果该值设置太小了,则instance则很可能因为临时的网络抖动而被摘除掉。
  • 该值至少应该大于leaseRenewalIntervalInSeconds

(2)eureka.instance.lease-renewal-interval-in-seconds

leaseRenewalIntervalInSeconds,表示eureka client发送心跳给server端的频率。如果在leaseExpirationDurationInSeconds后,server端没有收到client的心跳,则将摘除该instance。除此之外,如果该instance实现了HealthCheckCallback,并决定让自己unavailable的话,则该instance也不会接收到流量。

  • 默认30秒
服务下线

在系统运行过程中必然会面临关闭或重启服务的某个实例的情况,在服务关闭操作时,会触发一个服务下线的Rest服务请求给Eureka Server,告诉服务注册中心:“我要下线了”,服务端在接收到该请求后,将该服务状态置位下线(DOWN),并把该下线事件传播出去。

4.4.2 服务消费者
获取服务

消费者服务启动时,会发送一个Rest请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑,Eureka Server会维护一份只读的服务注册清单来返回给客户端,同时该缓存清单默认会每隔30秒更新一次。

下面是获取服务的两个重要的属性:

(1)eureka.client.fetch-registry

是否需要去检索寻找服务,默认是true

(2)eureka.client.registry-fetch-interval-seconds

表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒

服务调用

服务消费者在获取服务清单后,通过服务名可以获取具体提供服务的实例名和该实例的元数据信息。因为有这些服务实例的详细信息,所以客户端可以根据自己的需要决定具体调用哪个实例,在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。

4.5 Eureka Server相关配置

在默认配置下,Eureka Server 会将自己也作为客户端,即在注册中心注册自己,我们一般需要将其禁用:

#服务注册中心端口号
server.port=8761

#服务注册中心实例的主机名
eureka.instance.hostname=localhost

#是否向服务注册中心注册自己
eureka.client.register-with-eureka=false

#是否检索服务
eureka.client.fetch-registry=false

#服务注册中心的配置内容,指定服务注册中心的位置
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

优秀博文:

  • Spring Cloud Eureka详解:blog.csdn.net/sunhuiliang…
  • 《Spring Cloud Netflix》 – 服务注册和服务发现-Eureka 的使用:zhuanlan.zhihu.com/p/26472547
  • 微服务架构:Eureka参数配置项详解:www.cnblogs.com/fangfuhai/p…
  • SpringCloud 原理,通俗易懂:https://blog.csdn.net/z_hongchang/article…

五、Feign

现在我们已经可以通过服务名来获取具体服务实例的IP地址了,接下来就是实现远程调用,传统情况下在Java代码里访问RESTful服务,一般使用Apache的HttpClient,不过此种方法使用起来太过繁琐。在使用SpringCloud的时候我们不需要自己创建HttpClient来进行远程调用。可以使用Spring封装好的RestTemplate工具类:

// 传统的方式,直接显示写死IP是不好的!
//private static final String REST_URL_PREFIX = "http://localhost:8001";

// 服务实例名
private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";

/**
  * 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap,
  * ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
  */
@Autowired
private RestTemplate restTemplate;

@RequestMapping(value = "/consumer/dept/add")
public boolean add(Dept dept) {
    return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
}

Feign是一个声明式http客户端。使用Feign能让编写http客户端更加简单,它的使用方法是定义一个接口,然后在上面添加注解,避免了调用目标微服务时,需要不断的解析/封装json数据的繁琐。Spring Cloud中Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果。

// value --->指定调用哪个服务
// fallbackFactory--->熔断器的降级提示
@FeignClient(value = "MICROSERVICECLOUD-DEPT")
public interface DeptClientService {

    // 采用Feign我们可以使用SpringMVC的注解来对服务进行绑定
    @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
    public Dept get(@PathVariable("id") long id);

    @RequestMapping(value = "/dept/list", method = RequestMethod.GET)
    public List<Dept> list();

    @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
    public boolean add(Dept dept);
}

Feign的一个关键机制就是使用了动态代理。一起来看看下面的图,结合图来分析:

  • 首先,如果你对某个接口定义了@FeignClient注解,Feign就会针对这个接口创建一个动态代理
  • 接着你要是调用那个接口,本质就是会调用 Feign 创建的动态代理,这是核心中的核心
  • Feign的动态代理会根据你在接口上的@RequestMapping等注解,来动态构造出你要请求的服务的地址
  • 最后针对这个地址,发起请求、解析响应

微服务架构——SpringCloud理论学习_第8张图片

六、Ribbon负载均衡

为了实现服务的高可用,我们可以将服务提供者集群。比如说,现在一个秒杀系统设计出来了,准备上线了。在双十一的时候为了能够支持高并发,我们多开几台机器来支持并发量。

微服务架构——SpringCloud理论学习_第9张图片

现在想要这三个秒杀系统合理摊分用户的请求,Feign怎么知道该请求哪台机器呢?

这时Spring Cloud Ribbon就派上用场了。Ribbon就是专门解决这个问题的。它的作用是负载均衡,会帮你在每次请求时选择一台机器,均匀的把请求分发到各个机器上。

负载均衡有两种类型:

  • 客户端负载均衡(Ribbon)
    • 服务实例的清单在客户端,客户端进行负载均衡算法分配。
    • 从上面的知识我们已经知道了:客户端可以从Eureka Server中得到一份服务清单,在发送请求时通过负载均衡算法,在多个服务器之间选择一个进行访问
  • 服务端负载均衡(Nginx)
    • 服务实例的清单在服务端,服务器进行负载均衡算法分配

所以,我们的图可以画成这样:

微服务架构——SpringCloud理论学习_第10张图片

Ribbon默认的负载均衡策略是轮询,我们也是可以根据自己实际的需求自定义负载均衡策略的。

@Configuration
public class MySelfRule
{
	@Bean
	public IRule myRule()
	{
		//return new RandomRule();// Ribbon默认是轮询,我自定义为随机
		//return new RoundRobinRule();// Ribbon默认是轮询,我自定义为随机
		
		return new RandomRule_ZY();// 我自定义为每台机器5次
	}
}

实现起来也很简单:继承AbstractLoadBalancerRule类,重写public Server choose (ILoadBalancer lb, Object key)即可。

此外,Ribbon是和Feign以及Eureka紧密协作,完成工作的,具体如下:

  • 首先Ribbon会从 Eureka Client里获取到对应的服务注册表,也就知道了所有的服务都部署在了哪些机器上,在监听哪些端口号。
  • 然后Ribbon就可以使用默认的Round Robin算法,从中选择一台机器
  • Feign就会针对这台机器,构造并发起请求。

微服务架构——SpringCloud理论学习_第11张图片

(贴一篇博文,后面在深入了解Ribbon)

优秀博文:

  • 撸一撸Spring Cloud Ribbon的原理-负载均衡策略:www.cnblogs.com/kongxiangha…

七、Hystrix

在微服务架构里,一个系统会有很多的服务。比如以下业务场景:订单服务在一个业务流程里需要调用库存服务、仓储服务、积分服务这三个服务。现在假设订单服务自己最多只有100个线程可以处理请求,然后呢,积分服务不幸的挂了,每次订单服务调用积分服务的时候,都会卡住几秒钟,然后抛出—个超时异常。

这样会导致什么问题呢?

  1. 如果系统处于高并发的场景下,大量请求涌过来的时候,订单服务的100个线程都会卡在请求积分服务这块。导致订单服务没有一个线程可以处理请求
  2. 然后就会导致别人请求订单服务的时候,发现订单服务也挂了,不响应任何请求了

上面这个,就是微服务架构中恐怖的服务雪崩问题,如下图所示:

微服务架构——SpringCloud理论学习_第12张图片

如上图,这么多服务互相调用,要是不做任何保护的话,某一个服务挂了,就会引起连锁反应,导致别的服务也挂。比如积分服务挂了,会导致订单服务的线程全部卡在请求积分服务这里,没有一个线程可以工作,瞬间导致订单服务也挂了,别人请求订单服务全部会卡住,无法响应。

Hystrix是隔离、熔断以及降级的一个框架。简单来说就是,Hystrix会搞很多个小小的线程池,比如订单服务请求库存服务是一个线程池,请求仓储服务是一个线程池,请求积分服务是一个线程池。每个线程池里的线程就仅仅用于请求那个服务。

此时如果积分服务挂了,那么订单服务里用来调用积分服务的线程也就都卡死不能工作了,但由于订单服务调用库存服务、仓储服务的这两个线程池都是正常工作的,所以这两个服务不会受到任何影响。这个时候如果别人请求订单服务,订单服务还是可以正常调用库存服务扣减库存,调用仓储服务通知发货。只不过调用积分服务的时候,每次都会报错。**但是如果积分服务都挂了,每次调用都要去卡住几秒钟也没有意义!**所以我们可以直接对积分服务熔断,比如在5分钟内请求积分服务直接返回,不再进行网络请求卡住几秒钟,这个过程,就是所谓的熔断!

此时为了记录用户积分,可以在每次调用积分服务时,在数据库里新增一条积分记录,说给某某用户增加多少积分,因为积分服务挂了,导致没增加成功!这样等积分服务恢复了,就可以根据这些记录手工加一下积分。这个过程,就是所谓的降级。

Hystrix隔离、熔断和降级的全流程:

微服务架构——SpringCloud理论学习_第13张图片

Spring Cloud Hystrix实现了断路器、线程隔离等一系列服务保护功能。

  • Fallback(失败快速返回):当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝), 向调用方返回一个错误响应, 而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延
  • 资源/依赖隔离(线程池隔离):它会为每一个依赖服务创建一个独立的线程池,这样就算某个依赖服务出现延迟过高的情况,也只是对该依赖服务的调用产生影响, 而不会拖慢其他的依赖服务

Hystrix提供几个熔断关键参数:滑动窗口大小(20)熔断器开关间隔(5s)错误率(50%)

  • 每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。
  • 直到5s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开

参考资料:

  • Hystrix ,为什么说它是每个系统不可或缺的开源框架?zhuanlan.zhihu.com/p/34304136
  • 深入理解Hystrix之文档翻译:zhuanlan.zhihu.com/p/28523060
  • 谈谈我对服务熔断、服务降级的理解:blog.csdn.net/guwei911198…
  • Hystrix几篇文章《青芒》:segmentfault.com/u/yedge/art…

八、Zuul

基于上面的学习,我们现在的架构大致会设计成这样:

微服务架构——SpringCloud理论学习_第14张图片

这样的架构会有两个比较麻烦的问题:

  1. 路由规则与服务实例的维护间题:外层的负载均衡(nginx)需要维护所有的服务实例清单(图上的OpenService)
  2. 签名校验、 登录校验冗余问题:为了保证对外服务的安全性, 我们在服务端实现的微服务接口,往往都会有一定的权限校验机制,但我们的服务是独立的,我们不得不在这些应用中都实现这样一套校验逻辑,这就会造成校验逻辑的冗余。

为了解决上面这些常见的架构问题,API网关的概念应运而生。在SpringCloud中了提供了基于Netfl ix Zuul实现的API网关组件Spring Cloud Zuul这个组件是负责网络路由的

Spring Cloud Zuul是这样解决上述两个问题的:

  • SpringCloud Zuul通过与SpringCloud Eureka进行整合,将自身注册为Eureka服务治理下的应用,同时从Eureka中获得了所有其他微服务的实例信息。外层调用都必须通过API网关,使得将维护服务实例的工作交给了服务治理框架自动完成
  • 在API网关服务上进行统一调用来对微服务接口做前置过滤,以实现对微服务接口的拦截和校验

Zuul天生就拥有线程隔离和断路器的自我保护功能,以及对服务调用的客户端负载均衡功能。也就是说:Zuul也是支持Hystrix和Ribbon

Zuul支持Ribbon和Hystrix,也能够实现客户端的负载均衡。我们的Feign不也是实现客户端的负载均衡和Hystrix的吗?既然Zuul已经能够实现了,那我们的Feign还有必要吗?

微服务架构——SpringCloud理论学习_第15张图片

可以这样理解:

  • zuul是对外暴露的唯一接口相当于路由的是controller的请求,而Ribbonhe和Fegin路由了service的请求
  • zuul做最外层请求的负载均衡 ,而Ribbon和Fegin做的是系统内部各个微服务的service的调用的负载均衡

参考资料:

  • 微服务与API网关(上): 为什么需要API网关?:blog.didispace.com/hzf-ms-apig…
  • 谈谈 API 网关:www.jianshu.com/p/b52a2773e…
  • 谈谈微服务中的 API 网关(API Gateway):www.cnblogs.com/savorboard/…
  • API网关性能比较:NGINX vs. ZUUL vs. Spring Cloud Gateway :www.360doc.com/content/18/…
  • 谈API网关的背景、架构以及落地方案:www.infoq.com/cn/news/201…
  • zuul和nginx:zhuanlan.zhihu.com/p/37385481

九、SpringCloud Config

随着业务的扩展,我们的服务会越来越多,越来越多。每个服务都有自己的配置文件。

既然是配置文件,给我们配置的东西,那难免会有些改动的。

比如我们的Demo中,每个服务都写上相同的配置文件。万一我们有一天,配置文件中的密码需要更换了,那就得三个都要重新更改

Spring Cloud Config项目是一个解决分布式系统的配置管理方案。它包含了Client和Server两个部分,server提供配置文件的存储、以接口的形式将配置文件的内容提供出去,client通过接口获取数据、并依据此数据初始化自己的应用

  • 简单来说,使用Spring Cloud Config就是将配置文件放到统一的位置管理(比如GitHub),客户端通过接口去获取这些配置文件。
  • 在GitHub上修改了某个配置文件,应用加载的就是修改后的配置文件。

SpringCloud Config其他的知识:

  • 在SpringCloud Config的服务端, 对于配置仓库的默认实现采用了Git,我们也可以配置SVN。
  • 配置文件内的信息加密和解密
  • 修改了配置文件,希望不用重启来动态刷新配置,配合Spring Cloud Bus 使用~

使用SpringCloud Config可能的疑问:application.yml和 bootstrap.yml区别

  • www.cnblogs.com/BlogNetSpac…

十、总结

上述几个Spring Cloud核心组件,在微服务架构中,分别扮演的角色:

  • Eureka:各个服务启动时,Eureka Client都会将服务注册到Eureka Server,并且Eureka Client还可以反过来从Eureka Server拉取注册表,从而知道其他服务在哪里
  • Ribbon:服务间发起请求的时候,基于Ribbon做负载均衡,从一个服务的多台机器中选择一台
  • Feign:基于Feign的动态代理机制,根据注解和选择的机器,拼接请求URL地址,发起请求
  • Hystrix:发起请求是通过Hystrix的线程池来走的,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题
  • Zuul:如果前端、移动端要调用后端系统,统一从Zuul网关进入,由Zuul网关转发请求给对应的服务

SpringCloud系列文章参考资料:

  • 史上最简单的 SpringCloud 教程 | 终章blog.csdn.net/forezp/arti…
  • Spring Cloud基础教程《程序员DD》blog.didispace.com/Spring-Clou…
  • Spring Cloud 系列文章《纯洁的微笑》:www.ityouknow.com/spring-clou…
  • SpringCloud系列文章:www.cnblogs.com/woshimrf/ta…
  • SpringCloud系列文章《狂小白》:www.cnblogs.com/huangjuncon…
  • SpringCloud官方文档:projects.spring.io/spring-clou…
  • Spring Cloud 中文文档:springcloud.cc/spring-clou…
  • Spring Cloud原理详解:https://blog.csdn.net/qq_41701956/article…
  • SpringCloud微服务(原理篇):https://blog.csdn.net/shinlyzsljay/article…
  • Spring Cloud原理分析及使用:https://blog.csdn.net/richard_vi/article…
  • 面试必问的SpringCloud实现原理图:https://m.imooc.com/article…
  • 面试必问的SpringCloud实现原理图:http://www.cnblogs.com/sessionbest…

你可能感兴趣的:(Spring,Java,分布式,spring,cloud,java,分布式)