狂神说 SpringCloud 笔记

2022-08-01,,

狂神说 SpringCloud 笔记

视频:https://www.bilibili.com/video/BV1jJ411S7xr?from=search&seid=521497782171184907

课程随堂代码:https://gitee.com/daniel1996/kuangspringcloud

常见面试题:

  1. 什么是微服务?

  2. 微服务之间是如何独立通讯的?

  3. SpringCloud和Dubbo有哪些区别?

  4. SpringBoot和SpringCloud,请你谈谈对他们的理解

    SpringCloud:

    SpringCloud, 基于SpringBoot提供了一套微服务解决方案,包括**服务注册于发现配置中心全链路监控,服务网关负载均衡熔断器**等组件,除了基于NetFlix的开源组件做高度抽象封装之外,还有一些选型中立的开源组件。

    SpringBoot:

    SpringBoot并没有重复早轮子,他只是将目前各家公司开发的比较成熟,经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装,屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂易部署易维护分布式系统开发工具包

  5. 什么是服务熔断?什么是服务降级

  6. 微服务的优缺点分别是什么?说下你在项目开发中遇到的坑

    优点:

    1. 单一职责原则
    2. 每个服务足够内聚,足够小,代码容易理解,这样能聚焦一个指定的业务功能或业务需求;
    3. 开发简单,开发效率提高,一个服务可能就是专一的只干一件事;
    4. 微服务能够被小团队单独开发,这个小团队是2-5人的开发人员组成;
    5. 微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的。
    6. 微服务能使用不同的语言开发。
    7. 易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如jenkins, Hudson,bamboo
    8. 微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值。
    9. 微服务允许你利用融合最新技术。
    10. 微服务只是业务逻辑的代码,不会和HTML,CSS 或其他界面混合
    11. 每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一数据库
  7. 你所知道得微服务技术栈有哪些?请举例一二

  8. eureka和zookeeper都可以提供服务注册与发现的功能,请说说两个区别?

一、微服务架构4个核心问题

  1. 服务很多,客户端该怎么访问?
  2. 这么多服务?服务之间如何通信?
  3. 这么多服务? 如何治理?
  4. 服务挂了怎么办?

三种主流解决方案:

  • Spring cloud NetFlix

  • Apache Dubbo Zookeeper

  • Spring cloud Alibaba

二、Dubbo和SpringCloud技术选型

1. 分布式+服务治理Dubbo

目前成熟的互联网架构:应用服务化拆分 +消息中间件

2. Dubbo与SpringCloud对比

最大区别: SpringCloud抛弃 了Dubbo的RPC通信,采用的是基于HTTP的REST方式。
严格来说,这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约, 不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更加合适。

品牌机与组装机的区别
很明显,Spring Cloud的功能比DUBBO更加强大,涵盖面更广,而且作为Spring的拳头项目,它也能够与SpringFramework、Spring Boot、Spring Data、Spring Batch等其他Spring项目完美融合,这些对于微服务而言是至关重要的。使用Dubbo构建的微服务架构就像组装电脑,各环节我们的选择自由度很高,但是最终结果很有可能因为一条内存质量不行就点不亮了,总是让人不怎么放心,但是如果你是一名高手, 那这些都不是问题;而SpringCloud就像品牌机,在Spring Source的整合下,做了大量的兼容性测试,保证了机器拥有更高的稳定性,但是如果要在使用非原装组件外的东西,就需要对其基础有足够的了解。

社区支持与更新力度
最为重要的是,DUBBO停止了5年左右的更新,虽然2017.7重启了。对于技术发展的新需求,需要由开发者自行拓展升级(比如当当网弄出了DubboX),这对于很多想要采用微服务架构的中小软件组织,显然是不太合适的,中小公司没有这么强大的技术能力去修改Dubbo源码+周边的一整套解决方案,并不是每-一个公司都有阿里的大牛+真实的线上生产环境测试过。

总结:
曾风靡国内的开源RPC服务框架Dubbo在重启维护后,令许多用户为之雀跃,但同时,也迎来了- -些质疑的声音。互联网技术发展迅速, Dubbo是否还能跟上时代? Dubbo与Spring Cloud相比又有何优势和差异?是否会有相关举措保证Dubbo的后续更新频率?

3. SpringCloud使用步骤

  1. 导入依赖
  2. 编写配置文件
  3. 开启这个功能 @Enablexxx
  4. 编写配置类(配置bean)

三、Eureka服务注册与发现

1. 简介

基于CS架构 遵循AP原则
Eureka是Ntflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Zookeeper。

2. Eureka 自我保护机制

某时刻某一个微服务不可以用了,eruka不会立即清理,依旧会对该微服务信息进行保存!
​ 在SpringCloud中,可以使用‘eureka. server.enable-self-preservation = false’ 禁用自我保护模式[不推荐关闭自我保护机制]

3. Eureka配置

3.1 springcloud-api

  1. 实体类 ,其他模块需要引用该模块

    @Data
    @NoArgsConstructor
    @Accessors(chain = true)  //链式写法
    public class Dept implements Serializable {
    
        private Long deptno;
        private String dename;
        //这个数据存在哪个数据库的字段,微服务,一个服务对应一个数据库,同一个信息可能存在不同的数据库
        private String db_source;
    
        public Dept(String dename) {
            this.dename = dename;
        }
    }
    
  2. 导包

    <!--当前的Module自己需要的依赖,如果父类依赖中已经配置了版本。这里就不用写了-->
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
    

3.2 eureka-7001注册中心1

  1. 导入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
    
  2. 配置文件

    server:
      port: 7001
    
    #Eureka
    eureka:
      instance:
        hostname: eureka7001.com # Eureka服务端的实例名称
      client:
        register-with-eureka: false # 表示是否向eureka注册中心注册自己
        fetch-registry: false # fetch-registry如果为false,则表示自己为注册中心
        service-url: # 监控页面
          # 单机模式:http://${eureka.instance.hostname}:${server.port}/eureka/
          defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
    
  3. 主启动类开启注册功能

    @SpringBootApplication
    @EnableEurekaServer //EnableEurekaServer 服务端的启动类,可以接受别人注册进来
    public class EurekaServer_7001 {
        public static void main(String[] args) {
            SpringApplication.run(EurekaServer_7001.class,args);
        }
    }
    

3.3 eureka-7002注册中心2

​ eureka集群配置同上

3.4 springcloud-provider

服务提供者

  1. 导入依赖

    <dependencies>
        <!--我们需要拿到实体类,所以要配置api moudle-->
        <dependency>
            <groupId>com.kuang</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <!--Eureka-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--完善监控信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
    
  2. 配置Eureka

    server:
      port: 8001
    
    # mybatis配置
    mybatis:
      type-aliases-package: com.kuang.springcloud.pojo
      config-location: classpath:mybatis/mybatis-config.xml
      mapper-locations: classpath:mybatis/mapper/*.xml
    
    # spring配置
    spring:
      application:
        name: springcloud-provider-dept
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db01?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
        username: root
        password: root
    
    # Eureka的配置,服务注册到哪里
    eureka:
      client:
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
      instance:
        instance-id: springcloud-provider-dept8001 # 修改eureka上的默认描述信息
    
    # info配置
    info:
      app.name: kaungshen-springcloud
      company.name: blog.kuangstudy.com
    
  3. 开启功能

    //启动类
    @SpringBootApplication
    @EnableEurekaClient //在服务启动后,自动注册到Eureka中
    @EnableDiscoveryClient //服务发现
    public class DeptProvider_8001 {
        public static void main(String[] args) {
            SpringApplication.run(DeptProvider_8001.class,args);
        }
    }
    
  4. 获取服务信息 多人开发使用(做了解,但是该功能需要在启动类加@EnableDiscoveryClient)

    //注册进来的微服务,获取一些消息
    @GetMapping("/dept/discovery")
    public Object discovery() {
        //获得微服务列表的清单
        List<String> services = client.getServices();
        System.out.println("discovery=>services:" + services);
        //得到一个具体的微服务信息
        List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
        for (ServiceInstance instance : instances) {
            System.out.println(
                    instance.getHost() + "\t" +
                    instance.getPort() + "\t" +
                    instance.getUri() + "\t" +
                    instance.getServiceId() + "\t"
            );
        }
        return this.client;
    }
    
  5. 服务提供者项目结构图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EiLX34Nk-1595645219262)(D:\我\MyBlog\狂神说 SpringCloud 笔记.assets\image-20200722124932675.png)]

3.5 springcloud-consumer

服务消费者

  1. 导入依赖

    <!--实体类+web-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.kuang</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
    
  2. 配置端口

    server:
      port: 80
    
  3. 配置RestTemplate(因为Eureka基于Rest开发)

    @Configuration
    public class ConfigBean {
        // @Configuration --- spring applicationContext.xml
    
        @Bean
        public RestTemplate getRestTemplate(){
            return new RestTemplate();
        }
    }
    
  4. 消费者调用方式

    @RestController
    public class DeptController {
    
        //消费者,不应该有service层
        //RestTemplate ... 供我们直接调用就可以了 注册到Spring中
    
        @Autowired
        //提供多种便捷访问远程http服务的方法,简单的restful服务模板
        private RestTemplate restTemplate;
    
        private static final String REST_URL_PREFIX = "http://localhost:8001";
    
        @RequestMapping("/consumer/dept/add")
        public boolean add(Dept dept){
            return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept,Boolean.class);
        }
    
        @RequestMapping("/consumer/dept/get/{id}")
        public Dept get(@PathVariable("id") Long id){
            return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
        }
    
        @RequestMapping("/consumer/dept/list")
        public List<Dept> list(){
            return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
        }
    
    }
    
  5. 消费者结构图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A0OVYfP6-1595645219263)(D:\我\MyBlog\狂神说 SpringCloud 笔记.assets\image-20200722125335258.png)]

4. 对比Zookeeper

回顾CAP原则

RDBMS关系型数据库 (Mysq|、Oracle、sqlServer)----> ACID

NoSQL 非关系型数据库(redis、mongdb) —> CAP

4.1 ACID是什么?

  1. A (Atomicity) 原子性
  2. C (Consistency)一致性
  3. I (Isolation) 隔离性
  4. D (Durability) 持久性

4.2 CAP是什么?

  1. C (Consistency) 强一致性
  2. A (Availability) 可用性
  3. P (Partition tolerance) 分区容错性

CAP原则又称CAP定理,指的是在一个分布式系统中,一致性 (Consistency)、可用性(Availability) 、分区容错性(Partition tolerance)。CAP原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。
CAP的三进二: CA、AP、CP

4.3 CAP理论的核心

  1. 一个分布式系统不可能同时很好的满足一致性可用性分区容错性这三个需求
  2. 根据CAP原理,将NoSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类:
    • CA:单点集群,满足一致性,可用性的系统,通常可扩展性较差
    • CP:满足一致性,分区容错性的系统,通常性能不是特别高
    • AP:满足可用性,分区容错性的系统,通常可能对一致性要求低一些

作为服务注册中心,Eureka比Zookeeper好在哪里?

​ 著名的CAP理论指出,一个分布式系统不可能同时满足C (一致性)、A (可用性)、P (容错性)。由于分区容错性P在分布式系统中是必须要保证的,因此我们只能在A和C之间进行权衡。

**Zookeeper保证的是CP; **

Eureka保证的是AP;

4.4 Zookeeper保证的是CP

​ 当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。**但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30~120s,且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。**在云部署的环境下,因为网络问题使得zk集群失去master’节点是较大概率会发生的事件,虽然服务最终能够恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。

4.5 Eureka保证的是AP

​ Eureka看明白了这一点, 因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时,如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在, 就能保住注册服务的可用性,只不过查到的信息可能不是最新的,除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:

  1. Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
  2. Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点依然可用)
  3. 当网络稳定时,当前实例新的注册信息会被同步到其他节点中

因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像Zookeeper那样使整个注册服务瘫痪

四、负载均衡及Ribbon

1. Ribbon是什么

  • Spring Cloud Ribbon是基于Netflix Ribbon实现的一套**客户端负载均衡工具**。
  • 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将NetFlix的中间层服务连接在一起。Ribbon的客户端组件提供一系列完整的配置项如: 连接超时重试等等。简单的说,就是在配置文件中列出LoadBalancer (简称LB:负载均衡)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等等可以自定义)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法!

2. Ribbon的作用

  • LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。
  • 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高可用)。
  • 常见的负载均衡软件有Nginx(安装之后写配置), Lvs(国内大神写)等
  • dubbo、SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义
  • 负载均衡简单分类:
    • 集中式LB
      ■ 即在服务的消费方和提供方之间使用独立的LB设施,如Nginx: 反向代理服务器!由该设施负责把访问请求通过某种策略转发至服务的提供方! (由服务端进行调度)
    • 进程式LB
      ■ 将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。(由客户端进行调度)
      Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!

3. Ribbon配置

Ribbon是在客户端实现的,所以在消费者这端进行配置

springcloud-consumer-dept-80:

  1. 服务消费方添加Ribbon和Erueka的依赖

    <!--Ribbon-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--erueka-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    
  2. 配置Eureka

    # Eureka配置
    eureka:
      client:
        register-with-eureka: false # 不向Eureka注册自己
        service-url:
          defaultZone: http://eureka7003.com:7003/eureka/,http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
    
  3. 消费者ConfigBean(在RestTemplate上面加注释@LoadBalanced)

    @Configuration
    // @Configuration --- spring applicationContext.xml
    public class ConfigBean {
    
        //配置负载均衡实现RestTemplate
        @Bean
        @LoadBalanced //Ribbon
        public RestTemplate getRestTemplate(){
            return new RestTemplate();
        }
    }
    
  4. 配置消费者启动类

    //Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号
    @SpringBootApplication
    @EnableEurekaClient
    public class DeptConsumer_80 {
        public static void main(String[] args) {
            SpringApplication.run(DeptConsumer_80.class,args);
        }
    }
    
  5. 修改Controller访问地址

    //Ribbon,这里的地址应该是一个变量,通过服务名来访问
    //private static final String REST_URL_PREFIX = "http://localhost:8001";
    private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
    
    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept,Boolean.class);
    }
    
  6. 测试

    Ribbon和Eureka整合之后,客户端可以直接调用,不用关心IP地址

    通过创建三个不同端口号的提供者来测试,三个提供者拥有三个数据库,唯一的区别就是datasource不一样,经过测试,Ribbon负载均衡,每次访问就会读取不同提供者的数据库。

3.1自定义Ribbon 负载均衡算法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J5OLXZ9i-1595645219264)(D:\我\MyBlog\狂神说 SpringCloud 笔记.assets\image-20200722183954246.png)]

通过在启动列添加@RibbonClient指向自定义的类将Ribbon自带的算法取代

//Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号
@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候就能去加载我们自定义的Ribbon类
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = KuangRule.class)
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }
}

注意:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sggaQQPt-1595645219265)(D:\我\MyBlog\狂神说 SpringCloud 笔记.assets\image-20200722190536893.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IjtKnKrT-1595645219266)(D:\我\MyBlog\狂神说 SpringCloud 笔记.assets\image-20200722190736303.png)]

五、Feign负载均衡

1. 简介

​ feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。SpringCloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。(只需要创建一个接口,然后添加注解即可)

Feign,大家都习惯面向接口编程。这个是很多开发人员的规范。调用微服务访问两种方法

  1. 微服务名字【ribbon】
  2. 接口和注解【feign】

2. Feign能干什么

  • Feign旨在使编写Java Http客户端变得更容易
  • 前面在使用Ribbon + RestTemplate时,利用RestTemplate对Http请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义,在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它(类似于以前Dao接口上标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可。) 即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户端的开发量。

3. Feign集成了Ribbon

​ 利用Ribbon维护了服务列表信息,并且通过轮询实现了客户端的负载均衡,而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而且简单的实现了服务调用。
Feign也可结合Hystirx

4. Feign配置

  1. 定义服务绑定接口

    springcloud-api service:

    /*
        和 @Reference 是一样的
        value 是微服务的名字
    */
    @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
    @Component
    public interface DeptClientService {
    
        @GetMapping("/dept/get/{id}")
        public Dept queryById(@PathVariable("id") Long id);
    
        @GetMapping("/dept/list")
        public List<Dept> queryAll();
    
        @GetMapping("/dept/add")
        public boolean addDept(Dept dept);
    }
    
  2. 消费者Controller修改原有Ribbon调用方式 注入之后直接使用Java面向接口调用

    @RestController
    public class DeptController {
    
        @Autowired
        private DeptClientService service = null;
    
        @RequestMapping("/consumer/dept/add")
        public boolean add(Dept dept){
            return this.service.addDept(dept);
        }
    
        @RequestMapping("/consumer/dept/get/{id}")
        public Dept get(@PathVariable("id") Long id){
            return this.service.queryById(id);
        }
    
        @RequestMapping("/consumer/dept/list")
        public List<Dept> list(){
            return this.service.queryAll();
        }
    
    }
    
  3. 消费者主启动类配置FeignClient的扫描注解包

    //Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号
    @SpringBootApplication
    @EnableEurekaClient
    @EnableFeignClients(basePackages = {"com.kuang.springcloud"})
    public class DeptConsumer_80 {
        public static void main(String[] args) {
            SpringApplication.run(DeptConsumer_80.class,args);
        }
    }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zQXBmmcK-1595645219267)(D:\我\MyBlog\狂神说 SpringCloud 笔记.assets\image-20200722224755385.png)]

六、服务熔断

1. 分布式系统面临的问题

​ 复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的失败!

2. 服务雪崩

​ 多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的“扇出”、如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒中内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障,这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。我们需要:弃车保帅.

3. Hystrix

​ Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。

4. 断路器

​ “断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个服务预期的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩.

功能:

  • 服务降级 (服务消费端)
  • 服务熔断 (服务提供端)
  • 服务限流
  • 接近实时的监控

5.服务熔断

熔断机制是对应雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。

6. 服务熔断配置(在提供者里配置)

  1. 导入hystrix依赖

    <!--Hystrix-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    
  2. 修改消费者controller调用方式 使用@HystrixCommand注解指向出错时要调用的方法(缺点就是每个controller方法都会需要有一个备选方案)

    @RestController
    public class DeptController {
    
        @Autowired
        private DeptService deptService;
    
        @GetMapping("/dept/get/{id}")
        @HystrixCommand(fallbackMethod = "hystrixGet")
        public Dept queryById(@PathVariable("id") Long id){
            Dept dept = deptService.queryById(id);
            if(dept == null){
                throw new RuntimeException("id => " + id + ",不存在该用户,或者无法找到");
            }
            return dept;
        }
        
        //备选方法
        public Dept hystrixGet(@PathVariable("id") Long id){
            return new Dept().setDeptno(id)
                    .setDename("id => " + id + "没有对应的信息,null--@Hystrix")
                    .setDb_source("no this database in mysql");
    
        }
        
    }
    
  3. 添加对熔断的支持

    @SpringBootApplication
    @EnableEurekaClient //在服务启动后,自动注册到Eureka中
    @EnableDiscoveryClient //服务发现
    @EnableCircuitBreaker //添加对熔断的支持
    public class DeptProviderHystrix_8001 {
        public static void main(String[] args) {
            SpringApplication.run(DeptProviderHystrix_8001.class,args);
        }
    }
    

七、服务降级

服务消费端实现,用于对关闭某些服务器来实现特殊需要功能时采用 这样访问原来服务器就不会出现404报错。

1. 什么是服务降级

当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。(弃车保帅)
如果还是不理解,那么可以举个例子:假如目前有很多人想要给我付钱,但我的服务器除了正在运行支付的服务之外,还有一些其它的服务在运行,比如搜索、定时任务和详情等等。然而这些不重要的服务就占用了JVM的不少内存与CPU资源,为了能把钱都收下来(钱才是目标),我设计了一个动态开关,把这些不重要的服务直接在最外层拒掉,这样处理后的后端处理收钱的服务就有更多的资源来收钱了(收钱速度更快了),这就是一个简单的服务降级的使用场景。

2. 服务降级配置

  1. 在api模块中创建降级类,并实现FallbackFactory接口重写create方法(修改返回值类型<原来是object>直接对类处理)

    //降级
    @Component
    public class DeptClientServiceFallbackFactory implements FallbackFactory {
    
        public DeptClientService create(Throwable throwable) {
            return new DeptClientService() {
                public Dept queryById(Long id) {
                    return new Dept()
                            .setDeptno(id)
                            .setDename("id => " + id + "没有对应的信息,客户提供了降级的信息,这个服务现在已经被关闭")
                            .setDb_source("没有数据");
                }
    
                public List<Dept> queryAll() {
                    return null;
                }
    
                public boolean addDept(Dept dept) {
                    return false;
                }
            };
        }
    }
    
  2. 在api模块被处理的Feign接口中添加fallbackFactory属性(Feign整合了Hystrix)

    @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallbackFactory.class)
    @Component
    public interface DeptClientService {
    
        @GetMapping("/dept/get/{id}")
        public Dept queryById(@PathVariable Long id);
    
        @GetMapping("/dept/list")
        public List<Dept> queryAll();
    
        @GetMapping("/dept/add")
        public boolean addDept(Dept dept);
    }
    
  3. 在服务提供端开启服务降级

    # 开启降级 feign.histrix
    feign:
      hystrix:
        enabled: true
    

八、Hystrix:Dashboard流监控

用来监控实例的健康程度,因为在客户端监控 所以配在消费者端口

1. 配置Dashboard

  1. 新建consumer-hystrix-dashboard模块,导入dashboard依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    
  2. 消费者端application.yml配一个端口

    server:
      port: 9001
    
  3. 消费者启动类需要加@EnableHystirxDashboard开启Hystrix-Dashboard

    @SpringBootApplication
    @EnableHystrixDashboard //开启监控
    public class DeptConsumerDashboard_9001 {
        public static void main(String[] args) {
            SpringApplication.run(DeptConsumerDashboard_9001.class,args);
        }
    }
    
  4. 在服务提供者启动类上加上监控Servlet请求

    @SpringBootApplication
    @EnableEurekaClient //在服务启动后,自动注册到Eureka中
    @EnableDiscoveryClient //服务发现
    @EnableCircuitBreaker //添加对熔断的支持
    public class DeptProviderHystrix_8001 {
        public static void main(String[] args) {
            SpringApplication.run(DeptProviderHystrix_8001.class,args);
        }
    
        //增加一个 Servlet
        @Bean
        public ServletRegistrationBean hystrixMetricsStreamServlet(){
            ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
            registrationBean.addUrlMappings("/actuator/hystrix.stream");
            return registrationBean;
        }
    }
    
  5. Hystirx-dashboard效果图

九、Zuul路由网关

1. 介绍

​ Zuul包含了对请求的路由过滤两个最主要的功能:
其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而**过滤器功能则负责对请求的处理过程进行干预,**是实现请求校验,服务聚合等功能的基础。Zuul和Eureka进行整合, 将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。

注意: Zuu|服务最终还是会注册进Eureka

提供:代理+路由+过滤三大功能!

4. Zuul网关配置

  1. 导入zuul和eureka依赖(zuul需要注册到eureka中)

    <!--zuul-->
    <!--erueka-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zuul</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    
  2. zuul配置

    # 路由网关配置
    zuul:
      routes:
        mydept.serviceId: springcloud-provider-dept
        mydept.path: /mydept/**
      # 不能再使用这个路径访问了,ignore : 忽略 | “*” 隐藏全部的微服务真实路径
      ignored-services: "*"
      prefix: /kuang # 公共设置的前缀
    
  3. 开启zuul

    @SpringBootApplication
    @EnableZuulProxy //开启Zuule
    public class ZuulApplication_9527 {
        public static void main(String[] args) {
            SpringApplication.run(ZuulApplication_9527.class,args);
        }
    }
    

十、SpringCloud config 分布式配置

1. 分布式系统面临的配置文件的问题

​ 微服务意味着要将单体应用中的业务拆分成一个个子服务, 每个服务的粒度相对较小,因此系统中会出现大量的服务,由于每个服务都需要必要的配置信息才能运行,所以一套集中式的, 动态的配置管理设施是必不可少的。
SpringCloud提供了ConfigServer来解决这个问题,我们每一个微服务自己带着一个application.yml,那上百的的配置文件要修改起来,岂不是要发疯!

​ Spring Cloud Config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置。
Spring Cloud Config 分为服务端客户端两部分;
服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密,解密信息等访问接口。
客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理。并且可以通过git客户端工具来方便的管理和访问配置内容。

2. SpringCloud config分布式配置中心能做什么

  • 集中管理配置文件
  • 不同环境,不同配置,动态化的配置更新,分环境部署,比如/dev /test/ /prod /beta /release
  • 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息。
  • 当配置发生变动时,服务不需要重启,即可感知到配置的变化,并应用新的配置
  • 将配置信息以REST接口的形式暴露
    SpringCloud config分布式配置中心与github整合
    由于Spring Cloud Config默认使用Git来存储配置文件(也有其他方式,比如支持SVN和本地文件), 但是最推荐的还是Git,而且使用的是http / https访问的形式;

3. Config-Server服务端配置

  1. 导入config-server依赖

    <!--config-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
        <version>2.0.5.RELEASE</version>
    </dependency>
    
  2. application.yml配置 配置远程项目地址

    server:
      port: 3344
    
    spring:
      application:
        name: springcloud-config-server
      cloud: # 连接远程仓库
        config:
          server:
            git:
              uri: https://gitee.com/daniel1996/springcloud-config.git
    
  3. git上的spring配置信息

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dnojtzeD-1595645219270)(D:\我\MyBlog\狂神说 SpringCloud 笔记.assets\image-20200725101824473.png)]

  4. 启动类开启ConfigServer(加入注解@EnableConfigServer)

    @SpringBootApplication
    @EnableConfigServer
    public class Cofig_Server_3344 {
        public static void main(String[] args) {
            SpringApplication.run(Cofig_Server_3344.class,args);
        }
    }
    
  5. 效果图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VBUhWfdQ-1595645219271)(D:\我\MyBlog\狂神说 SpringCloud 笔记.assets\image-20200725102143102.png)]

4. Config-Server客户端配置

  1. 导入客户端依赖

    <!--config-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
        <version>2.0.5.RELEASE</version>
    </dependency>
    
  2. 配置bootstrap.yml(系统级别的配置,和application.yml不同 这个配置的就是从哪个地方获取配置信息)

# 系统级别的配置
spring:
  cloud:
    config:
      uri: http://localhost:3344
      label: master
      name: config-client # 需要从git上读取的资源名称,不要后缀
      profile: dev
  1. 测试controller直接通过@value获取服务端的配置信息

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xMJCug9b-1595645219272)(D:\我\MyBlog\狂神说 SpringCloud 笔记.assets\image-20200725102525415.png)]

  2. 运行效果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nJvCsDsJ-1595645219273)(D:\我\MyBlog\狂神说 SpringCloud 笔记.assets\image-20200725102817870.png)]

5. ConfigServer实战概述

整合Eureka和dept-provider配置

  1. 在远程配置项目上写eureka配置信息

  2. 创建一个eureka项目,导入config-server jar包,写一个bootstrap.yml 里面写配置要从哪个地方获取

  3. 启动项目

  4. 和上1,2,3步骤一样再配置provider的配置信息

  5. 两个都启动后则可从云端获取配置信息


Config服务端

  1. 导入config-server配置

    <!--config-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
        <version>2.0.5.RELEASE</version>
    </dependency>
    
  2. 服务端application.yml配置

    server:
      port: 3344
    
    spring:
      application:
        name: springcloud-config-server
      cloud: # 连接远程仓库
        config:
          server:
            git:
              uri: https://gitee.com/daniel1996/springcloud-config.git
    
  3. 主启动类开启ConfigServer服务

    @SpringBootApplication
    @EnableConfigServer
    public class Cofig_Server_3344 {
        public static void main(String[] args) {
            SpringApplication.run(Cofig_Server_3344.class,args);
        }
    }
    

重构Eureka(springcloud-config-eureka-7001配置)

  1. 导如config-client依赖

    <!--config-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
        <version>2.0.5.RELEASE</version>
    </dependency>
    
  2. 配置bootstarp.yml获取config-server上的配置文件连接

    label是远端git分支 profile是环境

    # 系统级别的配置
    spring:
      cloud:
        config:
          uri: http://localhost:3344
          label: master
          name: config-eureka # 需要从git上读取的资源名称,不要后缀
          profile: dev
    
  3. 启动类不需要加config注解

    @SpringBootApplication
    @EnableEurekaServer //EnableEurekaServer 服务端的启动类,可以接受别人注册进来
    public class EurekaServer_7001 {
        public static void main(String[] args) {
            SpringApplication.run(EurekaServer_7001.class,args);
        }
    }
    

重构服务提供端类似


十一、总结回顾

m/daniel1996/springcloud-config.git


3. 主启动类开启ConfigServer服务

```java
@SpringBootApplication
@EnableConfigServer
public class Cofig_Server_3344 {
    public static void main(String[] args) {
        SpringApplication.run(Cofig_Server_3344.class,args);
    }
}

重构Eureka(springcloud-config-eureka-7001配置)

  1. 导如config-client依赖

    <!--config-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
        <version>2.0.5.RELEASE</version>
    </dependency>
    
  2. 配置bootstarp.yml获取config-server上的配置文件连接

    label是远端git分支 profile是环境

    # 系统级别的配置
    spring:
      cloud:
        config:
          uri: http://localhost:3344
          label: master
          name: config-eureka # 需要从git上读取的资源名称,不要后缀
          profile: dev
    
  3. 启动类不需要加config注解

    @SpringBootApplication
    @EnableEurekaServer //EnableEurekaServer 服务端的启动类,可以接受别人注册进来
    public class EurekaServer_7001 {
        public static void main(String[] args) {
            SpringApplication.run(EurekaServer_7001.class,args);
        }
    }
    

重构服务提供端类似


十一、总结回顾

本文地址:https://blog.csdn.net/DDDDeng_/article/details/107575351

《狂神说 SpringCloud 笔记.doc》

下载本文的Word格式文档,以方便收藏与打印。