SpringCloud学习记录

目录

1.什么是微服务

1.定义

2.特点

3.优势

4.相关问题与解决方案

5.SpringCloud的重要组件

1.Eureka注册中心

2.Ribbon客户端负载均衡器

3.Feign声明式的 Web 服务客户端

4.Hystrix服务容错管理

5.Zuul路由网关

6.Config

2.Eureka注册中心

1.Eureka的自我保护机制

2.Eureka与zoopKeeper的区别

3.使用

3.Ribbon

1.Ribbon负载均衡规则

2.负载均衡自定义方式

3.使用

4.Feign

5.Hystrix

1.服务熔断

2.服务降级

3.Dashboard流监控


文章所使用的示例代码:

https://gitee.com/qq1244811434/spring-cloud.git

请搭配此视频学习--------->【狂神说Java】SpringCloud教程IDEA版 此为2019发布,主要学习各个组件与演示作用

1.什么是微服务

1.定义

  • 微服务是一种架构风格,它将一个大型的单体应用程序分解为一组小型的、独立的服务。每个服务都运行在自己的进程中,并且通过轻量级的通信机制(如 RESTful API 或消息队列)进行通信。
  • 微服务可以独立地进行开发、部署、扩展和维护。例如,一个电商系统可以分解为用户服务(负责用户注册、登录等功能)、商品服务(负责商品信息的管理)、订单服务(负责订单的创建、处理等功能)等多个微服务。每个微服务都有自己的数据存储(可以是关系型数据库、NoSQL 数据库等),并且专注于自己的业务逻辑。

2.特点

  • 小型与自治:每个微服务都是一个小而独立的部分,负责完成特定任务。
  • 可独立部署:微服务可以独立地进行开发、测试、部署和扩展,提高了开发效率。
  • 松散耦合:服务之间通过轻量级的通信机制进行交互,降低了系统间的耦合度。
  • 技术选型灵活:不同的微服务可以采用不同的技术栈实现,开发者可以根据具体需求选择最适合的技术。

3.优势

  1. 可扩展性:微服务架构允许根据需要轻松扩展单个服务,而不是整个应用程序,从而提高了系统的可扩展性。
  2. 可维护性:由于服务之间松散耦合,因此可以更容易地定位和解决问题,降低了维护成本。
  3. 开发效率:微服务架构允许团队并行开发不同的服务,从而加快了开发速度。
  4. 技术多样性:开发者可以为不同的服务选择不同的技术栈,这有助于采用新技术并满足特定需求。

4.相关问题与解决方案

  1. 服务治理:微服务架构中服务数量众多,需要有效的服务治理机制来确保系统的稳定运行。这包括服务注册与发现、负载均衡、熔断与降级等策略。

  2. 数据一致性:在分布式系统中,确保数据的一致性和最终一致性是一个重要问题。可以采用分布式事务、事件驱动架构或补偿事务等策略来解决。

  3. 测试与维护:随着服务数量的增加,系统的测试和维护难度也会相应增加。需要建立完善的测试体系和监控机制来确保系统的质量。

5.SpringCloud的重要组件

1.Eureka注册中心

        主要用于微服务架构中,帮助各个微服务实例进行注册和发现。在一个基于微服务的分布式系统中,众多的微服务需要一种方式来互相知晓对方的位置(网络地址等信息),Eureka 注册中心就提供了这样的功能。

  • 服务注册:当一个微服务启动时,它会将自己的服务信息(如服务名称、IP 地址、端口号等)发送给 Eureka 注册中心。这个过程就像是一个新居民在社区服务中心登记自己的住址和联系方式一样。例如,一个名为 “user - service”(用户服务)的微服务,在启动后会把自己运行的 IP 地址 “192.168.1.1” 和端口号 “8080” 以及服务名称发送给 Eureka 注册中心。
  • 服务发现:其他微服务可以从 Eureka 注册中心获取需要与之通信的微服务的信息。比如,“order - service”(订单服务)想要调用 “user - service”,它会向 Eureka 注册中心询问 “user - service” 在哪里,Eureka 注册中心就会返回 “user - service” 的 IP 地址和端口号等信息,这样 “order - service” 就可以通过这些信息建立与 “user - service” 的通信连接。
  • 心跳机制:已注册的微服务会定期向 Eureka 注册中心发送心跳(通常是通过 HTTP 请求发送一个简单的信号),以表明自己还在正常运行。如果 Eureka 注册中心在一定时间内没有收到某个微服务的心跳,它会认为这个微服务出现了故障,就会将这个微服务从服务列表中剔除。

2.Ribbon客户端负载均衡器

        在多个服务实例之间分配请求,以实现负载均衡。当一个微服务调用另一个微服务时,Ribbon 会根据一定的策略(如轮询、随机等)选择服务实例。

即当有多个功能相同的服务ABC时,用户请求会先被Ribbon拦截,再由Ribbon根据Eureka返回的服务列表与负载均衡策略具体选择某一服务

3.Feign声明式的 Web 服务客户端

        它使得编写微服务之间的调用代码更加简单。Feign 通过接口定义的方式来隐藏 HTTP 请求的细节,开发人员只需要定义一个接口并添加注解来描述请求,Feign 会自动完成请求的构建和发送。

4.Hystrix服务容错管理

        主要用于处理微服务之间调用的故障和延迟问题。它提供了熔断器机制,当一个服务出现故障或者响应时间过长时,Hystrix 可以中断对该服务的请求,并提供降级策略(如返回默认值或者缓存数据),以防止故障扩散。        

5.Zuul路由网关

        是一个 API 网关。它作为系统的统一入口,对外提供服务。Zuul 可以进行请求路由、过滤等功能,例如将外部请求路由到内部不同的微服务,还可以在请求过程中进行身份验证、日志记录等操作。

6.Config

        配置管理中心。它用于集中管理微服务的配置文件。通过 Config,可以将微服务的配置信息存储在远程服务器(如 Git 仓库),微服务在启动时可以从 Config Server 获取配置信息,并且可以动态更新配置。

2.Eureka注册中心

1.Eureka的自我保护机制

        当一个微服务不可用时,Eureka不会立刻清理,依旧会对该微服务的信息进行保存、

  1. 默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka之间无法正常通行,此时以上行为可能变得非常危险--因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过自我保护机制来解决这个问题一当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该EurekaServer节点会自动退出自我保护模式。

  2. 在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该EurekaServer节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。

  3. 自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮和稳定

  4. 在SpringCloud中,可以使用eureka.server.enable-self-preservation =false 禁用自我保护模式【一般不推荐关闭自我保护机制】

2.Eureka与zoopKeeper的区别

首先了解CAP原则即

  • C(Consistency)强一致性
  • A(Availability)可用性
  • P(Partition tolerance)分区容错性
  1. 一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求

  2. 根据CAP原理,将NoSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类:

    • CA:单点集群,满足一致性,可用性的系统,通常可扩展性较差

    • CP:满足一致性,分区容错性的系统,通常性能不是特别高

    • AP:满足可用性,分区容错性的系统,通常可能对一致性要求低一些

Zookeeper保证的是CP;Eureka保证证的是AP;

zoopKeeper:

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

Eureka

        在设计时优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时,如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保住注册服务的可用性,只不过查到的信息可能不是最新的。

3.使用

搭建注册中心:

导入相关依赖

<!--        Eureka依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

在yml配置文件中进行相关配置

#配置Eureka 使服务注册
eureka:
  client:
    service-url:
      #Eureka服务器地址
      defaultZone: http://localhost:7001/eureka/
  instance:
#    修改此服务器在Eureka页面中的默认描述
    instance-id: springcloud-provider-dept-8001
#info配置 注册进Eureka的服务可以通过此配置对自身的服务进行一些说明
info:
  app.name: springcloud-studyCode

在启动类中添加相关依赖

/**
 * Eureka访问地址 http://localhost:7001/
 */
@SpringBootApplication
@EnableEurekaServer //表示Eureka服务端的启动类,接收其他服务的注册,即开启Eureka
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7001.class);
    }
}

服务注册

引入依赖

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

在yml配置文件中进行相关配置

spring:
	application:
		name: userservice
eureka:
	client:
		service-url:
			defaultZone: http://127.0.0.1:10086/eureka/

 使用消费者通过Eureka注册中心去访问服务提供者

@RestController
public class DeptConsumerController {

    //使用RestTemplate直接调用provider模块下的服务
    //参数为(url, 实体:map, Class<T> responseType)
    //提供便捷访问远程http的方法,简单的restful服务模板
    @Autowired
    private RestTemplate restTemplate;
    //指定服务提供者的地址与端口号
    //当只有一个注册中心时,直接访问
    //public static final String REST_URL_PREFIX="http://localhost:8001";
    //当有eureka集群时,直接访问服务名即provider中yml中的:
    // spring:
    //  application:
    //    #项目名称
    //    name: springcloud-provider-dept
    //此时访问eureka集群会被ribbon拦截并通知eureka返回服务列表供ribbon选择,再由负载均衡策略选择具体某一服务
    public static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-DEPT";

    /**
     * 获取指定ID的部门
     * @param id
     * @return
     */
    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id")Long id){
        //restTemplate.getForObject(请求的地址与接口,返回的类型)
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
    }

    /**
     * 新增部门
     * @param dept
     * @return
     */
    @RequestMapping("/consumer/dept/add")
    public boolean addDept(Dept dept){
        //restTemplate.postForObject(请求的地址与接口,传递的对象,返回的类型)
        return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
    }

    /**
     * 获取所有部门
     * @return
     */
    @RequestMapping("/consumer/dept/list")
    public List<Dept> list(){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
    }
}

3.Ribbon

1.Ribbon负载均衡规则

  1. 规则接口是IRule

  2. 默认实现是ZoneAvoidanceRule,根据zone选择服务列表,然后轮询

2.负载均衡自定义方式

  1. 代码方式:配置灵活,但修改时需要重新打包

  2. 发布配置方式:直观,方便,无需重新打包发布,但是无法做全局配置

3.使用

引入依赖 

<!--        导入ribbon依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-ribbon</artifactId>
        </dependency>
<!--        导入Eureka依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

 在yml配置文件中进行相关配置

eureka:
  client:
#    不向eureka中注册自己
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001:7001/eureka/,http://eureka7002:7002/eureka/,http://eureka7003:7003/eureka/

此时为eureka集群,配置有三个eureka注册中心

添加注解配置config

@Configuration
public class ConfigBean {
    /**
     * 配置RestTemplate
     * 在controller中使用RestTemplate调用provider的服务
     * @return
     */
    @Bean
    @LoadBalanced//使用ribbon开启负载均衡
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

负载均衡的使用

通过定义IRule实现可以修改负载均衡规则,有两种方式:
    1.代码方式:在order-service中的OrderApplication类中,定义一个新的IRule:
//此方法作用于全局
@Bean
  public IRule randomRule(){
    return new RandomRule();//随机策略
}
	2.配置文件方式:application.yml文件中,添加新的配置也可以修改规则:
userservice:
 ribbon:
	NFLoadBalancerRuleClassName:
com.netflix.loadbalancer.RandomRule#负载均衡规则

4.Feign

Feign内部已经集成负载均衡

调用微服务访问两种方法。ribbon效率比feign高,可读性比feign差

  1. 微服务名字 【ribbon】

  2. 接口和注解【feign】

Ribbon使用RestTemplate指定服务名去访问服务

@RestController
public class DeptConsumerController {
    @Autowired
    private RestTemplate restTemplate;

    public static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-DEPT";

    /**
     * 获取指定ID的部门
     * @param id
     * @return
     */
    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id")Long id){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
    }
}

 Feign指定服务名后通过注解与接口使用Autowired直接调用接口

@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")//指定服务名称
@Component//注册至spring中
public interface DeptClientService {
    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id);
    @GetMapping("/dept/list")
    public List<Dept> queryAll();
    @PostMapping("/dept/add")
    public boolean addDept(Dept dept);

}
@RestController
public class DeptConsumerController {

    @Autowired
    private DeptClientService service=null;//feign通过注解实现,若service不为null,则需要实现类

    /**
     * 获取指定ID的部门
     * @param id
     * @return
     */
    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id")Long id){
        return this.service.queryById(id);
    }

    /**
     * 新增部门
     * @param dept
     * @return
     */
    @RequestMapping("/consumer/dept/add")
    public boolean addDept(Dept dept){
        return this.service.addDept(dept);
    }

    /**
     * 获取所有部门
     * @return
     */
    @RequestMapping("/consumer/dept/list")
    public List<Dept> list(){
        return this.service.queryAll();
    }
}
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")//指定服务名称
@Component//注册至spring中
public interface DeptClientService {
    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id);
    @GetMapping("/dept/list")
    public List<Dept> queryAll();
    @PostMapping("/dept/add")
    public boolean addDept(Dept dept);

}

5.Hystrix

1.服务熔断

使用:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>
//启动类中添加注解开启对熔断的支持
@SpringBootApplication
//开启Eureka支持
//在服务启动后自动注册到Eureka中
@EnableEurekaServer
//服务发现
@EnableDiscoveryClient
//添加对服务熔断的支持
@EnableCircuitBreaker
public class DeptProviderHystrix_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProviderHystrix_8001.class);
    }
}
//在需要熔断的方法上添加 @HystrixCommand注解,参数为备用的方法名
@RestController
public class DeptController {
  @Autowired
  private DeptService deptService;
  @GetMapping("/dept/get/{id}")
  //当get方法出现异常时使用hystrix调用备选方法
  @HystrixCommand(fallbackMethod = "hystrixGet")
  public Dept get(@PathVariable("id") Long id){
      Dept dept = deptService.queryById(id);
      if (dept==null){//判断服务是否出现异常
          throw new RuntimeException("id=====>"+id+"不存在该用户!");
          //当抛出异常后Hystrix会使用hystrixGet()方法进行返回
      }
      return dept;
  }
  //备选方法
    public Dept hystrixGet(@PathVariable("id") Long id) {
        return new Dept().setDeptNo(id)
                .setDeptName("id=====>" + id + "不存在该用户!-----》Hystrix")
                .setDbName("no this message in database");
    }
}

2.服务降级

使用:

feign:
  hystrix:
  #开启服务hystrix,否则feign与hystrix无法共用
    enabled: true
//在接口中指定FallBackFactory,服务关闭后将执行其中的方法
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallBackFactory.class)//指定服务名称与服务熔断降级的类
@Component//注册至spring中
public interface DeptClientService {
    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id);
    @GetMapping("/dept/list")
    public List<Dept> queryAll();
    @PostMapping("/dept/add")
    public boolean addDept(Dept dept);

}
//实现FallbackFactory方法
/**
 * 实现失败回调
 * 服务降级
 * 一个类里面所有的方法都熔断(无法访问抛出异常)=降级
 * 当服务关闭后将执行此处的的方法
 */
@Component//注册到spring容器中
public class DeptClientServiceFallBackFactory implements FallbackFactory {
    @Override
    public DeptClientService create(Throwable throwable) {
        return new DeptClientService() {
            @Override
            public Dept queryById(Long id) {
                return new Dept().setDeptNo(id)
                        .setDeptName("id==>"+id+"客户端提供服务降级,该服务已关闭")
                        .setDbName("无数据源");
            }
            @Override
            public List<Dept> queryAll() {
                return null;
            }
            @Override
            public boolean addDept(Dept dept) {
                return false;
            }
        };
    }
}

3.Dashboard流监控

使用:

#导入相关依赖
<!--        导入hystrix依赖实现dashboard流监控-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
<!--        dashboard监控界面-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>

 

#启动类开启流监控
@SpringBootApplication
//开启Dashboard流监控
@EnableHystrixDashboard
public class DeptConsumerDashboard_9001 {
    //http://localhost:9001/hystrix 访问地址
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumerDashboard_9001.class);
    }
}

yml配置

server:
  port: 9001
#hystrix监控页面无法打开时添加一下配置
hystrix:
  dashboard:
    proxy-stream-allow-list: localhost

监控对象

//在需要监控的的启动类上注入bean
/**
 * 启动类
 */
@SpringBootApplication
//开启Eureka支持
//在服务启动后自动注册到Eureka中
@EnableEurekaServer
//服务发现
@EnableDiscoveryClient
//添加对服务熔断的支持
@EnableCircuitBreaker
public class DeptProviderHystrix_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProviderHystrix_8001.class);
    }

    //使此服务能够被Dashboard监控
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        ///actuator/hystrix.stream为hystrix页面配置路径
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        return registrationBean;
    }
}

6.Zuul路由网关

Zuul包含了对请求的路由和过滤两个最主要的功能:

其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础,而过滤器功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础。

Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。

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

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

在本机的C:\Windows\System32\drivers\etc路径下hosts文件中添加127.0.0.1 mystudy.com

使用:

#路由设置
zuul:
  routes:
    #将服务名称替换为自定义URL
    myDept.serviceId: springcloud-provider-dept
    myDept.path: /myDept/**

 配置后

此时仍然可以通过微服务名进行访问因此还需要在yml中进行配置

#路由设置
zuul:
  routes:
    #将服务名称替换为自定义URL
    myDept.serviceId: springcloud-provider-dept
    myDept.path: /myDept/**
#    无法使用此路径访问服务
  ignored-services: springcloud-provider-dept

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值