springcloud 学习笔记(二)springcloud工程基础

引言

上篇文章中小猿说明了分布式服务必须面临的问题,要解决这些问题,我们就引入了注册管理中心,目前较为常见的注册管理中兴有Eureka、Zookeeper、Nacos,zookeeper小猿已经使用过了,他是RPC框架dubbo对应注册中心,而springcloud微服务比较流行的注册中心有Nacos,Eureka,下面我们先来学习Eureka。

Eureka注册中心

DevOps的思想是系统可以通过一组过程,方法或系统,提高应用发布和运维的效率,降低管理成本,而Eureka的设计也要遵从DevOps的思想。

Eureka能帮我们做什么

  1. Eureka记录服务提供者的信息。服务调用者无需自己寻找服务,而是把自己的需求告诉Eureka,然后Eureka会把符合需求的服务告诉服务调用者。
  2. 服务提供方与Eureka之间通过 “心跳” 机制进行监控,当某个服务提供方出现问题,Eureka自然会把它从服务列表中剔除,这就实现了服务的自动注册、发现、状态监控

注册原理

Eureka注册中心的工作原理其实与zooker注册中心的原理类似,下面 Eureka注册中心的工作原理图。

在这里插入图片描述

案例

注册中心

在这里插入图片描述

依赖文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloudparents</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eurekaserver</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!--<plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <!--<executions>
                    <execution>
                        <phase>none</phase>
                    </execution>
                </executions>-->
            </plugin>
        </plugins>
    </build>

</project>
启动类
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
配置文件
server:
  #修改端口高可用
  port: ${port:10086}
spring:
  application:
    name: eureka-server
eureka:
  client:
    service-url:
      # eureka 服务地址,如果是集群的话;需要指定其他集群Eureka地址
      # 修改defaultZone高可用
      defaultZone: ${defaultZone:http://127.0.0.1:10086/euraka}
    #不注册自己 默认为ture
    register-with-eureka: false
    #不主动拉取服务 默认为ture
    fetch-registry: false
userservice
工程结构

在这里插入图片描述

依赖文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloudparents</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>userservice</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>userdao</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!--<plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <!--<executions>
                    <execution>
                        <phase>none</phase>
                    </execution>
                </executions>-->
            </plugin>
        </plugins>
    </build>
</project>
启动类
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.feitian.dao")
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}
service类
@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    /**
     * 根据主键查询
     * @param id
     * @return
     */
    public User queryById(Long id){
        return userDao.selectByPrimaryKey(id);
    }
}
service访问类
@RestController
@RequestMapping("/userController")
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/findById/{id}")
    public User findById(@PathVariable Long id){
        return userService.queryById(id);
    }
}
配置类
server:
  port: ${port:9090}
spring:
  profiles:
    active: dataSource
  application:
    name: userservice
eureka:
  client:
    service-url:
      #defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
      defaultZone: http://127.0.0.1:10086/eureka
consumer
工程结构

在这里插入图片描述

依赖文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloudparents</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>consumer</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>-->
    </dependencies>
    <build>
        <plugins>
            <!--<plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <!--<executions>
                    <execution>
                        <phase>none</phase>
                    </execution>
                </executions>-->
            </plugin>
        </plugins>
    </build>
</project>
启动类
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
    
    @Bean
    /*@LoadBalanced*/
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

在启动类中需要获取RestTemplate并放入容器中。

web层
@RestController
@RequestMapping("/consumerController")
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

/*    @RequestMapping("/findById/{id}")
    public UserDomain findById(@PathVariable Long id){
        //String url = "http://localhost:9090/userController/findById/"+id;
        String url = "http://userservice/userController/findById/"+id;
        UserDomain userDomain = restTemplate.getForObject(url, UserDomain.class);
        return  userDomain;
    }*/
  @GetMapping ("/findById/{id}")
    public UserDomain findById(@PathVariable Long id){
        String url = "";
        List<ServiceInstance> userservice = discoveryClient.getInstances("userservice");
        ServiceInstance serviceInstance = userservice.get(0);
        url="http://"+ serviceInstance.getHost()+":"+serviceInstance.getPort()+"/userController/findById/"+id;
        UserDomain userDomain = restTemplate.getForObject(url, UserDomain.class);
        return  userDomain;
    }
}
配置文件
server:
  port: 9099
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
userdao类
工程结构

在这里插入图片描述

依赖导入
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloudparents</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>userdao</artifactId>
    <dependencies>
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>
</project>

无需启动,不需要导入spring-boot-maven-plugin

实体类
@Data
@Table(name = "tb_user")
public class User{
    // id
    @Id
    //开启主键自动回填
    @KeySql(useGeneratedKeys = true)
    private Long id;

    // 用户名
    private String userName;

    // 密码
    private String password;

    // 姓名
    private String name;

    // 年龄
    private Integer age;

    // 性别,1男性,2女性
    private Integer sex;

    // 出生日期
    private Date birthday;

    // 创建时间
    private Date created;

    // 更新时间
    private Date updated;

    // 备注
    private String note;
}
userDao
public interface UserDao extends Mapper<User> {



}
配置文件
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud
    username: root
    password: root
mybatis:
  type-aliases-package: com.feitian.domain

首先需要启动eurekaserver,再分别启动service和consumer,注意service报错出现没有userdao依赖文件,则需安装一下userdao模块。

配置euraka集群

为了实现冗余设计,提高系统的可用性,我们采用冗余设计。
在这里插入图片描述
首先要实现Eureka服务器之间的相互注册,开启自动注册和主动拉取服务。

server:
  #修改端口高可用
  port: ${port:10086}
spring:
  application:
    name: eureka-server
eureka:
  client:
    service-url:
      # eureka 服务地址,如果是集群的话;需要指定其他集群Eureka地址
      # 修改defaultZone高可用
      defaultZone: ${defaultZone:http://127.0.0.1:10086/euraka}
    #不注册自己
    #register-with-eureka: false
    #不主动拉取服务
    #fetch-registry: false

在这里插入图片描述

配置eureka集群

配置eureka服务器相互注册

第一台eureka服务器配置
在这里插入图片描述
第二台eureka服务器配置
在这里插入图片描述

配置服务端和消费端

在这里插入图片描述
消费端也一样配置即可。

测试

启动所有服务后访问eureka控制台
在这里插入图片描述
在这里插入图片描述
说明一个由2台eureka服务器组成的集群搭建成功

多个Eureka集群搭建

如果有三台或者三台以上的Eureka服务器,则每一台EurekaServer都需要注册到其它几个Eureka服务中,
例如:有三个分别为10086、10087、10088,则:
10086要注册到10087和10088上
10087要注册到10086和10088上
10088要注册到10086和10087上
在Eureka客户端,则需要将自身服务注册到所有eureka服务器上。

Eureka客户端参数配置

在客户端服务提供者在启动时,首先会检测配置属性中的:eureka.client.register-with-erueka=true 参数是否正确,事实上默认就是true。如果值确实为true,则会向EurekaServer发起一个Rest请求, 并携带自己的元数据信息,EurekaServer会把这些信息保存到一个双层Map结构中。

第一层Map的Key就是服务id,一般是配置中的spring.application.name 属性

第二层Map的key是服务的实例id。一般host+ serviceId + port,例如: localhost:userservice:9090值则是服务的实例对象,也就是说一个服务,可以同时启动多个不同实例,形成集群。

配置默认注册名

默认注册时使用的是主机名或者localhost,如果想用ip进行注册,可以在 userservice 中添加配置如下:

server:
  port: 9099
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    # 更倾向使用ip地址,而不是host名
    prefer-ip-address: true
    ip-address: 127.0.0.1

在这里插入图片描述

配置续约

在注册服务完成以后,服务提供者会维持一个心跳(定时向EurekaServer起Rest请求),告诉EurekaServer:“我还活着”。这个我们称为服务的续约(renew);

server:
  port: 9090
spring:
  profiles:
    active: dataSource
  application:
    name: userservice
eureka:
  client:
    service-url:
      #defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    # 更倾向使用ip地址,而不是host名
    prefer-ip-address: true
    ip-address: 127.0.0.1
    #续约间隔时间 默认30秒
    lease-renewal-interval-in-seconds: 5
    #服务失效时间,默认30秒
    lease-expiration-duration-in-seconds: 30     

在这里插入图片描述
注意这个是服务提供者端配置。

配置服务拉取时间

此服务,这是在消费端配置,即及时去拉取服务,此配置需要配置在消费者端
当服务消费者启动时,会检测 eureka.client.fetch-registry=true 参数的值,如果为true,则会从EurekaServer服务的列表拉取只读备份,然后缓存在本地。并且 每隔30秒 会重新拉取并更新数据。如若改变拉取时间,可以在consumer模块的yaml中修改配置。

server:
  port: 9099
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
      #获取服务地址列表间隔时间,默认30秒
    registry-fetch-interval-seconds: 10

在这里插入图片描述

失效剔除和自我保护

失效踢出

当服务进行正常关闭操作时,它会触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心:“我要下线了”。服务中心接受到请求之后,将该服务置为下线状态。
然而在这过程中我们也会遇到服务可能由于内存溢出或网络故障等原因使得服务不能正常的工作,而服务注册中心并未收到“服务下线”的请求。相对于服务提供者的“服务续约”操作,服务注册中心在启动时会创建一个定时任务,默认每隔一段时间(默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务剔除,这个操作被称为失效剔除,通常我们需要设置相关的时间参数
可以在eureka服务端来对此进行配置

自我保护

当关停一个服务,很可能会在Eureka面板看到一条警告:
在这里插入图片描述
出现这个警告的原因是触发了eureka的自我保护机制。
当服务未按时进行心跳续约时,Eureka会统计服务实例最近15分钟心跳续约的比例是否低于了85%。在生产环境下,因为网络延迟等原因,心跳失败实例的比例很有可能超标,但是此时就把服务剔除列表并不妥当,因为服务可能没有宕机。Eureka在这段时间内不会剔除任何服务实例,直到网络恢复正常。生产环境下这很有效,保证了大多数服务依然可用,不过也有可能获取到失败的服务实例,因此服务调用者必须做好服务的失败容错。

server:
  #修改端口高可用
  port: ${port:10086}
spring:
  application:
    name: eureka-server
eureka:
  client:
    service-url:
      # eureka 服务地址,如果是集群的话;需要指定其他集群Eureka地址
      # 修改defaultZone高可用
      defaultZone: ${defaultZone:http://127.0.0.1:10086/euraka}
    #不注册自己 默认为ture
    register-with-eureka: false
    #不主动拉取服务 默认为ture
    fetch-registry: false
  server:
    #服务失效剔除时间间隔 默认60秒
    eviction-interval-timer-in-ms: 30000
    #关闭自我保护
    enable-self-preservation: false

在这里插入图片描述

负载均衡

Ribbon是Netflix发布的负载均衡器,他有助于控制HTTP和TCP客户端的行为,Ribbon配置服务提供地址列表后,就可以基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon就可以基于某种负载均衡算法,自动地帮助服务消费者去请求、
Ribbon默认为我们提供了很多的负载均衡算法,我们也可以自定义其中的一些算法。

负载均衡案例

首先负载均衡小案例需至少要两个userservice模块,一个注册中心,还有一个consumer模块,

注册中心

注册中心的启动引导类不需要发生变化,需要取消集群配置,改为一般配置

server:
  #修改端口高可用
  port: ${port:10086}
spring:
  application:
    name: eureka-server
eureka:
  client:
    service-url:
      # eureka 服务地址,如果是集群的话;需要指定其他集群Eureka地址
      # 修改defaultZone高可用
      defaultZone: ${defaultZone:http://127.0.0.1:10086/euraka}
    #不注册自己 默认为ture
    register-with-eureka: false
    #不主动拉取服务 默认为ture
    fetch-registry: false
  server:
    #服务失效剔除时间间隔 默认60秒
    eviction-interval-timer-in-ms: 30000
    #关闭自我保护
    enable-self-preservation: false

在这里插入图片描述

consumer模块
修改引导类
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }

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

将RestTemplate放入容器时 需要加入@LoadBalanced注解 配置文件可不做修改或者配置服务拉取时间。

配置文件
server:
  port: 9099
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
      #获取服务地址列表间隔时间,默认30秒
    registry-fetch-interval-seconds: 10
改造web层
@RestController
@RequestMapping("/consumerController")
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping("/findById/{id}")
    public UserDomain findById(@PathVariable Long id){
        //String url = "http://localhost:9090/userController/findById/"+id;
        String url = "http://userservice/userController/findById/"+id;
        UserDomain userDomain = restTemplate.getForObject(url, UserDomain.class);
        return  userDomain;
    }
/*    @GetMapping ("/findById/{id}")
    public UserDomain findById(@PathVariable Long id){
        String url = "";
        List<ServiceInstance> userservice = discoveryClient.getInstances("userservice");
        ServiceInstance serviceInstance = userservice.get(0);
        url="http://"+ serviceInstance.getHost()+":"+serviceInstance.getPort()+"/userController/findById/"+id;
        UserDomain userDomain = restTemplate.getForObject(url, UserDomain.class);
        return  userDomain;
    }*/
}

值得一提的是此处将原来的地址http://localhost:90xx替换为userservice的名称。但userservice对应两个端口,如果访问成功,则表明fegin负载均衡生效了。
在这里插入图片描述

userservice模块

配置选件需要修改

server:
  port: ${port:9090}
spring:
  profiles:
    active: dataSource
  application:
    name: userservice
eureka:
  client:
    service-url:
      #defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    # 更倾向使用ip地址,而不是host名
    prefer-ip-address: true
    ip-address: 127.0.0.1
    #续约间隔时间 默认30秒
    lease-renewal-interval-in-seconds: 5
    #服务失效时间,默认30秒
    lease-expiration-duration-in-seconds: 30

需要修改端口。

配置多个userservice模块

采用idea配置即可
在这里插入图片描述
在这里插入图片描述

userdao

userdao模块则不需要修改。

测试

在这里插入图片描述
在这里插入图片描述

负载均衡原理

在这里插入图片描述
在这里插入图片描述
打开负载均衡配置类:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
接着就会进入下面的代码
在这里插入图片描述

测试

第一次访问
在这里插入图片描述
端口为9090
第二次访问
在这里插入图片描述
说明ribbon的默认负载均衡方式为轮询方式。

HYSTRIX

hystrix英译为豪猪,它与eureka同属Netflix旗下产品,它在微服务系统中是一款提供保护机制的组件,它是Netflix开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败。

雪崩效应

在这里插入图片描述
如库存服务出现问题,则导致商品服务出现问题,商品服务出现问题导致订单服务出现问题,累计就成为一个很严重的问题导致整个系统全面瘫痪。

hystrix的作用节

Hystrix解决雪崩问题的手段主要是服务降级,包括线程隔离,服务熔断
那么hystrix如何解决雪崩问题,主要是通过线程隔离和服务降级。

线程隔离&服务降级

hystrix如何采用服务降级问题,Hystrix为每个依赖服务调用分配一个小的线程池,如果线程池已满则调用将被立即拒绝,默认不采用排队,加速失败判定时间。
用户的请求将不再直接访问服务,而是通过
线程池中的空闲线程来访问服务,如果线程池已满,或者请求超时,
则会进行降级处理。
服务降级: 优先保证核心服务,而非核心服务不可用或弱可用。用户的请求故障时,不会被阻塞,更不会无休止的等待或者看到系统崩溃,如当系统压力比较大时可以返回一个比较友好的提示。
服务降级虽然会导致请求失败,但是不会导致阻塞,而且最多会影响这个依赖服务对应的线程池中的资源,对其它服务没有响应。

总结
  • 线程隔离:用户请求不直接访问服务,而是使用线程池中空闲的线程访问服务,加速失败判断时间。
  • 服务降级:及时返回服务调用失败的结果,让线程不因为等待服务而阻塞。
触发Hystrix服务降级的情况
  1. 线程池已满.
  2. 请求超时。

熔断器

Hystrix的服务熔断机制,可以实现弹性容错;当服务请求情况好转之后,可以自动重连。通过断路的方式,将后续请求直接拒绝,一段时间(默认5秒)之后允许部分请求通过,如果调用成功则回到断路器关闭状态,否则继续打
开,拒绝请求的服务。

熔断器的模型如下所示:
在这里插入图片描述
Closed:关闭状态(断路器关闭),所有请求都正常访问。
Open:打开状态(断路器打开),所有请求都会被降级。Hystrix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全打开。默认失败比例的阈值是50%,请求次数最少不低于20次。
Half Open:半开状态,不是永久的,断路器打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放部分请求通过,若这些请求都是健康的,则会关闭断路器,否则继续保持打开,再次进行休眠计时。

熔断器案例

我们可以采用程序的方式,当访问的id为1,我们就让程序访问失败并抛异常,这样就会人为产生访问失败,不断让他产生失败,从而达到熔断保护的目的。

改造consumer文件

controller类改造

@RestController
@RequestMapping("/consumerController")
@Slf4j
@DefaultProperties(defaultFallback = "defaultFallback")
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    /*@RequestMapping("/findById/{id}")
    @HystrixCommand(fallbackMethod = "findByIdCallBack")
    public UserDomain findById(@PathVariable Long id){
        //String url = "http://localhost:9090/userController/findById/"+id;
        String url = "http://userservice/userController/findById/"+id;
        UserDomain userDomain = restTemplate.getForObject(url, UserDomain.class);
        return  userDomain;
    }*/

    @RequestMapping("/findById/{id}")
    @HystrixCommand(fallbackMethod = "findByIdCallBack")
    public String findById(@PathVariable Long id){
        //String url = "http://localhost:9090/userController/findById/"+id;
        if(id ==1){
            throw new RuntimeException("太忙了!!!");
        }
        String url = "http://userservice/userController/queryById/"+id;
        UserDomain userDomain = restTemplate.getForObject(url, UserDomain.class);
        return  userDomain.toString();
    }

 /*@GetMapping ("/findById/{id}")
    public UserDomain findById(@PathVariable Long id){
        String url = "";
        List<ServiceInstance> userservice = discoveryClient.getInstances("userservice");
        ServiceInstance serviceInstance = userservice.get(0);
        url="http://"+ serviceInstance.getHost()+":"+serviceInstance.getPort()+"/userController/findById/"+id;
        UserDomain userDomain = restTemplate.getForObject(url, UserDomain.class);
        return  userDomain;
    }*/

    public String findByIdCallBack(Long id){
            log.error("查询用户信息失败。id:{}", id);
            return "对不起,网络不太好!";
    }

    public String defaultFallback(Long id){
        log.error("查询用户信息失败。id:{}", id);
        return "对不起,网络太忙了!";
    }
}

启动类加上熔断注解或者直接用springcloud来代替上面的几个注解,

/*@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker*/
@SpringCloudApplication //可代替上述三个注解
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
    
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

在这里插入图片描述

yaml配置文件
spring:
  application:
    name: consumer
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
      #获取服务地址列表间隔时间,默认30秒
    registry-fetch-interval-seconds: 10
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000 #熔断超时设置,默认为1秒
      circuitBreaker:
        errorThresholdPercentage: 50 # 触发熔断错误比例阈值,默认值50%
        sleepWindowInMilliseconds: 10000 # 熔断后休眠时长,默认值5秒
        requestVolumeThreshold: 10 #熔断触发最小请求次数,默认值是20

熔断器测试

首先不断访问id=1的数,不断产生异常,当异常达到阈值就会触发熔断机制
在这里插入图片描述
当触发熔断机制时,则其他请求也就会失效。
在这里插入图片描述
当熔断机制恢复,则其他请求就可正常访问。
在这里插入图片描述
辞职springcloud的基础知识已经复习的的差不多了,小猿希望各位后面复习中获得更多的知识。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值