Springcloud知识梳理

1. 核心知识

网关、服务发现注册、配置中心、链路追踪、负载均衡、熔断
1. 网关:路由转发+过滤器
比如:
/api/v1/product/ 商品服务
/api/v1/order/ 订单服务
/api/v1/user/ 用户服务
根据不同的接口地址,分发到对应的服务
2. 注册服务与发现:调用和被调用方的信息维护
3. 配置中心:管理配置,动态更新 application.properties 4. 链路追踪:分析调用链路耗时
比如:下单->查询商品服务获取商品价格->查询用户信息->保存数据库
5. 负载均衡:分发负载
6. 熔断:保护自己和被调用方

2. CAP定理

指的是在一个分布式系统中,Consistency(一致性)、Availability(可用性)、Partitiontolerance(分区容错性)三者不可同时兼得
CAP理论就是说在分布式存储系统中,最多只能实现其中的两点,而由于当前网络硬件肯定会出现延迟丢包等问题,所以分区容错性是必须实现的,因此只能在一致性和可用性之间进行平衡。

  1. 一致性(C):在分布式系统中的所有数据备份,在同一时刻 是否是同样的值。即所有的节点在同一时间的数据完全一致,越多节点,数据同步越耗时
  2. 可用性(A):负载过大后,集群整体是否还能响应客户端的读写请求。即,服务一直可用,而且是正常的响应时间。
  3. 分区容错性(P):分区容错性,就是搞可用性,一个节点崩了,并不影响其它节点。比如100个节点,挂了几个,不影响服务,越多机器越好。
  4. CA满足情况下P不能满足的原因:数据提同步需要时间,也要正常的时间内响应,那么机器数量就要少,所以P不能满足。比如数据同步复制需要100ms,响应时间为2秒,则机器数量就不能太多
  5. CP满足的情况下,A不满足的原因:数据同步需要时间,机器数量也多,但是同步数据需要时间,所以不能在正常的时间内响应,所以A不满足。比如,1000台机器,每台机器的同步复制时间为100ms,那么久不能在1s的时间内进行响应。
  6. AP满足的情况下,C不满足的原因:机器数量多,正常的时间内响应,那么数据就不能及时同步到其它节点,所以C不满足。比如:1000台机器,响应时间为1s,同步一个节点时间为100ms,那么,如果需要在1s内响应,则数据无法及时同步到其他节点。

3. 注册中心

注册中心就是服务管理,核心是有个服务注册表,通过心跳机制动态维护
服务提供者provider:启动的时候向注册中心上报自己的网络信息
服务消费者consumer:启动的时候向注册中心上报自己的网络信息,同时拉取provider的相关网络信息。
使用注册中心是因为微服务应用和机器越来越多,调用方需要知道接口的网络地址,如果单靠配置文件的方式去控制网络地址,对于动态新增机器和维护带来很大的问题

4. 注册中心的选择

Zookeeper: CP设计,保证了一致性,集群搭建的时候,某个节点失败,则会进行选举行的leader,或者半数以上节点不可用,则无法提供服务,因此可用性没法满足
Eureka: AP原则,无主从节点,一个节点挂了,自动切换到其它可用节点就可以使用,去中心化
所以,如果要保持一致性,则选择zookeeper,如金融行业,如果要去可用性,则Eureka,如电商系统

5. Eureka

Eureka2.0开始闭源

1.引入依赖:

<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

2.启动类加入注解:@EnableEurekaServer`
3.配置文件加入如下配置,声明自己是服务端

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    #声明自己是个服务器
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: htpp://${eureka.instance.hostname}:${server.port}/eureka/

4.服务方引入如下依赖

 <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

并在服务方的配置文件中加入如下配置:

#注册到服务中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
#声明自己的服务名
spring:
  application:
    name: product-service

6. 服务消费者ribbon和feign

  1. Ribbon

1.在服务方加入依赖:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

2.在启动类或配置类中加入如下代码:

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

3.在服务层调用服务

    @Autowired
    private RestTemplate restTemplate

使用restTemplate.getForObject()等方法进行服务接口调用,例如:

    restTemplate.getForObject("http://product-service/api/v1/product/find?id=" + productId, Map.class)

4.启动类新增的bean中,@LoadBalanced 的原理

1.首先从注册中心获取provider的列表
2.通过一定的策略选择其中一个节点
3.再返回给restTemplate调用

5.Ribbon默认使用轮循的负载均衡策略,如果要修改策略则需要加入如下配置:

#自定义负载均衡策略
        product-service:
          ribbon:
            NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

其它策略可以查看com.netflix.loadbalancer.IRule的子类,

策略选择
1、如果每个机器配置一样,则建议不修改策略 (推荐)
2、如果部分机器配置强,则可以改为 WeightedResponseTimeRule

  1. fegin
  1. 加入依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
  2. 启动类增加@EnableFeignClients

  3. 增加一个接口 并加入注解@FeignClient(name="服务名"),例如:
    @FeignClient(name="product-service")

  4. 直接注入该接口,用相关服务接口

7. 服务降级熔断

指系统负载过高,突发流量或者网络等各种异常情况,常用的解决方案
1. 熔断:
类似保险丝,熔断服务是为了防止整个系统崩溃,保护自己服务和下游服务,比如:
下单服务->商品服务->用户服务(出现异常->熔断)
2. 降级:
抛弃一些非核心的数据和接口,比如:
行李箱,只带核心的物品,抛弃非核心的,等有条件的时候再去携带这些物品
3. 熔断和降级相互交集
相同点:
1) 从可用性和可靠性出发,为了防止系统崩溃
2) 最终让用户体验到的是服务暂时不可用
不同点:熔断服务一般是下游服务故障导致的,而服务降级一般是从整体系统负荷考虑,由调用方控制

8. Hystrix断路器

1.加入hystrix依赖

 <!--hystrix断路器-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>

2.启动类加入 @EnableCircuitBreaker注解
3.在api方法上加入注解`@HystrixCommand,降级的方法一定要和api的一致,例如:

 @RequestMapping("save")
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public JsonResult save(@RequestParam("user_id") Long userId,@RequestParam("product_id") Long productId){
        ProductOrder order = productOrderService.save(userId, productId);
        return JsonResult.success(order);
    }
    private JsonResult saveOrderFail(Long userId,Long productId){
        return JsonResult.fail(-1,null,"当前访问人数过多,请稍后尝试");
    }

4.fegin结合Hystrix,需要在@FeignClient注解的方法中,加入fallback属性,fallback调用的类,需要实现fegin所在类的接口,并标记为@Component,例如:

@FeignClient(name = "product-service",fallback = ProductClientFailBack.class)
public interface ProductClient {}

@Component
public class ProductClientFailBack implements ProductClient {
    @Override
    public String fingById(Long id) {
        System.out.println("fegin 调用product-service fingById 异常");
        return null;
    }
}


由于2.0.3的fegin默认关闭了hystrix,所以需要在配置中开启:

feign:
  #2.0.3的fegin默认是关闭hystrix
  hystrix:
    enabled: true

9. zuul网关

1.引入zuul依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>

2.启动类加入注解@EnableZuulProxy
3.配置需要加入网关过滤的服务,服务的代替地址不能一样,否则后者会覆盖前者,产生前者服务接口404,由于routes将部分请求头过滤掉了,如果需要往下游服务传递请求头,需要加入sensitive-headers:配置:

#名称如果一样会覆盖前者
zuul:
  routes:
    order-service: /apigateway/order/**
    product-service: /apigateway/product/**
  #处理请求头为空的问题
  sensitive-headers:
 #统一入口为上面的配置,其他入口忽略
 #ignored-patterns: /*-service/**
 #忽略整个服务,对外提供接口
 #ignored-services: product-service