SpringCloud

一,SpringCloud概述:

1)SpringCloud是什么?

  1. SpringCloud是什么?
  2. 答:SpringCloud是一个微服务框架的规范,而微服务是一种架构模式,将一个完整的项目根据不同的业务模块拆分成多个小的项目,即,服务模块,每个服务模块独立的运行在一个tomcat容器中,每个服务模块甚至可以有自己独立的数据库。

2)SpringCloud有哪些特点?

特点:
    - Spirng Cloud 天然支持 Spring Boot。
     - 实现了:高内聚,低耦合.
    - eureka组件实现了:服务的注册与发现 的功能;
    - Feign + Ribbon组件实现了:服务之间的调用和负载均衡 的功能;
    - Hystrix组件实现了:服务的降级,服务的熔断(即,断路器) 的功能;
    - config组件实现了:分布式的配置管理(通过git管理) 的功能;
    - Zuul组件实现了:路由/网关 的功能;
    - Sleuth组件实现了:服务的链路追踪的功能;

3)SpringCloud和Dubbo的区别:

 1.分布式通信的方式不同:
                    基于http的RESTful方式.        : springcloud    
                     基于RPC方式.                  : dubbo

 2.注册中心不同:
             dubbo: zookeeper(CP,数据一致性,分区容错性)
                springcloud: eureka(AP,服务可用性,分区容错性)

 3.SpringCloud还比Dubbo多实现了这几个功能: 

             Feign + Ribbon.  -  服务的调用和负载均衡.

            Hystrix   -  服务的降级,服务的熔断.

            config   -  分布式配置管理.(通过git管理)

            zuul      -   网关. (filter)

4)SpringCloud六大组件:

eureka   -  服务的注册与发现.

Feign + Ribbon.  -  服务的调用和负载均衡.

Hystrix   -  服务的降级,服务的熔断.

config   -  分布式配置管理.(通过git管理)

zuul      -   网关. (filter)

Sleuth  -  服务追踪

二,Eureka

1. Eureka是什么?

    Eureka在springcloud中作为一个服务的注册与发现的关键组件.
     是以一个单独的项目的形式,作为注册中心。

2. Eureka的自我保护机制

1、定义
    自我保护机制是一种针对网络异常波动的安全保护措施,使用自我保护机制能使Eureka集群更加的健壮、稳定的运行。

2、客户端的心跳机制:
    在默认情况下,eureka的客户端默认是每30秒给eureka发送一次心跳,90秒没发送,eureka就认为该客户端宕机了.

3、工作机制
    自我保护机制的工作机制是:如果在15分钟内超过85%的客户端都没有正常的心跳,那么Eureka就认为是客户端与注册中心出现了网络故障,于是Eureka会自动进入自我保护机制,此时会出现以下几种情况:
     Eureka Server(Eureka服务注册中心)不再从注册列表中移除因长时间没有心跳而应该过期的服务。
     Eureka Server仍然能够接受新服务的注册和发现请求,但是不会同步到其它的节点上,保证当前的节点依然可用。
     当网络稳定时,Eureka Server会将新的注册信息同步到其它节点中。

4、优点
    Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像ZK那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。
    自我保护模式的架构哲学就是:AP,服务可用性、分区容错性;用通俗的语言说就是:好死不如赖活着。

4、问题
    在自我保护机制的安全模式下,Eureka不会即使的剔除掉不可用的节点,所以会造成访问不可用节点的问题,出现Connection Refuse(连接被拒绝的现象)

5、解决方案
    由服务订阅者添加重连或断路器来解决此问题,无论服务有没有被及时的剔除,订阅端在引入ribbon包后,默认开启ribbon重试机制.

3. Eureka的高可用—集群配置:

    Eureka的集群是不存在什么主从结构的,你只要多开几台tomcat容器,就可以将一个Eureka集群搭建出来;

Eureka集群的配置:
        1. 每台eureka节点都注册到其他的eureka注册中心上
        2. 这样eureka节点之间就可以互相拉取数据,保持数据同步;
        3. 当一台eureka挂掉之后,客户端还可以继续使用其他的eureka,保证了eureka的高可用;

eg:

比如:
    eureka1的端口号是8761,eureka2的端口号是8762,
    那么eureka1的service-url为8762,eureka2的service-url为8761,这样就做到了eureka1可以拉取到eureka2上面的注册信息,eureka2也可以拉取到了eureka1上面的注册信息,做到了eureka节点之间的数据同步。 
--------------------------------------
1. 搭建多台eureka,并保证通讯.
(8761节点)
server:
  port: 8761
eureka:
  instance:
    hostname: 127.0.0.1           # 避免搭建集群时,导致无法拉取信息
  client:
    register-with-eureka: true  # false意味着不注册到注册中心中(单机版使用);官方推荐为true
    fetch-registry: true            # false意味着不从其他eureka上面拉取信息. (单机版使用)
    service-url:
      defaultZone: http://localhost:8762/eureka/   #  指定其他的eureka注册中心的地址

(8762节点)
server:
  port: 8762
eureka:
  instance:
    hostname: 127.0.0.1           # 避免搭建集群时,导致无法拉取信息
  client:
    register-with-eureka: true   # false意味着不注册到注册中心中(单机版使用);官方推荐为true
    fetch-registry: true            # false意味着不从其他eureka上面拉取信息. (单机版使用)
    service-url:
      defaultZone: http://localhost:8761/eureka/   # 指定其他的eureka注册中心的地址

    这样就可以 在eureka1上看到eureka1和eureka2的服务信息.
             在eureka2上看到eureka1和eureka2的服务信息.

-------------------------------------------- 
客户端注册时,要指定多台eureka的信息
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/   #  指定注册中心的地址

4. Eureka安全认证机制

    eureka在更新到2.x之后,添加安全机制,即,csrf过滤.
    但是csrf将微服务的注册也给过滤了,所有的微服务都无法注册到注册中心上。 

     办法就是:手动关闭csrf,即可正常完成服务注册,且不影响登录注册中心.

三,feign+Ribbon

1)Springcloud中feign的作用

    在Spring Cloud中,各个服务模块都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时(即,调用其他的服务模块)就必须使用HTTP客户端。
    HTTP客户端有很多种,比如:JDK原生的URLConnection、Apache的Http Client、Spring的RestTemplate。
    但是在SpringCloud中,用起来最方便的还是要属Feign了。

    feign是一个单独的组件,是一种声明式、模板化的HTTP客户端。它实现服务之间的相互调用,并隐藏调用细节。
    在Spring Cloud中使用Feign, 可以做到使用HTTP请求远程服务时,与调用本地方法一样的编码体验。
    开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。

feign传递参数.

1. 简单的参数.      ->      推荐使用@PathVariable
2. 复杂的参数.      ->      使用json传参.(提供者方必须是@Post)

2)Springcloud中Ribbon的作用—为客户端实现负载均衡

Ribbon的介绍: 

    在微服务架构中,会有很多服务,每个服务有可能会有多个实例,为了治理这些服务,我们可以通过eureka注册中心来实现。
    解决完服务管理后,还有问题,当某个服务(消费者)希望调用其它服务(提供者)的时候,通常会通过eureka去查询服务(提供者)的列表,然后eureka返回提供者的所有实例,那么消费者应该调用哪个提供者呢?

     Feign 中自带Ribbon,Ribbon的主要功能是:帮助客户端去决定选择哪个提供者,提供负载均衡算法。

     简单的说, Ribbon是⼀个微服务客户端的负载均衡器,和微服务提供者端没什么关系。

     Ribbon默认采用轮询的方式,(这里一般也不用去改负载均衡的方式,轮询就是最好的负载均衡方式)

如图所示:

6_SpringCloud以及它的六大组件 - 图1

四,Hystrix

1)什么是服务雪崩:

6_SpringCloud以及它的六大组件 - 图2

    这是几个服务,假设A服务调用B服务,B服务调用C服务,C服务调用D服务,...
    当C服务出现问题时,即C服务挂掉了;那么线程会一直阻塞在B服务那里,于是B服务也挂掉了;于是连锁反应,A服务紧接着也挂掉了。
    这就是服务模块的雪崩。和缓存雪崩有一些些的类似。

2)Hystrix的功能:

1. 快速失败策略,避免服务雪崩.
        如果一个服务出现了问题,导致线程一直阻塞在那里,hytrix会启动快速失败策略,从而避免服务雪崩;

2. 舱壁模式,实现依赖隔离
        详见下一段;


3. hystrix提供了熔断器机制,(即,熔断策略)
        详见下下一段;

3)Hystrix的限流、依赖隔离-线程池隔离方式

图一,依赖隔离之前:

6_SpringCloud以及它的六大组件 - 图3

图二,依赖隔离之后:

6_SpringCloud以及它的六大组件 - 图4

    依赖,指的是各个服务模块之间互相调用,即互相依赖,通俗的来说就是牵一发而动全身的意思,一个服务挂掉导致所有的服务跟着完蛋,即产生了服务雪崩。
    依赖的隔离,使得不同的服务之间不会互相影响,保证了服务的稳定。

    前提:一个业务对多个的服务的调用请求,会先进入到一个hystrix定义的共有线程池,然后再切换由hystrix线程池中的线程去真正执行对多个的服务的调用。

舱壁模式-线程池隔离:
       货船为了进行防止漏水和火灾的扩散,会将货仓分隔为多个,这种资源隔离减少风险的方式被称为: 舱壁模式。
       Hystrix将同样的模式运用到了对服务的调用上,在一个微服务系统中,一个业务逻辑通常会依赖多个服务,比如:商品详情业务会依赖商品服务、价格服务、商品评论服务。

     没有舱壁模式时,商品详情业务 对多个服务模块的调用 是使用 hystrix定义的共有线程池中 的线程们来执行调用的,在高并发的情况下,一个性能较低的服务会一直“霸占”着 共有线程池中的绝大多数线程,而对其它正常的服务的调用请求 则需要等待线程资源的释放。
     最终,导致一个个正常的服务被拖垮掉,即发生了服务雪崩。

     解决办法就是Hystrix的舱壁模式,将共有的这一个线程池拆分为多个小的线程池,即,为每一个服务提供一个单独的小线程池,使得一个业务对多个服务的调用请求由不同的线程池创建线程,然后去向服务提供者发送请求。

    这种线程池隔离的方式,使得不同的服务之间不会互相影响,能够保证服务的稳定。

3)Hystrix的限流、依赖隔离-信号量机制

### 信号量机制

    信号量的资源隔离只是起到一个开关的作用,比如,服务 A 的信号量大小为 10,那么就是说它同时只允许有 10 个 tomcat 线程(用户线程)来访问服务 A,其它的请求都会被拒绝,从而达到资源隔离和限流保护的作用。

6_SpringCloud以及它的六大组件 - 图5

### 线程池与信号量区别

    线程池隔离技术,是用 Hystrix 自己的线程去执行对服务的调用;

    而信号量隔离技术,是直接让 tomcat 线程去执行对服务的调用。信号量隔离,只是一道关卡,信号量有多少,就允许多少个 tomcat 线程通过它,然后去执行对服务的调用。

4)Hystrix的熔断器机制:

    我们在各种场景下都会接触到熔断这两个字。高压电路中,如果某个地方的电压过高,熔断器就会熔断,对电路进行保护。股票交易中,如果股票指数过高,也会采用熔断机制,暂停股票的交易。同样,在微服务架构中,熔断机制也是起着类似的作用。

    熔断机制是为了避免服务器产生雪崩效应而产生的一种微服务链路保护机制。在高并发的情况下,流量超出了设置的阈值,或者当服务器达到最大的承受能力之后,直接熔断外界对该服务模块的调用,即拒绝外界访问该服务。然后调用降级方法,返回给用户一个友好提示。之后当检测到流量恢复正常后,再恢复外界对该服务模块的调用。

     熔断的目的:为了防止服务宕机(保护服务),会进行熔断处理。

    熔断需要和服务降级一起使用。

熔断器与线程池(隔离):    
    熔断器是位于线程池之前的组件。用户请求某一服务之后,Hystrix会先经过熔断器,此时如果熔断器的状态是打开(跳起),则说明已经熔断,这时将直接进行服务降级处理,不会继续将请求发到线程池。
    熔断器相当于是在线程池之前的一层屏障。
----------------------------------------
熔断的原理和三种状态:

    Closed:熔断器关闭状态,调用失败次数积累,到了指定的阈值(或一定比例)后,则启动熔断机制;

    Open:熔断器打开状态,此时断掉外界对该服务模块的调用,即拒绝外界访问该服务,然后调用服务降级方法,返回给用户一个友好的提示。但还设计了一个时钟选项,当时钟达到了一定的时间后(这个时间一般设置成平均故障处理时间,也就是MTTR),熔断器进入半熔断状态;

    Half-Open:半熔断状态,允许一定量的请求 尝试调用该服务,如果都调用成功了(或一定比例成功了),则认为服务恢复正常了,于是关闭熔断器。反之认为服务还没恢复好,熔断器再次返回为打开状态;

五,config组件

1)config组件的介绍:

    在Spring Cloud中,由于服务数量众多,为了方便将服务的配置文件统一管理,实时更新,所以出现了分布式配置组件,即spring cloud config。
    config它支持将服务的配置文件放到内存中(即本地),也支持放到远程Git仓库中。
    在spring cloud config 组件中,分两个角色,一是config server,二是config client。

动态更新配置:
    SpringCloud Bus组件负责帮config组件,实现动态更新配置;

2)config执行流程:

6_SpringCloud以及它的六大组件 - 图6

    第一步:config server会拉取远程Git仓库(比如GitHub、码云)里面的配置文件上的信息到自身;

    第二步:同时,config server 再将从Git上拉取到的信息,放到本地的磁盘上,即本地git仓库中;

    第三步:config server 将自己注册到eureka注册中心上面;

     第四步:config client,(比如order服务,就是一个消费者),它会找到eureka,订阅config server,然后直接锁定config server,拉取到order的相关配置信息到自身;

六,Zuul路由/网关

1. Zuul的特点.

网关作为服务的入口,承担着很重要的角色.
    1. 高可用 -- 必须做到7 * 24热部署.
    2. 高性能 --能够承受很高的并发量
    3. 安全性 --比如:反爬虫 
    4. 高扩展性.  --比如:某个服务模块拆分成了两个之后,只需要在网关上动态的做一些配置就行了

6_SpringCloud以及它的六大组件 - 图7

2. 常见的路由/网关:

常见的网关:
    nginx:    (很多的网关的底层都是基于nginx做成的),安全性,高性能.高扩展性,7 * 24热部署,高可用 -> keepalived监视器.
    tengine: 淘宝基于nginx二次封装的一个网关,添加一些插件.
    kong: 基于nginx二次封装,收费.
    zuul: zuul优点在于springcloud的生态圈中使用起来很方便. 性能根本不能和nginx相提并论.

3. Zuul的核心:

zuul的特点.
    1. zuul的核心就是过滤器.
    2. 过滤器的类型:
        Pre前置过滤器 - Route路由过滤器 - Post后置过滤器 - error错误过滤器

4. Zuul的执行流程:

zuul的执行流程 | 生命周期:(如下图所示)

1    客户端发送一个HTTP请求;
2    请求到达zuul的前置过滤器(prefilters);
3    然后再到达路由过滤器(routingfilters);
4    然后路由过滤器将请求分发给指定的服务模块(比如order订单服务);
5    服务模块处理请求;
6    服务模块处理完成之后,再将处理结果响应给routingfilters路由过滤器;(或者直接返回错误信息给errorfilters错误过滤器)
7    然后路由过滤器将响应结果传递给postfilters后置过滤器;
8    再由postfilters后置过滤器将响应结果返回给客户端;

6_SpringCloud以及它的六大组件 - 图8

5. Zuul的限流.


    限流有很多种方式,比较常见的有:hystrix的线程池隔离方式、信号量机制,以及Zuul的漏桶算法和令牌桶算法这几种;

1. hystrix中的两种线程隔离方式.
    hystrix的线程池.
    信号量.


2. 令牌桶算法:

    prefilters前置过滤器中的 令牌桶算法.(如下图所示)

    我们规定,以固定的速率往令牌桶中放置一定数量的令牌,如果令牌桶满了就将再来的令牌丢弃掉;
    客户端请求到达zuul网关的prefilters前置过滤器时,必须先尝试去令牌桶中获取一个令牌,
    如果该请求获取到了令牌,则放行;
    如果桶中没有令牌了,则请求没有获取到令牌,则zuul直接拒绝掉这个请求,
    就这样达到了 限流 的效果;

6_SpringCloud以及它的六大组件 - 图9


七. Sleuth+Zipkin

1. Sleuth介绍.


Sleuth:
    Sleuth也是springcloud中的一个组件. 这个组件被称为服务追踪.
    主要是用来监控:所有的服务之间调用的情况,它可以追踪一个请求的处理行踪,先到哪了又到哪了...,并且每一个服务执行的时间是多久,是哪个服务的卡顿导致了请求执行了这么长时间。 

----------------------    

Zipkin:    
     zipkin是Sleuth的一个可视化工具。
     Sleuth将服务追踪的信息存储到了日志里面,但日志不方便我们查看,所以用zipkin可视化工具来配合Sleuth做服务的追踪与监控。
    zipkin并不是springcloud中的组件,是一个单独的外界组件,只是被springcloud整合到了一起.

2. sleuth+zipkin+RabbitMQ.

     zipkin只有一台的话,存在单点故障.
    如果服务连接多台zipkin,也会带来不必要的消耗.
    办法就是:服务将sleuth链路追踪的信息发送到mq中,然后zipkin去接收mq中的信息即可.

4. Sleuth + Zipkin + RabbitMQ + ES

问题:
    默认情况下,Zipkin会将跟踪信息存储在内存中;
    这样导致的问题是: 
        每次重启Zipkin Server后,都会使之前收集的 链路跟踪数据 全部丢失掉,
        并且当有大量跟踪数据时,内存存储也会造成性能瓶颈;

办法:
    所以通常我们都会将链路跟踪信息存储到外部的组件中,如 Mysql、ES。

    存到mysql中的话,速度太慢了,而且zipkin中的信息也是比较多的,所以不推荐这种方式;

     最合适的办法就是: 让zipkin将数据全部持久化到es中。

八. springcloud的整体架构.

1)SpringCloud的常见组件以及执行流程:

大致流程:

    客户端请求先到达nginx,(因为zuul的性能一般(用它主要是因为它属于SpringCloud家族,“有背景”),所以让nginx作为客户端的入口,即负责对外暴露端口)

    然后nginx再将该客户端请求发到某一个zuul组件上面(zuul性能一般,所以就多来几个,通常是一个zuul集群),

    然后zuul再将请求转发到指定的服务模块上面,

    服务之间通过Feign进行相互的调用,

    请求在处理的过程中可能会出现问题,出现问题怎么办呢,用Hystrix来做服务降级处理(即,直接返回一个错误信息给zuul的errorfilter错误过滤器),

    服务最后处理完请求之后,返回响应结果给zuul的路由过滤器,然后路由过滤器将响应结果传递给postfilters后置过滤器;然后由zuul的postfilters后置过滤器将处理结果再响应给用户。

---------------------------------------
SpringCloud家族的一些组件的分析:

    PS:再来看众多的服务模块,所有的服务模块都需要把它们自己的信息注册到Eureka上面,

1.动态更新配置 系列组件:config
          SpringCloud Bus组件负责帮config组件,实现动态更新配置;
          config组件将配置文件同步到本地的git仓库里面;
          最终实现将config组件里面的配置文件拉取到需要指定配置的服务里边。

2.消息总线RabbitMQ:用来做服务之间的通讯;

3.服务的监控与追踪:zipkin+Sleuth,
        sleuth负责监控所有的服务之间调用的情况,它可以追踪一个请求的处理行踪,先到哪了又到哪了...,并且每一个服务执行的时间是多久,是哪个服务的卡顿导致了请求执行了这么长时间。
          zipkin是Sleuth的一个可视化工具。
        Sleuth将追踪的信息存储到了日志里面,但日志不方便查看,所以用zipkin可视化工具来配合Sleuth做服务的追踪与监控。


4.Ribbon:微服务客户端的负载均衡器,帮助客户端去决定选择哪个服务实例,提供负载均衡算法,帮助实现负载均衡。


    PS: 集群,由图中也可以看出,“带分层的”组件的意思是,这些组件都是需要搭建集群的,一台服务器是显然不够用的。