SpringCloud学习笔记

开始

项目地址
SpringCloud中文文档

尝试使用restTamplete调用http请求,实现微服务

  1. 建立父工程:springcloud_study,配置依赖管理

    <dependencyManagement>
        <dependencies>
            <!-- SpringBoot依赖-->
            <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.4.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- SpringCloud依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
  2. 建立两个module,provider和consumer,并都导入父工程的依赖

    <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
  3. 生产者提供接口

    @RestController
    public class ProviderController {
    
        @GetMapping("/hello")
        public String hello() {
            return "hello";
        }
    }
    
  4. 消费者调用接口

    @RestController
    public class ConsumerController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        //生产者的地址
        private static final String URL_PREFIX = "http://localhost:8081/";
    
        @GetMapping("hello")
        public String hello() {
            return restTemplate.getForObject(URL_PREFIX + "hello", String.class);
        }
    
    }
    
  5. 访问消费者提供的接口,可以看到调用成功

eureka

配置eureka

上面的例子就是微服务最简单的实现,一个生产者一个消费者,通过http请求进行通信。

这里我们引入eureka,eureka是一个注册中心,提供服务注册的功能,上面的例子中消费者连接生产者的地址写在代码中,这里我们使用eureka保存这些信息。

  1. 新建eureka_server模块,导入依赖

    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka-server</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    
  2. 编写配置文件application.yml

    server:
      port: 7001
    
    # eureka配置
    eureka:
      instance:
        hostname: localhost #eureka服务端实例名称
      client:
        register-with-eureka: false #是否注册自己
        fetch-registry: false # 表示自己是注册中心
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    
  3. 启动访问

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

    访问localhost:7001即可

注册

  1. 添加依赖

    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    
  2. 修改启动类

    @SpringBootApplication
    @EnableEurekaClient
    @EnableDiscoveryClient
    public class ProviderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ProviderApplication.class, args);
        }
    }
    
  3. 修改配置文件

    server:
      port: 8081
    spring:
      application:
        name: provider
    
    #eureka配置
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:7001/eureka/
      instance:
        instance-id: provider
    
  4. 启动

    可以看到注册成功

    请添加图片描述

  5. 获取服务信息

    @GetMapping("/service")
    public void getInfo(){
        List<String> services = discoveryClient.getServices();
        for (String service : services) {
            System.out.println(service);
        }
        List<ServiceInstance> provider = discoveryClient.getInstances("provider");
        for (ServiceInstance serviceInstance : provider) {
            System.out.println(serviceInstance.getHost());
            System.out.println(serviceInstance.getPort());
    
        }
    }
    

配置eureka集群

通过本地不同端口来配置集群,模仿eureka再不同机器上运行

  1. 新建模块eureka_server1,eureka_server2模块,分别在7002和7003端口启动

  2. 修改host文件,模仿不同的节点。并配置三个eureka_server的application.yml文件。

    127.0.0.1 eureka7001.com
    127.0.0.1 eureka7002.com
    127.0.0.1 eureka7003.com
    
    server:
      port: 7001
    
    # eureka配置
    eureka:
      instance:
        hostname: localhost #eureka服务端实例名称
      client:
        register-with-eureka: false #是否注册自己
        fetch-registry: false # 表示自己是注册中心
        service-url:
          defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #配置其他两个节点的地址
    
  3. 启动三台服务器,查看,发现已经形成集群

    在这里插入图片描述

  4. 将provider注册到集群,完成

    eureka:
      client:
        service-url:
          defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
    

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

CAP理论的一个例子。开学了,你和同桌互对寒假作业答案,对到一半同桌去了厕所,恰好老师进来要收作业,你决定:AP【交就交吧,有错也无所谓了,交作业要紧】;CP【等同桌回来,把答案对完再交,满分要紧】

ribbon

ribbon介绍

ribbon是一个客户端负载均衡工具

使用

  1. 在消费者(客户端)导入依赖,启动类加上注解:@EnableEurekaClient

    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    
  2. 重新配置restTemplate

    @Bean
    @LoadBalanced //ribbon负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    
  3. 修改provider地址,改成eureka中的服务名,启动即可(由于这里只有一个provider,所以无法体现负载均衡的效果)

    //生产者的地址,这里通过eureka中的applicaton name配置,会自己获取服务地址,如果配置了多个provider以及ribbon,会进行provider的负载均衡
    private static final String URL_PREFIX = "http://PROVIDER/";
    

多个provider体现负载均衡

  1. 再建立两个provider,分别为provider1,provider2。启动再8002和8003端口,导入相关依赖。三个provider的application name要相同,只需要修改instance-id即可。三个都像eureka进行注册,启动三个provider。为了体现到底用了哪个provider,三个provider提供相同的接口,返回不同的内容。

    下图可以看见三个provider启动后(需要注册,等一段时间)可以在eureka上看到一个服务有三个实例

    在这里插入图片描述

  2. 测试,访问消费者接口,可以看到ribbon是通过轮询的机制访问provider的。

自定义负载均衡策略

ribbon负载均衡策略
策略类命名描述
RandomRule随即策略随机选择server
RoundRobinRule轮询策略按照顺序选择server(默认策略)
RetryRule重试策略在一个配置时间段内,当选择server不成功,则一直尝试选择一个可用的server
BestAvailableRule最低并发策略逐个考察server,如果server断路器打开,则忽略,再选择其中并发链接最低的server
AvailabilityFilteringRule可用过滤策略过滤掉一直失败并被标记为circuit tripped的server,过滤掉那些高并发链接的server(active connections超过配置的阈值)
ResponseTimeWeightedRule响应时间加权重策略根据server的响应时间分配权重,响应时间越长,权重越低,被选择到的概率也就越低。响应时间越短,权重越高,被选中的概率越高,这个策略很贴切,综合了各种因素,比如:网络,磁盘,io等,都直接影响响应时间
ZoneAvoidanceRule区域权重策略综合判断server所在区域的性能,和server的可用性,轮询选择server并且判断一个AWS Zone的运行性能是否可用,剔除不可用的Zone中的所有server
使用其他策略
  1. 在主启动类外层建立策略(做到策略可配置,在主启动类同级或下级会被扫描,而我们需要的是指定多个策略,想要使用哪个就配置哪个,不进行扫描)

    ========

  2. 在MyRule中配置bean

    @Configuration
    public class MyRules {
        //随机
        @Bean
        public IRule randomRule() {
            return new RandomRule();
        }
    }
    
  3. 修改启动类,加上注解:@RibbonClient(name = “PROVIDER”, configuration = MyRules.class),其中name为生产者的名称,configuration为策略类。启动消费者,发现负载均衡策略已经变成了随机策略。

feign

feign介绍

基于服务器端的负载均衡,集成了ribbon

使用

  1. 新建模块consumer_feign,通过feign的方式来调用服务。

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
    
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
    
    </dependencies>
    
  2. 配置文件

    # eureka配置
    eureka:
      client:
        register-with-eureka: false  #不想eureka中注册自己(因为只是消费者)
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7002.com:7002/eureka/
    
  3. 编写service层

    @Component
    @FeignClient(value = "PROVIDER")//feign客户端,PROVIDER是生产者的服务名
    public interface MyService {
        //服务生产者的接口地址
        @GetMapping("hello")
        String hello();
    }
    
  4. 编写controller

    @RestController
    public class ConsumerController {
    
        @Autowired
        private MyService myService;
    
        @GetMapping("hello")
        public String hello() {
            return myService.hello();
        }
    
    }
    
  5. 启动类

    @EnableEurekaClient
    @SpringBootApplication
    @EnableFeignClients(basePackages = {"consumer"})//要扫描的包路径
    public class ConsumerApplication {
        public static void main(String[] args) {
    
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }
    

Hystrix

服务熔断

服务熔断在服务端做

  1. 服务提供者添加依赖

    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    
  2. controller添加服务

    @HystrixCommand(fallbackMethod = "fallbackMethod")//失败调用的方法名
    @GetMapping("/hystrix/{id}")
    public String testHystrix(@PathVariable("id") Long id) {
        if (id > 10) {
            return String.valueOf(id);
        } else {
            throw new RuntimeException("异常捕获中id超出范围");
        }
    }
    
    
    
    //发生异常调用的方法
    public String fallbackMethod(@PathVariable("id") Long id) {
        return "hystrix中的i超出范围";
    }
    
  3. 主启动类添加注解:@EnableCircuitBreaker

  4. 利用feign创建消费者消费服务

    • service

      @Component
      @FeignClient(value = "PROVIDER")//feign客户端,PROVIDER是生产者的服务名
      public interface MyService {
      
          //服务生产者的接口地址
          @GetMapping("hello")
          String hello();
      
          @GetMapping("/hystrix/{id}")
          String testHystrix(@PathVariable("id") Long id);
      
      }
      
    • controller

      @RestController
      public class ConsumerController {
      
          @Autowired
          private MyService myService;
      
          @GetMapping("hello")
          public String hello() {
              return myService.hello();
          }
      
          @GetMapping("/hystrix/{id}")
          public String testHystrix(@PathVariable("id") Long id) {
              return myService.testHystrix(id);
          }
      
      }
      
  5. 启动生产者和消费者,访问消费者端口,可以看到当id小于10的时候,发生异常,执行了断路器,当id大于10的时候正确执行。

image-20210731152844414

image-20210731152928225

服务降级

服务降级在客户端做

  1. 在客户端添加工厂类MyFallbackFactory

    @Component
    public class MyFallbackFactory implements FallbackFactory<MyService> {
        //MyService时服务的客户端接口
        //重写create方法,返回MyService接口,实现方法,当服务端不可用时,调用对MyService的实现方法
        @Override
        public MyService create(Throwable throwable) {
            return new MyService() {
                @Override
                public String hello() {
                    return "服务降级返回的hello";
                }
    
                @Override
                public String testHystrix(Long id) {
                    return "服务降级返回的id:" + id;
                }
            };
        }
    }
    
  2. MyService添加注解allbackFactory = MyFallbackFactory.class,将刚创建的工厂类给MyService

    @Component
    @FeignClient(value = "PROVIDER", fallbackFactory = MyFallbackFactory.class)//feign客户端,PROVIDER是生产者的服务名
    public interface MyService {
    
        //服务生产者的接口地址
        @GetMapping("hello")
        String hello();
    
        @GetMapping("/hystrix/{id}")
        String testHystrix(@PathVariable("id") Long id);
    
    }
    
  3. 配置服务降级

    # hystrix配置,启用服务降级
    feign:
      hystrix:
        enabled: true
    

启动客户端和服务端,发现当服务端可以正常访问时没有异常;关掉服务端,发现执行了MyService的默认实现

image-20210731160916924

服务监控

  1. 配置服务监控服务器

    • 创建dashboard模块,导入依赖

      <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-hystrix</artifactId>
          <version>1.4.6.RELEASE</version>
      </dependency>
      
      <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
          <version>1.4.6.RELEASE</version>
      </dependency>
      
    • 编写配置文件

      server:
        port: 9000
      
    • 添加启动类

      @SpringBootApplication
      @EnableHystrixDashboard
      public class DashboardApplication {
      
          public static void main(String[] args) {
              SpringApplication.run(DashboardApplication.class, args);
          }
      }
      
    • 启动dashboard,访问地址http://localhost:9000/hystrix,可以看到监控服务器启动成功。

      image-20210731171448621

  2. 修改provider

    1. 需要导入hytrix和actuator依赖

      <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-hystrix</artifactId>
          <version>1.4.6.RELEASE</version>
      </dependency>
      
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      
    2. 在启动类上添加servlet bean

      //固定写法,配置servlet bean
      @Bean
      public ServletRegistrationBean res() {
          ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
          servletRegistrationBean.addUrlMappings("/actuator/hystrix.stream");
          return servletRegistrationBean;
      }
      
    3. 启动provider,并将监控的地址添加到监控服务器,进行监控

      image-20210731171639823

      点击monitor stream开始监控,此时一直会loading…,必须要客户端进行一次消费才会出现监控页面,监控的具体信息在图上的地址可见,dashboard只是将图上的地址可视化了,原信息如下图。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8QXwIGFa-1631063048933)(https://i.loli.net/2021/07/31/nw65XTzedBcbEuK.png)]

    4. 监控页面

      image-20210731172212916

      图中实心原点的大小表示流量的大小,颜色表示健康程度:绿色>黄色>橙色>红色,此外还有以下信息

      image-20210731172421623

zuul

  1. 创建zuul服务:新建springcloud_zuul项目,调入依赖

    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
    </dependency>
    
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
    <version>1.4.6.RELEASE</version>
    </dependency>
    
  2. 编写启动类

    @SpringBootApplication
    @EnableZuulProxy
    public class ZuulApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ZuulApplication.class, args);
        }
    }
    
  3. 配置文件

    server:
      port: 9527
    spring:
      application:
        name: zuul
    
    #eureka配置
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
      instance:
        instance-id: zuul-01
    
    # zuul的配置
    zuul:
      routes:
        myService.serviceId: provider
        myService.path: /zuulPath/**
      ignored-services: "*" # 所有的服务都不能使用原来的路径访问
      prefix: /prefix # 路径的前缀
    
  4. 启动zuul,可以看出zuul已经向eureka注册了

    image-20210731185959698

  5. 通过zuul访问接口,可以看出可以正常访问,并且使用原接口不能访问

    image-20210731190031178

    image-20210731190159422

Spring Cloud Config

前期工作

通过统一的配置来管理微服务应用,server读取远程的配置,client读取server

image-20210801172656877

  1. 创建公开的远程git仓库,我这里用的是gitee。创建仓库springcloud_config。

    image-20210801171114880

  2. 添加application.yml文件,编写多配置环境

    spring:
      profiles:
        active: dev
    ---
    spring:
      profiles: dev
      application:
        name: dev_config
    ---
    spring:
      profiles: test
      application:
        name: test_config
    

服务端

  1. 创建模块springcloud_config_server,导入依赖。

    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-config-server -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>
    
  2. 配置文件

    server:
      port: 3000
    spring:
      application:
        name: config_server
      cloud:
        config:
          server:
            git:
              uri: https://gitee.com/wms16477/springcloud_config.git
    
  3. 启动类

    @SpringBootApplication
    @EnableConfigServer
    public class ConfigApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConfigApplication.class, args);
        }
    }
    
  4. 访问地址,可以看到成功访问了不同环境的配置文件

    image-20210801171847122

image-20210801171859134

客户端

这里的客户端就是一个个的服务,读取服务端的配置,配置文件统一由服务端管理。

  1. 添加配置文件config-client.yml到远程仓库

    spring:
      profiles:
        active: dev
    ---
    server:
      port: 8200
    spring:
      profiles: dev
      application:
        name: client
    ---
    server:
      port: 8201
    spring:
      profiles: test
      application:
        name: client
    
    
  2. 新建模块springcloud_config_client,导入依赖

    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-config-client -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-client</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
  3. 创建配置文件bootstrap.yml(系统级配置,一般不会改变,在bootstrap中写系统级的配置,采用springlcloud-config,模块独有的配置写在application.yml中)

    spring:
      cloud:
        config:
          name: config-client # 需要从git上读取的配置文件名,不要后缀
          profile: dev
          label: master # git分支
          uri: http://localhost:3000 #server的地址
    
  4. 创建启动类,并启动,可以看到服务端可以读取远程的配置,客户端读取了服务端的配置文件,从服务端中的配置文件配置的端口启动了

    image-20210801184425957

    image-20210801184347012

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值