springcloud

1、简介

springcloud 是微服务开发组件集合。


微服务:mirco-service
小服务,一般情况把整个项目划分多个小模块,针对每个小模块建立独立的工程,有独立的数据库,能够提供独立的服务

微服务开发过程遇到最基本的问题:
1、服务发现与注册问题 【Eureka、 Consul、 Nacos
2、服务调用问题 【Ribbon 、 Feign】
3、服务集中配置问题 【SpringCloud config 结合 git】
4、服务保护问题 【Hystrix】
5、服务的网关问题 【Zuul SpringCloud gateway】

初识springcloud

1、springcloud : 整合市场所有知名企业微服务框架,汇聚在一起!定位集合
2、版本问题:SpringCloud底层需要依赖springboot构建因此,注意本次:Greenwich ---> 要求springboot版本 2.1.X
3、注意:一般微服务开发:
1、基于apache dubbo
2、基于springcloud
3、基于k8s (技术难度大,运维复杂,绑定,国内目前不太流行)
4、dubbo和springcloud 区别:
性能:dubbo优于springcloud
底层通信协议:(dubbo RPC 、 springcloud HTTP)
dubbo是基于更为底层通信协议,封包和拆包的效率高
springcloud基于应用层通信协议,封包和拆包效率低
功能:springcloud功能更加完善

2、服务注册中心组件

组件: 能够单独完成某一项功能的一个软件或者框架。


两项最基本功能:
服务注册
服务发现

1.1、eureka组件

基本架构: C/S 架构 (client 和 server) Java中很多c/s 依赖方式。

1.1.1 创建一个服务提供方工程 (一个微服务)

提供根据商品id查询商品功能 --- 接口:
        ①接口Java程序员的眼中interface关键字,
        ②前端或者测试眼中接口 http://localhost:8080/goods/1 

第一步:引入依赖

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

第二步: 编写配置文件 application.yml

server:
  port: 8000

eureka:
  instance:
    hostname: localhost #主机名
    prefer-ip-address: true #使用IP注册到eureka
    ip-address: 127.0.0.1 #设置当前的实例IP
    instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} #eureka控制台中显示的实例ID
    lease-renewal-interval-in-seconds: 3 # 每隔3秒发一次心跳包,默认30秒
    lease-expiration-duration-in-seconds: 9 # 如果9秒内没有发心跳包,就会被服务器干掉,默认90秒
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka #eureka服务端地址,将来客户端使用该地址和eureka进行通信
      
spring:
  application:
    name: eureka-provider #设置当前应用的名称:
                          #  1.将来会在eureka管理平台的Application中显示
                          #  2.将来需要使用该名称来获取路径

第三步: 编写相关逻辑代码

//引导类
package com.itheima.provider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient //开启eureka客户端
public class ProviderApp {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApp.class,args);
    }
}
//实体类
public class Goods {

    private int id;
    private String title;//商品标题
    private double price;//商品价格
    private int count;//商品库存

    public Goods() {
    }

    public Goods(int id, String title, double price, int count) {
        this.id = id;
        this.title = title;
        this.price = price;
        this.count = count;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}
//dao层
package com.itheima.provider.dao;
import com.itheima.provider.domain.Goods;
import org.springframework.stereotype.Repository;
@Repository
public class GoodsDao {
    public Goods fingById(int id){
        return new Goods(1,"华为手机",399,10000);
    }
}
//service层
package com.itheima.provider.service;

import com.itheima.provider.dao.GoodsDao;
import com.itheima.provider.domain.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class GoodsService {
    @Autowired
    private GoodsDao goodsDao;

    public Goods findOne(int id){
        return goodsDao.fingById(id);
    }
}
//controller层
package com.itheima.provider.contrller;

import com.itheima.provider.domain.Goods;
import com.itheima.provider.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/goods")
public class GoodsController {

    @Autowired
    private GoodsService goodsService;

    @GetMapping("/findOne/{id}")
    public Goods findOne(@PathVariable("id") int id){
        Goods goods = goodsService.findOne(id);
        return goods;
    }
}

1.1.2 创建一个消费者工程(一个微服务),只需要调用 生产者工程 提供好的这个接口!

第一步:导入依赖同生产者

第二步:编写配置文件

server:
  port: 9000
eureka:
  instance:
    hostname: localhost #主机名
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka #eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
  application:
    name: eureka-consume
//引导类
package com.itheima.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient # 开启
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

第三步:实体类与生产者一致

第四步: 编写 RestTemplate 配置类

服务调用 : RestTemplate 底部封装HTTP

package com.itheima.consumer.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

第五步: 编写控制层

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/goods/{id}")
    public Goods findGoodsById(@PathVariable("id") int id){
        //根据服务名称获取服务路径集合
        List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");
        //对路径做作健壮性判断
        if (instances == null || instances.size() ==0){
            return null;
        }
        //因为当下只有一个,所以索引为0 直接获取路径
        ServiceInstance instance = instances.get(0);
        URI uri = instance.getUri();
        //远程调用Goods服务中的 findOne() 接口
        /**
         * 1. 定义Bean restTemplate
         * 2. 注入Bean
         * 3. 使用方法
         */
        String url = uri+"/goods/findOne/"+id;
        Goods goods = restTemplate.getForObject(url, Goods.class);
        return goods;
    }
}

1.1.3 创建eureka服务端:

第一步: 导入依赖

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

第二步: 配置文件 application.yam

server:
  port: 8761

eureka:
  instance:
    hostname: localhost #主机名

  client:
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka #eureka服务端地址,将来客户端使用该地址和eureka进行通信

    register-with-eureka: false #默认为true,是否将自己的地址注册到eureka上 集群时需要  provider client也需要
    fetch-registry: false #是否需要从eureka中抓取路径, consumer client 需要


  server:
    enable-self-preservation: false # 关闭自我保护机制
    eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔位3秒,默认60秒

第三步: 引导类

package com.itheima;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaApp {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApp.class,args);
    }
}
eureka配置分为4个部分:
1. dashboard : eureka的web控制台配置
2. server: eureka 的服务端配置
3. client: eureka的客户端配置
4. instance: eureka的实例配置

server中自我保护机制,默认就是开启的 (了解)

eureka:
    instance:  
        lease-renewal-interval-in-seconds: 3 # 每隔3秒发一次心跳包,默认30秒
        lease-expiration-duration-in-seconds: 9 # 如果9秒内没有发心跳包,就会被服务器干掉,默认90秒
    server:
        enable-self-preservation: false # 关闭自我保护机制
        eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔位3秒,默认60秒

1.1.4搭建server服务集群:

①在 C:\Windows\System32\drivers\etc 中有一个hosts文件,

需要分别绑定集群中成员的主机名与IP:  127.0.0.1       eureka-server1

②下面以其中一个配置文件为例: application.yam

server:
  port: 8761
eureka:
  instance:
    hostname: eureka-server1 #主机名
  client:
    service-url:
      defaultZone: http://eureka-server2:8762/eureka #集群这里是相互搭建
    register-with-eureka: true #默认为true,是否将自己的地址注册到eureka上 
    fetch-registry: true #是否需要从eureka中抓取路径
spring:
  application:
    name: eureka-server-ha #这里同一集群内的每个name最好一致

高可用


1.准备两个Eureka Server
2.分别进行配置,相互注册
3.Eureka Client分别注册到这两个Eureka Server中

1.2、consul组件

  • Consul是由HashiCorp基于Go语言开发的, 支持多数据中心, 分布式高可用的服务发布和注册服务软件。
  • 用于实现分布式系统的服务发现与配置。
  • 使用起来也较为简单。具有天然可移植性(支持Linux、windows和MacOSX) ; 安装包仅包含一个可执行文件,方便部署。
    官网地址: https://www.consul.io
开启方式: 
    1. 直接解压到E盘的software文件夹,按住shift+右键,选择 在此处打开Powersholl窗口 
    2. 输入开发模式命令:  .\consul agent -dev  (.\consul可以不加尾缀.exe,也可以加上。-dev开发者模式不会持久化任何数据)
    3. 管理控制台地址: http://localhost:8500/ui/dc1/services

1.搭建Provider和Consumer服务。
2.使用RestTemplate完成远程调用。
3.将Provider服务注册到Consul中。
4.Consumer服务通过从Consul中抓取Provider地址完成远程调用

1.2.1 服务提供方

需要依赖 pom.xml

<dependencies>

        <!--consul 客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</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-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--服务监控用-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
  </dependencies>

配置文件 application.yml

server:
  port: 8000
spring:
  cloud:
    consul:
      host: localhost # consul 服务端的 ip
      port: 8500 # consul 服务端的端口 默认8500
      discovery:
        service-name: ${spring.application.name} # 当前应用注册到consul的名称
        prefer-ip-address: true # 注册ip

  application:
    name: consul-provider # 应用名称

1.2.2 服务消费方

这里注意下开启 @EnableDiscoveryClient : 可以获取服务信息

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

1.3、nacos组件

  • Nacos(Dynamic Naming and Configuration Service) 是阿里巴巴2018年7月开源的项目。
  • 它专注于服务发现和配置管理领域致力于帮助您发现、配置和管理微服务。Na cos支持几乎所有主流类型的“服务”的发现、配置和管理。
  • 一句话概括就是Nacos=SpringCloud注册中心+SpringCloud配置中心。
    官网:https://nacos.io/
    下载地址:https://github.com/alibaba/nacos/releases
    本地起来后访问网址: http://localhost:8848/nacos
    用户名: nacos 密码: nacos
    开启nacos服务: E:\software\nacos\bin startup.cmd

1.3.1 需要依赖

<dependencies>
        <!--nacos-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>0.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>1.1.0</version>
        </dependency>


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

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies><dependencies>
        <!--nacos-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>0.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>1.1.0</version>
        </dependency>


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

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

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

配置文件

server:
  port: 8000

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # 配置nacos 服务端地址
  application:
    name: nacos-provider # 服务名称

3、Ribbon客户端负载均衡

Ribbon是Netflix提供的一个基于HTTP和TCP的 客户端 负载均衡工具。
Ribbon主要有两个功能:1.简化远程调用 2.负载均衡

服务端负载均衡

  • 负载均衡算法在服务端
  • 由负载均衡器维护服务地址列表

客户端负载均衡

负载均衡算法在客户端
客户端维护服务地址列表



@Configuration
public class RestTemplateConfig{
  @LoadBalance
  @Bean
  public RestTemplate restTemplate() { return new RestTemplate() ;}
}
/**
*使用Ribbon简化rest Template调用
*1.在声明rest TempLate的Bean时候, 添加一个注解:@LoadBalanced
*2.在使用rest TempLate发起请求时, 需要定义url时,host:port可以替换为, 服务提供方的应用名称
*@param id
*@return
*/
@Get Mapping(“/goods 2/{id} “)
public Goods findGoodsById2(@PathVariable(“id") int id) {
  String url=“http://EUREKA-PROVIDER/goods/findOne/“+id;
  //3.调用方法
  Goods goods = restTemplate.getForObject(url, Goods.class) ;
  return goods;
}

服务调用:
① RestTemplate 发送请求
② DiscoveryClient 从eureka中获取服务ip和端口
③ Ribbon 负载均衡 按照规则选取一个来调用

Ribbon负责均衡策略:

随机:RandomRule
轮询:RoundRobinRule
最小并发:BestAvailableRule
过滤:AvailabilityFilteringRule
响应时间:WeightedResponseTimeRule
轮询重试:RetryRule
性能可用性:ZoneAvoidanceRule

配置方式:①客户端代码添加规则 ②配置增加规则

代码方式:
package com.i theima.consumer.config;

import com.netflix.loadbalancer.I Rule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyRule{
  @Bean
  public IRule rule() {
    return new RandomRule();
  }
}
@EnableDiscoveryclient //激活DiscoveryClient 
@EnableEurekaClient
@SpringBootApplication
/*
  配置Ribbon的负载均衡策略 name
  *name:设置服务提供方的 应用名称
  *configuration:设置负载均衡 Bean
*/
@RibbonClient(name=“EUREKA-PROVIDER", configuration=My Rule.class)
public class ConsumerApp {
  public static void main(String[]args) {
    Spring Application.run(ConsumerApp.class, args);
  }
}
配置方式(在客户端配置)
#配置的方式设置Ribbon的负载均衡策略
EUREKA-PROVIDER: #设置的服务提供方的应用名称
  ribbon:
    NFloadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #策略类

4、Feign (粪) 简化 服务调用 【项目中会使用】

Feign是一个声明式的REST客户端, 它用了基于接口的注解方式, 很方便实现客户端配置。
Feign最初由Netflix公司提供, 但不支持SpringMVC注解, 后由SpringCloud对其封装, 支持了SpringMVC注解,让使用者更易于接受。

1.依赖 --- 消费端添加

<!--feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2.定义一个接口

接口上添加注解 @FeignClient,设置value属性为 服务提供者的 应用名称
里面的方法返回值and参数,需要与生产者的方法保持一致
映射路径需要在原方法的基础上添加 /goods

@FeignClient(value = "feign-provider") 
public interface GoodsFeignClient {
    @GetMapping("/goods/findOne/{id}")
    public Goods findGoodsById(@PathVariable("id")int id);
}

3.添加注解

@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients //开启Feign的功能
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

4.超时间设置:

在消费者配置文件中配置(feign底层使用的ribbon 我们一般设置ribbon超时时间即可)

# 设置Ribbon的超时时间
ribbon:
  ConnectTimeout: 1000 # 连接超时时间 默认1s
  ReadTimeout: 1000 # 逻辑处理的超时时间 默认1s

5.feign 的日志问题:

在消费者配置文件中配置

# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
  level:
    com.itheima: debug

5、Hystrix 服务熔断器(保险丝)

豪猪(身上带刺的猪,刺保护自己)

A--->B--->C 服务级联调用,过程中很容产生服务雪崩效应,我们Hystrix组件解决问这个问题。
Hystrix是Netflix开源的一个延迟和容错库, 用于隔离访问远程服务、第三方库,防止出现级联失败(雪崩)
雪崩:一个服务失败,导致整条链路的服务都失败的情形
Hystrix主要功能
隔离
降级
熔断
限流

1.隔离(默认配置)

1.线程池隔离
2.信号量隔离

2.降级

当服务发生异常或调用超时,返回默认数据
触发降级的场景: ①异常 ②超时


2.1 服务提供方降级

1.在服务提供方, 引入hystrix依赖
2.定义降级方法
3.使用@HystrixCommand注解配置降级方法
4.在启动类上开启Hystrix功能:@EnableCircuitBreaker

① 引入hystrix依赖

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

②注解: 引导类 @EnableCircuitBreaker , controller 方法上要加入@HystrixCommand(fallbackmethod=“降级方法名称”)

@EnableEurekaClient //该注解 在新版本中可以省略
@SpringBootApplication
@EnableCircuitBreaker //开启熔断器hystrix
public class ProviderApp {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApp.class,args);
    }
}

③编写降级方法 --- 这里的方法是生产者controller层提供服务的方法上

    @GetMapping("/findOne/{id}")
    @HystrixCommand(fallbackMethod = "findOne_fallback", commandProperties = {//指代触发降级后运行的方法
      @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",  value="3000")//超时
    }) 
    public Goods findOne(@PathVariable("id") int id){
        Goods goods = goodsService.findOne(id);
        //当前线程睡2秒
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        goods.setTitle(goods.getTitle() + ":" + port);//将端口号,设置到了 商品标题上
        return goods;
    }

    /**
     * 定义降级方法
     * 1. 方法的参数和返回值需与原方法保持一致
     */
    public Goods findOne_fallback(@PathVariable("id") int id){
        Goods goods = new Goods();
        goods.setTitle("降级了...");
        return goods;
    }

2.2 服务消费方降级

1.feign组件已经集成了hystrix组件。
2.定义feign调用接口实现类, 复写方法, 即降级方法
3.在@FeignClient注解中使用fallback属性设置降级处理类。
4.配置开启feign.hystrix.enabled=true

①配置文件中开熔断

#开启feign对hystrix的支持
feign:
  hystrix:
    enabled: true
#开启feign对hystrix的支持
feign:
  httpclient:
    enabled: true

② 写一个降级的类 a.实现feign客户端接口(自己定义远程调用的接口) b.加入springIOc容器

package com.itheima.consumer.feign;

import com.itheima.consumer.domain.Goods;
import org.springframework.stereotype.Component;

/**
 * Feign客户端降级处理
 * 1. 定义类 实现Feign接口
 * 2. 使用@Component注解,将改类加入springmvc
 * 3.
 */
@Component
public class GoodsFeignClientFallback implements GoodsFeignClient {
    @Override
    public Goods findGoodsById(int id) {
        Goods goods = new Goods();
        goods.setTitle("又降级了...");
        return goods;
    }
}

2.3 服务提供方 和消费方同时都提供 降级处理的时候,谁生效?

服务提供方的生效

3.熔断

Hystrix熔断机制, 用于监控微服务调用情况, 当失败的情况达到预定的阈值(5秒失败20次),会打开断路器,拒绝所有请求,直到服务恢复正常为止。


circuitBreaker.sleepWindowInMiliseconds:监控时间默认5000毫秒
circuitBreaker.requestVolumeThreshold:失败次数默认20次
circuitBreaker.errorThresholdPercentage:失败率默认50%  

只要我们引入依赖默认的配置不需要你去处理!

feign 底层 对 hystrix 进行了封装

 <!-- hystrix  如果有了feign就不需要了 -->
 <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
 </dependency>
<!--feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
#开启feign对hystrix的支持
feign:
  httpclient:
    enabled: true

熔断器的状态:

关闭: 正常提供服务
打开: 不能正常提供服务
半开: 有部分服务请求能够使用 (水龙头半开状态)

面试问题:
熔断器 :状态:3种状态 关闭状态半开状态打开状态 默认是关闭状态,关闭----》打开状态 (条件:当我们的服务降级次数在5秒内超过20次时候)打开---》半开状态 (条件:五秒之以后我会放一部分请求过来)----》关闭状态 (半开状态放过来的请求成功)

熔断器监控

Hystrix提供了Hystrix-dashboard功能, 用于时监控微服务运行状态。
但是Hystrix-dashboard只能监控一个微服务。
Netfix还提供了Turbine, 进行聚合监控。




image.png
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
spring:
  application.name: hystrix-monitor
server: 
  port: 8769
turbine:
  combine-host-port: true
  # 配置需要被监控的服务名称列表
  app-config: hystrix-provider, hystrix-consumer
  cluster-name-expression: "'default'"
  aggregator:
    cluster-config: default
  # instanceUrlSuffix: /actuator/hystrix.stream
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

创建启动类

@SpringBootApplication
@EnableEurekaclient
@EnableTurbine //开启Turbine很聚合监控功能
@EnableHystrixDashboard //开启Hystrix仪表盘监控功能
public class HystrixMonitorApp{
  public static void main(String[] args) {
    SpringApplication.run(HystrixMonitorApp.class, args) ;
  }
}

修改被监控模块,需要分别修改hystrix-provider和hystrix-consumer模块:
1、导入依赖:

<dependency>
   <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
@Bean
public ServletRegistrationBean getServlet(){
  HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
  ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
  registrationBean.setLoadOnStartup(1);
  registrationBean.addurlMappings("/actuator/hystrix.stream/);
  registrationBean.setName(“HystrixMetricsStreamServlet");
  return registrationBean;
}

启动服务后查看监控仪表盘
http://localhost:8769/hystrix/ 浏览器访问
http://localhost:8769/turbine.stream 仪表盘首页填入


4.限流

        4.1   rabbitMQ

         4.2  nginx

        4.3   gateway

6、SpringCloudGateway 网关 (城门)【项目中会使用】

网关 : 提供统一API路由访问的入口

网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等
在目前的网关解决方案里, 有Nginx+Lua、Netflix Zuul、SpringCloud Gateway等等

操作步骤:

1.搭建网关模块

2.引入依赖: starter-gateway

<!--引入gateway 网关-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

3.编写启动类

@SpringBootApplication
// 启用EurekaClient
@EnableEurekaClient
public class EurekaApp {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApp.class,args);
    }
}

4.编写配置文件

server:
  port: 80

eureka:
   client:
    service-url:
      defaultZone: http://localhost:8761/eureka
spring:
  application:
    name: api-gateway-server

  cloud:
    # 网关配置
    gateway:
      # 路由配置:转发规则
      routes: #集合。
        # id: 唯一标识。默认是一个UUID
        # uri: 转发路径
        # predicates: 条件,用于请求网关路径的匹配规则
        # filters:配置局部过滤器的

        - id: gateway-provider
          # 静态路由
          # uri: http://localhost:8001/
          # 动态路由 lb : load baldance 负载均衡     
          uri: lb://GATEWAY-PROVIDER
          predicates:
            - Path=/goods/**
          filters:  #局部过滤器
            - AddRequestParameter=username,zhangsan

        - id: gateway-consumer
          # uri: http://localhost:9000
          uri: lb://GATEWAY-CONSUMER
          predicates:
            - Path=/order/**
         
          
      # 微服务名称配置----这里是将请求路径前加项目名称,一般不用
      discovery:
        locator:
          enabled: true # 设置为true 请求路径前可以添加微服务名称
          lower-case-service-id: true # 允许为小写

7、Gateway 网关中的过滤器

内置过滤器工厂: https://www.jianshu.com/p/58267466251e

局部过滤器

以添加请求参数为列:

1.在网关模块的yam配置文件上添加配置

cloud:
    # 网关配置
    gateway:
      # 路由配置:转发规则
      routes: #集合。
        # filters:配置局部过滤器的

        - id: gateway-provider
          # 动态路由
          uri: lb://GATEWAY-PROVIDER
          predicates:
            - Path=/goods/**
          filters: #局部过滤器,这里只仅仅给goods路径下的请求添加参数
            - AddRequestParameter=username,zhangsan

        - id: gateway-consumer
          # uri: http://localhost:9000
          uri: lb://GATEWAY-CONSUMER
          predicates:
            - Path=/order/**
          # 微服务名称配置

2.给服务提供者的方法上添加 username 参数

 @GetMapping("/findOne/{id}")
    @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
            //设置Hystrix的超时时间,默认1s
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
            //监控时间 默认5000 毫秒
            @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
            //失败次数。默认20次
            @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
            //失败率 默认50%
            @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")

    })
    public Goods findOne(@PathVariable("id") int id,String username){
        System.out.println(username);

        //如果id == 1 ,则出现异常,id != 1 则正常访问
        if(id == 1){
            //1.造个异常
            int i = 3/0;
        }

        /*try {
            //2. 休眠2秒
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        Goods goods = goodsService.findOne(id);

        goods.setTitle(goods.getTitle() + ":" + port);//将端口号,设置到了 商品标题上
        return goods;
    }


    /**
     * 定义降级方法:
     *  1. 方法的返回值需要和原方法一样
     *  2. 方法的参数需要和原方法一样
     */
    public Goods findOne_fallback(int id,String username){
        Goods goods = new Goods();
        goods.setTitle("降级了~~~");

        return goods;
    }

全局过滤器

自定义全局过滤器步骤:

1.定义类实现 GlobalFilter 和 Ordered 接口

2.复写方法

3.完成逻辑处理
public class MyFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("自定义全局过滤器执行了......");
        return chain.filter(exchange);//放行当前过滤器,执行下个过滤器
    }

    /**
     * 过滤器排序
     * 数值越小越先执行
     * @return
     */
    public int getOrder() {
        return 0;
    }
}

8、微服务配置中心---Config

优点:

  1. 集中管理配置文件
  2. 不同环境不同配置,动态化配置更新
  3. 配置信息改变时,不需要重启即可更新配置信息到服务

config-server模块:

1.使用gitee创建远程仓库,上传配置文件

2.搭建config server 模块

@SpringBootApplication
@EnableConfigServer // 启用config server功能
public class ConfigServerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApp.class,args);
    }
}

3.导入config-server依赖

<!-- config-server -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

4.编写配置,设置gitee远程仓库地址

server:
  port: 9527

spring:
  application:
    name: config-server
  # spring cloud config
  cloud:
    config:
      server:
        # git 的 远程仓库地址
        git:
          uri: https://gitee.com/itheima_cch/itheima-configs.git
      label: master # 分支配置

5.测试访问远程配置文件

config-client模块:

1.导入 starter-config 依赖

<!--config client -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

2.配置 config server 地址,读取配置文件名称等信息

bootstrap.yml --- 优先级更高,一般用来系统化的配置

# 配置config-server地址
# 配置获得配置文件的名称等信息
spring:
  cloud:
    config:
      # 配置config-server地址
      uri: http://localhost:9527
      # 配置获得配置文件的名称等信息
      name: config # 文件名
      profile: dev # profile指定,  config-dev.yml
      label: master # 分支

3.获取配置值

Config客户端刷新

1.在config客户端引入actuator 依赖

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

2.获取配置信息类上,添加 @RefreshScope 注解

@RestController
@RequestMapping("/goods")
@RefreshScope //开启刷新功能
public class GoodsController {

    @Autowired
    private GoodsService goodsService;

    @Value("${server.port}")
    private int port;


    @Value("${itheima}")
    private String itheima;

    /**
     * 降级:
     *  1. 出现异常
     *  2. 服务调用超时
     *      * 默认1s超时
     *
     *  @HystrixCommand(fallbackMethod = "findOne_fallback")
     *      fallbackMethod:指定降级后调用的方法名称
     */

    @GetMapping("/findOne/{id}")
    @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
            //设置Hystrix的超时时间,默认1s
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
            //监控时间 默认5000 毫秒
            @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
            //失败次数。默认20次
            @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
            //失败率 默认50%
            @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")

    })
    public Goods findOne(@PathVariable("id") int id){

        //如果id == 1 ,则出现异常,id != 1 则正常访问
        if(id == 1){
            //1.造个异常
            int i = 3/0;
        }

        /*try {
            //2. 休眠2秒
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        Goods goods = goodsService.findOne(id);

        goods.setTitle(goods.getTitle() + ":" + port+":"+itheima);//将端口号,设置到了 商品标题上
        return goods;
    }


    /**
     * 定义降级方法:
     *  1. 方法的返回值需要和原方法一样
     *  2. 方法的参数需要和原方法一样
     */
    public Goods findOne_fallback(int id){
        Goods goods = new Goods();
        goods.setTitle("降级了~~~");

        return goods;
    }

}

3.添加配置

management:
  endpoints:
    web:
      exposure:
        include: '*'

4.使用curl工具在小黑窗口发送post请求

curl -X POST http://localhost:8001/actuator/refresh

config---集成eureka

在config-server模块配置eureka客户端依赖

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

添加配置信息

# 将自己注册到eureka中
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

9、Bus 消息总线

1.分别在config-server和config-client中引入 bus依赖: bus-amqp
2.分别在config-server和config-client中配置RabbitMQ
3.在config-server中设置暴露监控断点: bus-refresh
4.启动测试

不需要编写代码,只需要做配置:

https://cloud.spring.io/spring-cloud-bus/2.2.x/reference/html/appendix.html

1.分别再 config-server 和 config-client 中引入bus依赖: bus-amqp

<!--导入bus依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

<!-- 暴露断点 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2.分别在 config-server 和 config-client 中配置 RabbitMQ

3.在config-server 中设置暴露监控断点: bus-refresh

# 配置Rabbitmq,将配置模块注册到eureka中
 rabbitmq:
   host: localhost
   post: 5672
   username: guest
   password: guest
   virtual-host: /
    
# 暴露bus的刷新断点
management:
  endpoints:
    web:
      exposure:
        include: 'bus-refresh'

4.测试
还是要通知1次config_server,config_server通过bus消息总线通知各个微服务配置更新
在小黑窗口中输入: curl -X POST http://localhost:9527/actuator/bus-refresh

10、Stream消息驱动

  • Spring Cloud Stream是一个构建消息驱动微服务应用的框架。
  • Stream解决了开发人员无感知的使用消息中间件的问题, 因为Stream对消息中间件的进一步封装, 可以做到代码层面对中间件的无感知,甚至于动态的切换中间件,使得微服务开发的高度解耦,服务可以关注更多自己的业务流程。
  • Spring Cloud Stream目前支持两种消息中间件Rabbit MQ和Kafka
  • Spring Cloud Stream构建的应用程序与消息中间件之间是通过绑定器Binder相关联的。绑定器对于应用程序而言起到了隔离作用,它使得不同消息中间件的实现细节对应用程序来说是透明的。
  • binding是我们通过配置把应用和spring cloud stream的binder绑定在一起
  • output:发送消息Channel, 内置Source接口
  • input:接收消息Channel, 内置Sink接口

1.创建消息生产者模块

1.1引入依赖 starter-stream-rabbit

<!-- stream -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>

1.2编写配置,定义binder和bingings

server:
  port: 8000



spring:
  cloud:
    stream:
      # 定义绑定器,绑定到哪个消息中间件上
      binders:
        itheima_binder: # 自定义的绑定器名称
          type: rabbit # 绑定器类型
          environment: # 指定mq的环境
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
                virtual-host: /
      bindings:
        output: # channel名称
          binder: itheima_binder #指定使用哪一个binder
          destination: itheima_exchange # 消息目的地

1.3.定义消息发送业务类.添加 @EnableBindings(Source.class),注入MessageChannel output , 完成消息发送

@Component
@EnableBinding(Source.class)
public class MessageProducer {

    @Autowired
    private MessageChannel output;

    public void send(){
        String msessage = "hello stream~~~";

        //发送消息
        output.send(MessageBuilder.withPayload(msessage).build());

        System.out.println("消息发送成功~~~");

    }
}
@RestController
public class ProducerController {

    @Autowired
    private MessageProducer producer;


    @RequestMapping("/send")
        public String sendMsg(){
        producer.send();
        return "success";
    }
}

4.编写启动类,测试

2.创建消息消费者模块

2.1创建消息消费者模块,引入依赖 starter-stream-rabbit

同生产者

2.2编写配置,定义binder和bingings

server:
  port: 9000



spring:
  cloud:
    stream:
      # 定义绑定器,绑定到哪个消息中间件上
      binders:
        itheima_binder: # 自定义的绑定器名称
          type: rabbit # 绑定器类型
          environment: # 指定mq的环境
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
                virtual-host: /
      bindings:
        input: # channel名称 <-----------------------------------这里特别注意channel名称
          binder: itheima_binder #指定使用哪一个binder
          destination: itheima_exchange # 消息目的地

2.3定义消息接收业务类,添加 @EnableBinding(Sink.class) ,使用 @StreamListener(Sink.INPUT) ,完成消息接收

/**
 * 消息接收类
 */
@EnableBinding({Sink.class})
@Component
public class MessageListener {

    @StreamListener(Sink.INPUT)
    public void receive(Message message){

        System.out.println(message);
        System.out.println(message.getPayload());
    }
}

2.4编写启动类测试

11、Sleuth+Zipkin链路追踪

Spring Cloud Sleuth 其实是一个工具,它在整个分布式系统中能跟踪一个用户请求的过程,捕获这些跟踪数
据,就能构建微服务的整个调用链的视图,这是调试和监控微服务的关键工具。

• 耗时分析
• 可视化错误
• 链路优化

Zipkin 是 Twitter 的一个开源项目,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。

使用步骤:

  1. 安装启动zipkin。 java –jar zipkin.jar

  2. 访问zipkin web界面。 http://localhost:9411/

  3. 在服务提供方和消费方分别引入 sleuth 和 zipkin 依赖

     <!-- sleuth-zipkin -->
    <!--<dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-sleuth</artifactId>
         </dependency>-->
    
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
    
  4. 分别配置服务提供方和消费方。

    server:
      port: 8001
    
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka
    spring:
      application:
        name: feign-provider
      zipkin:
        base-url: http://localhost:9411/  # 设置zipkin的服务端路径
    
      sleuth:
        sampler:
          probability: 1 # 采集率 默认 0.1 百分之十。
    
  5. 启动,测试

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容