六小时学会SpringCloud

SpringCloud学习

一 、第一部分

是什么

能干什么

去哪里下

怎么使用了解一个新技术的步骤

版本设置

SpringBoot2.x与SpringCloudH版本

https://start.spring.io/actuator/info查看具体版本的对应情况
在这里插入图片描述

SpringCloudAlibaba

设置的版本

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <mysql.version>5.1.47</mysql.version>
    <druid.version>1.1.12</druid.version>
    <mybatis.spring.boot.version>2.1.2</mybatis.spring.boot.version>
    <junit.version>4.10</junit.version>
    <log4j.version>1.2.17</log4j.version>
    <lombok.version>1.18.6</lombok.version>
  </properties>
  <!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version  -->
  <dependencyManagement>
    <dependencies>
      <!--SpringBoor2.3.0-->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.3.0.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!-- SpringCloud Hoxton.SR1 -->
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Hoxton.SR1</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!--SpringCloud-Alibaba 2.1.0 RELEASE-->
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.1.0.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!--mysql-connection-->
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
      </dependency>
      <!--druid-->
      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>${druid.version}</version>
      </dependency>
      <!--mybatis-spring-boot-->
      <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>${mybatis.spring.boot.version}</version>
      </dependency>
      <!--junit-->
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
      </dependency>
      <!--log4j-->
      <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j.version}</version>
      </dependency>
      <!--lombok-->
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

order是消费者,payment是消费者

cloud-provider-payment8001提供者

cloud-consumer-order80消费者

操作步骤:建model 改pom 写yml 主启动 业务类

一个model的操作流程

  1. 建立model

  2. 修改pom.xml文件

  3. 配置yml文件

  4. 建立数据库与设置实体类以及返回给前端的通用配置类

  5. 设置主启动类

  6. 编写业务需求

    5.1 mapper与mapper.xml

    5.2 service serviceimpl

    5.3 Controller

通用配置类 是专门用来负负责向前端响应数据的

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonResult<T> {
    /**
     * code 404 200等
     * message 响应的信息
     * data 保存发送的数据
     */
    private Integer code;
    private String message;
    private T data;
    public CommonResult(Integer code,String message){
        this(code,message,null);
    }
}

RestTemplate提供了多种便捷的访问远程Http服务的方法

是一种简单便捷的访问restful服务的模板类是Spring提供的用于访问Rest服务

客户端模板工具集

通过使用restTemplate能够实现消费者对提供者的跨域请求

1、注册RestTemplate

@Configuration
public class ApplicaitonContextConfig {
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

进行发送跨域请求

但是生产者与消费者里面之间是存在冗余,都存在实体类,所以需要将公共部分进行抽离存放在一个单独的模块里面

在新建的model里面引入重复定义的实体类(最好路径一致),然后在其他的模块里面引入这个模块

完成简单的0基础的分布式基础配置


1、服务的注册和发现(Eureka,Zookeepr)

因为传统的rpc远程调用框架中,管理每个服务和服务之间的关系比较复杂,所以需要进行服务治理管理这些依赖,能够实现服务调用,负载均衡,容错等机制实现服务的发现与注册

Eureka
1.1 Eureka Server提供服务的注册服务
<!--eureka-server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
server:
  port: 7001
eureka:
  instance:
    hostname: localhost #eureka服务端的实例名称
  client:
    register-with-eureka: false #表示不向注册中心注册自己
    fetch-registry: false #表示自己就是就是注册中心,用来维护服务的实例,并不需要去检索服务
    service-url:
      #设置与EurekaServer交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

主启动类

@SpringBootApplication
@EnableEurekaServer  //需要开启Eureka服务
public class EurekaMain7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaMain7001.class,args);
    }
}

测试:http://localhost:7001/

1.2 Eureka Client 通过注册中心进行访问

将提供者与消费者注册进去

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
@EnableEurekaClient
eureka:
  client:
    #表示自己需要到注册中心里面进行注册
    register-with-eureka: true
    #是否在Eureka Server里面抓取以有的注册信息
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka/
 spring:
  application:
    name: cloud-payment-service这个是注册到eureka里面的名称一定要进行设置
1.3 集群Eureka的搭建步骤

实现负载均衡与故障容错(互相注册,相互守望,也就是说自己能够关联到出自己之外所有的注册信息)

创建一个EurekaServer 与另一个一样

1.更改windows下面的host的映射文件

127.0.0.1       localhost
127.0.0.1       eureka7001.com
127.0.0.1       eureka7002.com
127.0.0.1       eureka7003.com

2.配置yml文件

在7001的yml里面 连接7002同理7002也是

server:
  port: 7001
eureka:
  instance:
    hostname: eureka7001.com #eureka服务端的实例名称  这个名称在host文件里面进行了映射
  client:
    register-with-eureka: false #表示不向注册中心注册自己
    fetch-registry: false #表示自己就是就是注册中心,用来维护服务的实例,并不需要去检索服务
    service-url:
      #设置与EurekaServer交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7002.com:7002/eureka/

7002

server:
  port: 7002
eureka:
  instance:
    hostname: eureka7002.com #eureka服务端的实例名称
  client:
    register-with-eureka: false #表示不向注册中心注册自己
    fetch-registry: false #表示自己就是就是注册中心,用来维护服务的实例,并不需要去检索服务
    service-url:
      #设置与EurekaServer交互的地址查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7001.com:7001/eureka/

测试:http://eureka7002.com:7002/或者localhost:7002都会显示指向对应的服务,形成一个集群的服务

3、客户端注册到集群里面

defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

4、最好配置提供者的集群服务

  • 端口不能一致
  • 修改Controller 查看是否搭建成功
import org.springframework.beans.factory.annotation.Value;
@Value("${server.port}")
private String serverPort;

return new CommonResult(200,"插入数据成功"+serverPort,i);
        }else{
            return new CommonResult(666,"对不起插入数据是被"+serverPort,null);

5、修改消费者的Controller 根据名字

public static final String PAYMENT_URL="http://CLOUD-PAYMENT-SERVICE";
因为这这个名字下面有两个提供者  随机进行选取 消费者只需要关注提供者的名称

需要开启RestTemplate注解富裕RestTemplate负载均衡的功能

@Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }80里面使用@LoadBalanced进行负载均衡

补充:actuator微服务信息的完善

前提是:引入了web和actuator的配置文件

  • 主机名称:服务名称的修改 尽可能不把真实的主机名进行暴露
eureka:
  client:
    #表示自己需要到注册中心里面进行注册
    register-with-eureka: true
    #是否在Eureka Server里面抓取以有的注册信息
    fetch-registry: true
    service-url:
#      defaultZone: http://localhost:7001/eureka/
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
  instance:
    instance-id: payment8002  自定义主机名
  • 范文信息有IP信息的提示
instance:
    instance-id: payment8001
    prefer-ip-address: true

​ 服务发现Discovery

在8001的Controller中

@Resource
    private DiscoveryClient discoveryClient;
在自身进行测试就可以了
@GetMapping("/discovery")
    public Object discovery(){
        List<String> services = discoveryClient.getServices();
        for(String element:services){
            log.info("***element"+element);
        }
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for(ServiceInstance instance:instances){
            log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
        }
        return this.discoveryClient;
    }
@EnableDiscoveryClient

测试

@GetMapping("/discovery")
    public Object discovery(){
        List<String> services = discoveryClient.getServices();
        for(String element:services){
            //获取当前eureka上面的服务
            log.info("***element"+element);
        }
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for(ServiceInstance instance:instances){
            log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
        }
        return this.discoveryClient;
    }
    /**
     * ***elementcloud-payment-service
     * : ***elementcloud-order-service
     *  CLOUD-PAYMENT-SERVICE	172.17.226.28	8001	http://172.17.226.28:8001
     *  CLOUD-PAYMENT-SERVICE	172.17.226.28	8002	http://172.17.226.28:8002
     */
1.4、Eureka的自我保护

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

也可以禁用保护模式 (网上查阅资料)

Zookeeper
1.5 Zookeeper的注册于发现

将Eureka换位Zookeeper

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>
	controller   这个是服务的提供者
@RestController
@RequestMapping("/payment")
@Slf4j
public class PaymentController {
    @Value("${server.port}")
    private String serverPort;
    @GetMapping("/zk")
    public String paymentzk(){
        return "springcloud with zookeeper:"+serverPort+"\t"+ UUID.randomUUID().toString();
    }
}

因为使用了zooker的引入可能会出现zookeeper与jar包冲突的问题

解决冲突问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eW0hn94G-1600564910203)(C:\Users\Administrator\Desktop\SpringCloud笔记\解决zk与jar冲突问题.png)]

!解决方案

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mIf8ZWzF-1600564910205)(C:\Users\Administrator\Desktop\SpringCloud笔记\zookeeper与jar冲突问题.png)]

测试:http://localhost:8004/payment/zk

特性:只要提供者取消,那么zookeeper就会将其进行删除,下一次启动就会产生一个新的

服务的消费者

server:
  port: 88
spring:
  application:
    name: cloud-consumerzk-order
  cloud:
    zookeeper:
      connect-string: 192.168.120.129:2181
 @Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

@RestController
@Slf4j
@RequestMapping("/consumer")
public class OrderZkController {

    public static final String INVOKE_URL="http://cloud-provider-payment";
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/getzk")
    public String getzk(){
        String result=restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
        return result;
    }
}
consul

是一种分布式的服务发现和配置管理

1、安装Consul

下载安装包,在Window下使用consul agent -dev进行运行

localhost:8500进行检验运行

添加pom

<dependency>
   <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>

设置yml

server:
  port: 8005
spring:
  application:
    name: cloud-providerConsul-payment8005
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}

消费者的配置与zk一样只不过是引入的jar包不同而已

Eureka zookeeper consul比较在这里插入图片描述

补充:

spring cloud中discovery service有许多种实现(eureka、consul、zookeeper等等@EnableDiscoveryClient基于spring-cloud-commons, @EnableEurekaClient基于spring-cloud-netflix其实用更简单的话来说,就是如果选用的注册中心是eureka,那么就推荐@EnableEurekaClient,如果是其他的注册中心,那么推荐使用@EnableDiscoveryClient。(作用于提供者和消费者)

2、服务的负载与调用(Ribbon,OpenFeign)

1、Ribbon的使用与原理

ibbon是基于Netflix Ribbon实现的一套客户端(消费者使用的),负载均衡的工具

Ribbon:负载均衡+RestTemplate调用

在引入eureka的时候就会自动的引入Rabbion

Ribbon的核心组件是IRule

​ Irule:根据特定的算法在服务列表里面选取一个要访问的服务

注意:自定义配置类不能够放在@ComponentScan扫描的当前包下以及子包下,否则这个自动配置的类就会被所有的客户端共享,达不到特殊定制的目的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kbxVkmUn-1600564910208)(C:\Users\Administrator\Desktop\SpringCloud笔记\IRule的算法.png)]

自定义算法步骤:

​ 在main类扫描不到的包下创建爱你一个类

@Configuration
public class MySelRule {
    public IRule myRule(){
        return new RandomRule();
        //定义为随机的
    }
    //默认是轮询的
}

在main上设置一个使用的方法

@RibbonClient(value = "CLOUD-ORDER-SERVICE",configuration = MySelRule.class)

负载均衡算法:rest接口第几次请求服务器集群的数量=实际调用服务器的位置下标,

每次服务器重启之后rest接口数从1开始

2、OpenFeign

前面使用的是Ribbon与RestTemplate进行请求处理,但是在实际的开发中由于对服务的依赖调用可能不止一处,往往一个接口会被对出进行调用所以通常会针对每个微服务自行封装一些客户端的类来包装这些一依赖服务的调用,所以对于Fegin来说我们只需要创建一个接口使用注解的方式来进行配置即可

Feign集成了Ribbon维护类Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡,但是对于Feign来说只需要定义服务绑定接口并且以声明式的方法

现在feign已经不在维护现在使用的是OpenFeign(是作用于消费端的)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MKtPC8A2-1600564910210)(C:\Users\Administrator\Desktop\SpringCloud笔记\Feign与OpenFeign的对比.png)]

OpenFeign 的搭建与配置

<!--搭建OpenFeign 的jar包-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--还是以Eureka作为注册中心-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
这里还是以Eureka作为注册中心

在主启动类上面使用

@EnableFeignClients

在服务类上面使用

@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
表明想要访问的提供者的地址

整体思路:

​ 引入配置文件之后定义一个接口这个接口能够被容器扫描并且能够开启Feign注解,表明开启Feign并且识别那个提供这的而服务,访问提供者的那个方法并且在只启动类里面开启支持Feign的注解

@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService
{
    @GetMapping(value = "/select/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);

//    @GetMapping(value = "/payment/feign/timeout")
//    public String paymentFeignTimeout();
}
@RestController
@Slf4j
public class OpenFeignController {
    @Autowired
    private PaymentFeignService paymentFeignService;
    @GetMapping(value = "/consumer/select/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
        return paymentFeignService.getPaymentById(id);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xGi0IU3b-1600564910211)(C:\Users\Administrator\Desktop\SpringCloud笔记\OpenFeign的流程.png)]

注意这里的启动类之所以不需要添加EnableEurekaClient是因为后面已经支持只需要配置配置环境和配置文件就可以不需要在添加注解了


超时设置

#设置feign客户端超时时间(OpenFeign默认支持ribbon)
#ribbon:
#  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
#  ReadTimeout: 5000
#  #指的是建立连接后从服务器读取到可用资源所用的时间
#  ConnectTimeout: 5000

日志打印功能:

日志级别:

1、NONE:默认的不显示日志

2、BASE:仅权限请求的方法,URL,响应状态码以及执行时间

3、HEADERS:除了BASIC中定义信息之外,还有请求和响应的头信息

4、Full 除了HEADDERS中定义的信息之外,还有请求和响应的正文以及元数据

创建配置文件

@Configuration
public class FeignConfig {
    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}

​ 配置yml

logging:
  level:
#    Feign日志以什么级别监控一个接口
    com.ljx.service.PaymentFeignService: debug

3、服务的熔断降级(HyStrix)

能够保障一个依赖出现问题的情况下,不会导致整体的服务失败,避免级联故障,以提高分布式系统的弹性

是用来处理分布式系统的延迟容错的开源库

  1. 服务降级 fallback

服务器忙,不让客户端等待并且立刻返回一个友好的提示,调用方法返回一个符合预期的可处理的备选的相应

​ 程序运行时异常,超时,服务熔断触发服务降级,线程池/信号量打满也会导致服务降级

  1. 服务熔断 beak

    当访问量达到最大服务访问的时候,直接拒绝访问,拉闸限电,然后调用服务降级的方法返回友好的提示

  2. 服务限流 flowlimit

    秒杀,高并发等操作同一时刻量过大,使其有序的进行

操作步骤:

  1. 创建Model

  2. 引入pom

    <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
    还有eureka座位注册中心
    <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
    

​ 编写application.yml

server:
  port: 8001
spring:
  application:
    name: cloud-provider-hystrix-payment
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

编写启动类和服务


@Service
public class PaymentService {
    //正常访问
    public String paymentInfo_Ok(Integer id){
        return "线程池"+Thread.currentThread().getName()+"  paymentInfo_ok,id: "+id+"\t";
    }
    //使其超时测试
    public String paymentInfo_TimeOut(String id){
        int timeout=3;
        try {
            TimeUnit.SECONDS.sleep(timeout);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池"+Thread.currentThread().getName()+" paymentInfo_error  id"+id+"\t"+"耗时:"+timeout;
    }
}


@RestController
@Slf4j
public class PaymentController {
    @Resource
    private PaymentService paymentService;
    @Value("${server.port}")
    private String serverport;
    //成功的请求
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id)
    {
        String result = paymentService.paymentInfo_Ok(id);
        log.info("*****result: "+result);
        return result;
    }
    //超时的请求
    @GetMapping("/payment/hystrix/error/{id}")
    public String paymentInfo_error(@PathVariable String id){
        String timeOut = paymentService.paymentInfo_TimeOut(id);
        log.info("****result"+timeOut);
        return timeOut;
    }
}

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

创建消费者

pom.xml与application.yml

<!--  hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!--用oopfeign做负载 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--还是以Eureka作为注册中心-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
spring:
  application:
    name: cloud-consumer-feign-hystrix
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/
server:
  port: 88

这里使用的是Feign 所以要设置Service和Controller进行负载均衡

	设置Service
@Component
@FeignClient("CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface HystrixService {
    @GetMapping(value = "/payment/hystrix/ok/{id}")
    public String getPaymentById(@PathVariable("id") Long id);
    @GetMapping("/payment/hystrix/error/{id}")
    public String paymentInfo_error(@PathVariable("id") Long id);
}
	设置Controller
	@RestController
public class HystrixController {
    @Resource
    private HystrixService hystrixService;
    @GetMapping("/consumer/select/{id}")
    public String getPaymentId(@PathVariable("id") Long id){
        return hystrixService.getPaymentById(id);
    }
    @GetMapping("/consumer/error/{id}")
    public String getErrorPaymentId(@PathVariable("id") Long id){
        return hystrixService.paymentInfo_error(id);
    }
}

当有多个线程进行访问地时候容易产生异常会导致客户端访问减慢,所以就会有降级/容错/限流等产生,解决服务器变慢,出现(宕机)等问题,出现错误的时候不可以返回错误信息返回指定的界面

服务降级

对方服务器(8001)超时了,调用者(80)不能一直卡死等待,所以必须要有服务的降级

对方的服务器(8001)宕机了,调用了无法进行访问,所以要有服务的降级

调用者(80)访问的速度太慢,提供者出现多个线程产生堵塞,所以要有服务的降级

​ 服务降级

使用@HystrixCommand

@HystrixCommand 注解 能对某个一个接口定制 Hystrix的超时时间

1、在8001的角度设置自身的峰值,峰值内可以正常的运行,如果超过了要有兜底的方法作为降级的fallback

提供者
//使其超时测试   在3秒内执行完成都是可以接受的,但是超过了3秒就会出现错误  只要这个服务不可用自己跳转到兜底的服务里面
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandle",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
    })
    //如果超时了会执行哪一个方法
    public String paymentInfo_TimeOut(String id){
        int timeout=5;
        try {
            TimeUnit.SECONDS.sleep(timeout);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池"+Thread.currentThread().getName()+" paymentInfo_error  id"+id+"\t"+"耗时:"+timeout;
    }

    public String paymentInfo_TimeOutHandle(String id){
        return "我是当出现异常的时候进行兜底的服务";
    }
在主启动类里面需要开启服务降级的活动
@EnableCircuitBreaker开启服务降级的活动
全局默认的兜底方法

如果有服务出现超时 宕机等这些方法并且没有指定

2、对于80消费者方向来说

feign:
  hystrix:
    enabled: true #在feign里面开启Hystrix

其余的步骤与消费者是一致的

定义全局的兜底方法(全局 fallback)

使用注解指定默认的全局的注解方法

@DefaultProperties(defaultFallback = )
在Controller里面
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public String payment_Global_FallbackMethod(){
        return "这个是全局的接受的界面,如果没有指定的页面则执行这个页面";
    }

这样就可以对那些没有指定具体兜底方法的方法指定一个兜底的方法

配置指定方法的兜底方法

对每一个服务提供的方法进行解耦,这样就不用在Controller里面对每一个想要指定方法的方法进行兜底实现了指定兜底方法的全局性

进行解耦:根据Service接口新建一个实现了他的类,就可以对Service管理的提供者的服务进行统一的管理,就不用进行对每一个绑定的方法都设置一个兜底的方法了,就可以将Controller里面指定的兜底方法给取消了

feign:
  hystrix:
    enabled: true #在feign里面开启Hystrix
@Component
public class HystrixServiceImpl implements HystrixService {
    @Override
    public String getPaymentById(Long id) {
        return "我是getPaymentById方法的指定的兜底方法";
    }

    @Override
    public String paymentInfo_error(Long id) {
        return "我是paymentInfo_error方法的指定的兜底方法";
    }
}
一定要放入到容器里面
实现了指定方法接口的类,这些类就是指定方法的兜底方法

最后在Service接口里面指定默认的兜底方法

@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = HystrixServiceImpl.class)
public interface HystrixService {
    @GetMapping(value = "/payment/hystrix/ok/{id}")
    public String getPaymentById(@PathVariable("id") Long id);
    @GetMapping("/payment/hystrix/error/{id}")
    public String paymentInfo_error(@PathVariable("id") Long id);
}
@EnableFeignClients
@SpringBootApplication
@EnableHystrix
@EnableCircuitBreaker
启动类里面

服务熔断

熔断机制应对雪崩效应的是一种微服务链路保护机制,当扇出链路的某个微服务出错不可用或者响应的时间太长了就会对服务进行降级,进而熔断该节点微服务的调用,快速返回错误的响应信息,当检测到该节点微服务调用响应正常后恢复调用的链路

@HyStrixCommand

@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否开启断路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失败率达到多少后跳闸
    })
    public String paymentCircuitBreaker( Integer id)
    {
        if(id < 0)
        {
            throw new RuntimeException("******id 不能负数");
        }
        String serialNumber = IdUtil.simpleUUID();

        return Thread.currentThread().getName()+"\t"+"调用成功,流水号: " + serialNumber;
    }
    public String paymentCircuitBreaker_fallback(Integer id)
    {
        return "id 不能负数,请稍后再试,/(ㄒoㄒ)/~~   id: " +id;
    }

@GetMapping("/payment/circuit/{id}")
    public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
        String result = paymentService.paymentCircuitBreaker(id);
        log.info("****result: " + result);
        return result;
    }
当短时间错误的次数超过了6次就会触发一个熔断机制这样再次访问正确的也不会有效果  只有过了时间窗口期才会重新有效果

熔断的类型:

  1. 熔断打开:请求不在进行调用当前的服务,内部设置时钟一般为MTTR(平均故障的处理时间),当打开的时长达到所设值的时钟的时候就会进入到版熔断的状态
  2. 熔断关闭:熔断关闭不会对服务进行熔断
  3. 熔断断开:部分请求根据规则调用当前的服务,如果请求成功并且符合规则则认为当前的服务恢复正常,关闭熔断
熔断器开启或者关闭的条件:

当满足一定的阈值的时候(默认是10秒超过了20次的请求)

当失败率达到了一定的时候(默认10秒内超过50%的请求失败)

到达以上阈值的时候断路器就会开启

当开启之后所有请求都不会再进行转发

一段时候后默认是5秒,这个时候断路器是半开的状态,会让其中的一个请求进行转发,如果成功断路器会关闭如果失败继续开启重复4~5

服务限流

后期在高级部分进行讲解

服务监控hystrixDashboard

model +pom+yml

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

注意:要想实现监控对应的提供者(8001这些)都需要添加监控依赖配置actuator与web进行连用
端口设置9001
http://localhost:9001/hystrix进行测试  是否配置成功

这里通过9001来监控8001 所以8001要配置actuar的配置文件

在主启动类里面

@SpringBootApplication
@EnableCircuitBreaker
//EnableCircuitBreaker  实现服务熔断与降级
//@EnableEurekaClient
public class PaymentHystrixMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentHystrixMain8001.class,args);
    }
    /**
     *此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
     *ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
     *只要在自己的项目里配置上下面的servlet就可以了
     */
    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}9001.hystrix里面访问http://localhost:8001//hystrix.stream显示监控的实时情况

4、服务的网关 Getway

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kz8ndyrQ-1600564910212)(C:\Users\Administrator\Desktop\SpringCloud笔记\GetWay整体结构.png)]

Zuul(不怎么用了)现在基本上使用的都是GetWay

作为SpringCloud里面的网关,在微服务里面架构提供一种简单有效的统一的API的路由管理,是一种基于WebFlux框架实现的,而WebFlux地城是通过React模式通信框架Netty

基于Filter链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流

作用:

  1. 反向代理
  2. 监权
  3. 流量控制
  4. 熔断
  5. 日志监控

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6tKbCKhJ-1600564910212)(C:\Users\Administrator\Desktop\SpringCloud笔记\基本架构.png)]

特点:

动态路由:能够匹配任何请求的属性

可以对路由指定Predicate(断言)和Filter(过滤器)

集成hystrix的断路器功能:

集成了SpringCloud服务的发现功能等

三大核心概念:

Router(路由):构建网关的基本模块,他由ID,目标URL等一系列的断言和过滤器组成,如果断言为true则匹配路由

Predicate(断言):

Filter(过滤):使用过滤器可以在路由前或者后对请求进行修改

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3v95yDnw-1600564910213)(C:\Users\Administrator\Desktop\SpringCloud笔记\GateWay的工作流程.png)]

加入不想暴露路由的端口,希望在外面套一层9527

Router

注意getway的pom里面不要配置actuar和web会出现冲突

配置getway+pom+yml 配置路由

<!--gateway-->
        <dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
路由网关的配置
server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001          #匹配后提供服务的路由地址
          #uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/select/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001          #匹配后提供服务的路由地址
          #uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/lb/**         # 断言,路径相匹配的进行路由
            #- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
            #- Cookie=username,zzyy
            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式

eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    register-with-eureka: true #服务提供者provider注册进eureka服务列表内
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/


http://localhost:8001/select/1与http://localhost:9527/select/1产生的结果是一致的就会实现网关的代理

也可以通过注入RouterLocal的Bean进行注册

@Configuration
public class GateWayConfig
{
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder)
    {
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();

        routes.route("path_route_ljx",
                r -> r.path("/guonei")
                        .uri("http://news.baidu.com/guonei")).build();

        return routes.build();
    }
}
当访问http://localhost:9527/guonei==>http://news.baidu.com/guonei

通过微服务的名称实现动态路由

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由 采用了根据服务名称匹配的动态创建路由的格式
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/select/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/lb/**         # 断言,路径相匹配的进行路由
            #- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
            #- Cookie=username,zzyy
            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式

eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    register-with-eureka: true #服务提供者provider注册进eureka服务列表内
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/
Predicate断言

https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#gateway-request-predicates-factories

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址  lb://xxx都是这一种格式进行管理
          predicates:
            - Path=/select/**         # 断言,路径相匹配的进行路由
#            - After=2020-09-18T09:50:44.151+08:00[Asia/Shanghai]  #只有在9:50之后才可以进行调用
        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
#          uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/lb/**         # 断言,路径相匹配的进行路由
            - After=2020-09-18T09:50:44.151+08:00[Asia/Shanghai]
            #标志只有在这个时间之后断言才会起作用  在这个时间段之前无论是怎么访问都是不会有作用的
            #- Cookie=username,lijiaxi
            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式
            
  After指的是在做指定的时间之后才可以执行,在之前是不能进行运行的
  Cookie设置两个参数,一个是Cookie name,一个是正则表达式路由规则会通过获取对应的Cookie name值和正则表达式进行匹配,如果匹配上就会执行路由,如果没有匹配上就不会进行执行
  
可以使用curl进行微服务的测试 curl http://localhost:9527/select/1  --cookie "username=lijiaxi" 表示携带了cookie的方式进行传输数据  测试是否具有匹配的Cookie
用postman也可以
http://localhost:9527/select/1 -H "X-Request-Id:123"

在这里插入图片描述

Filter过滤器

使用过滤器能够在请求被路由之前后者之后被修改

https://docs.spring.io/spring-cloud-gateway/docs/2.2.5.RELEASE/reference/html/#gatewayfilter-factories

主要学习自定义的过滤器:

主要是实现两个接口

@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
    /**
     * 总的全局过滤器
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("欢迎来到全局过滤器"+new Date());
        String uname=exchange.getRequest().getQueryParams().getFirst("uname");
        if (uname==null){
            log.info("对不起非法用户,不可进入");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            //返回错误的原因
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

http://localhost:9527/select/1?username=123

4、服务的分布式部署

4.1、SpringCloud Config分布式配置中心

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7c0oD3gt-1600564910215)(C:\Users\Administrator\Desktop\SpringCloud笔记\Config.png)]

主要的作用就是一次配置处处生效,为微服务架构中的微服务提供集中化的外部部署支持,配置服务器为各个不同的微服务应用的所有环境提供了一个中心化的外部部署

Config服务端的配置与测试

<dependency>
         <!--server作为配置中心-->  <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <!--还是以Eureka作为注册中心-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
server:
  port: 3344
spring:
  application:
    name: cloud-config-center3344
  cloud:
    config:
      server:
        git:
          uri: git@github.com:ljx-p/SpringCloud-Config.git
          #对应的是GitHub上面的Git仓库的名称
          search-paths:
            - SpringCloud-Config
      label: master
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

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

Config分为客户端与服务端两种 客户端是获取服务端的数据,服务端是获取中心仓库的数据

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <!--还是以Eureka作为注册中心-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

需要引入bootstrap.yml

bootstrap.yml是系统级别的,优先级更高

application.yml是用户级别的资源

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:
      label: master #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称   上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
      uri: http://localhost:3344 #配置中心地址k

  #rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

# 暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: "*"
@RestController
@RefreshScope
public class ConfigClientController {
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo()
    {
        return configInfo;
    }
}
@SpringBootApplication
public class ConfigClientMain3355 {
    /**
     * 获取github里面config-dev.yml文件里面的config.info记录  通过localhost:3344进行获取
     * @param args
     */
    public static void main(String[] args) {
        SpringApplication.run(ConfigClientMain3355.class,args);
    }
}

解决客户端的动态刷新问题

  1. 添加actuator监控

  2. 修改yml暴露监控端口

    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
  3. @RefreshScope业务类Controller修改

  4. 此时修改github=>3344=>3355

  5. 运维人员发送Post请求刷新3355

  6. curl -X POST “http://localhost:3355/actuator/refresh”

但是总不能每一个服务都要进行进行单独的刷新所以引入了SpringCloud Bus

4.2、SpringCloud Bus 消息总线

在这里插入图片描述

在这里插入图片描述

安装RabbitMq在linux启动

实现Bus动态刷新全局广播

配置与3355一样

设计思想:

1、利用消息总线触发一个客户端/bus/refresh来刷新哭护短的配置

2、利用消息总线触发一个服务端的/bus/refresh断点而刷新所有客户端的配置(主)

给3344服务端添加消息总线的支持

在3344引入pom

<dependency>
    
  <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>

在yml里面增加rabbitmq的支持

#rabbitmq相关配置  是在spring级别下面的
rabbitmq:
  host: localhost
  port: 5672
  username: guest
  password: guest
#以及暴露bus的刷新配置的断点
#rabbitmq相关配置,暴露bus刷新配置的端点  对于这些暴露监控的一定要有actuator 除了Getway不需要配置尽可能都配置
management:
  endpoints: #暴露bus刷新配置的端点
    web:
      exposure:
        include: 'bus-refresh'

给3355客户端添加消息总线的支持

<dependency>
    
  <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
        
#rabbitmq相关配置  是在spring级别下面的
rabbitmq:
  host: localhost
  port: 5672
  username: guest
  password: guest
  单独的 暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

给3366客户端添加消息总线的支持

操作与3355一样

进行测试: 运维方面进行刷新

curl -X POST "http://localhost:3344/actuator/bus-refresh"来实现刷新服务器对所有的客户端都实现刷新

2、不想全部通知,只想定点通知

例如只想通知3355不想通知3366

http://lcoalhost:配置中心的端口号/actuator/bus-refresh/{destination}

通过destination参数类指定需要配置更新的服务或者实例

http://localhost:3344/actuator/bus-refresh/config-client:3355(applicationname+port)

4.3SpringCloud Stream 消息驱动

屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程模型

通过Bind进行处理两种不同的消息方式屏蔽底层,通过定义绑定器Binder作为中间层,实现了应用程序与消息中间件的细节之间的隔阂

SpringCloud Stream标准流程套路:

  1. Binder很方便的连接中间件,屏蔽差异
  2. 通道(Channel),是队列Queue的一种抽象,在消息通信系统中实现存储和转发的媒介,通过Channel对队列进行配置
  3. Source和Sink 简单的可以理解为参照对象是Spring Cloud Stream自身,从Stream发布信息就是输出,接受消息就是输入

在这里插入图片描述

Stream中的消息通信的方式遵循了发布-订阅的模式

定义一个提供者,两个消费者

提供者:

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

yml

server:
  port: 8801

spring:
  application:
    name: cloud-stream-provider
  cloud:
      stream:
        binders: # 在此处配置要绑定的rabbitmq的服务信息;
          defaultRabbit : # 表示定义的名称,用于于binding整合
            type: rabbit # 消息组件类型
            environment: # 设置rabbitmq的相关的环境配置
              spring:
                rabbitmq:
                  host: localhost
                  port: 5672
                  username: guest
                  password: guest
        bindings:
          output: # 这个名字是一个通道的名称  表示设施一个消息的生产者
            destination: studyExchange # 表示要使用的Exchange名称定义
            content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
            binder:  defaultRabbit  # 设置要绑定的消息服务的具体设置

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
    instance-id: send-8801.com  # 在信息列表时显示主机名称
    prefer-ip-address: true     # 访问的路径变为IP地址
public interface IMessageProviderService {
    /**
     * 这是一个发送消息的过程
     * @return
     */
    public String send();
}
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.MessageChannel;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.UUID;

/**
 * @author 李加喜
 * @date 2020/9/19 0019 12:38
 * @Email 1129071273@qq.com
 */
//@Service  不需要写了这里是需要与RabbitMQ进行交流的
@EnableBinding(Source.class) //定义消息的推送广告
public class IMessageProviderServiceImpl implements IMessageProviderService {
    @Resource
    private MessageChannel output;
    //消息发送管道

    @Override
    public String send() {
        String uuid= UUID.randomUUID().toString();
        output.send(MessageBuilder.withPayload(uuid).build());
        System.out.println(uuid);
        return uuid;
    }
    //通过output这个通道发送消息(output.send(MessageBuilder.withPayload(uuid).build());)到RabbitMQ
}
@RestController
public class SendMessageController {
    @Resource
    private IMessageProviderServiceImpl iMessageProviderService;
    @GetMapping("/sendMessage")
    public String sendMessage(){
        return iMessageProviderService.send();
    }
    //流程就是 调用之后就会开启输出源的通道,然后通过output消息的发送管道进行向中间件发送消息
}

消费者

pom.xml一直

application.yml

server:
  port: 8802
spring:
  application:
    name: cloud-stream-consumer
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitmq的服务信息;
        defaultRabbit: # 表示定义的名称,用于于binding整合
          type: rabbit # 消息组件类型
          environment: # 设置rabbitmq的相关的环境配置
            spring:
              rabbitmq:
                host: localhost
                port: 5672
                username: guest
                password: guest
      bindings: # 服务的整合处理
        input: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为对象json,如果是文本则设置“text/plain”
          binder: defaultRabbit # 设置要绑定的消息服务的具体设置
eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
    instance-id: receive-8802.com  # 在信息列表时显示主机名称
    prefer-ip-address: true     # 访问的路径变为IP地址
@Component
@EnableBinding(Sink.class)
public class ReseiveMessageListenerController {
    @Value("${server.port}")
    private String serverport;
    @StreamListener(Sink.INPUT)
    public void input(Message<String> message){
        System.out.println("消费者1号,----->接受到的消息: "+message.getPayload()+"\t  port: "+serverport);
    }
}
分组消费与持久化

不同的组是可以进行全面消费的(重复消费)

同一个组会发生竞争关系,只有其中的一个可以进行消费

重复消费:

​ 原因:默认分组group是不同的,组流水号不一样,被认为不同组可以进行消费

解决消息重复消费

将8802与8803分为同一个组 atxxA,atxxA

bindings: # 服务的整合处理
        input: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为对象json,如果是文本则设置“text/plain”
          binder: defaultRabbit # 设置要绑定的消息服务的具体设置
          group: atguiguA  《重点》
          另一个也是A

自定义配置分组:

​ 自定义配置分为同一个组,解决重复消费的问题

如果将8802里面的group删除关闭8802与8803之后运行8801之后再启动8802/3 之后8803能够接受到消息8802接受不到消息

4.4SpringCloud Sleuth 分布式请求链路跟踪

在微服务框架中,一个客户端发起的请求在后端系统中会经过多个不同的服务节点调用来写作产生最后的请求结果,每一个前段请求都会形成一条复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请求的最后失败

  1. 下载zipkin https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/2.12.9/
  2. zipkin-server-2.12.9-exec.jar 也可以直接通过docker进行下载

一条链路通过Trace iD唯一标识,Span标识发起的请求信息,各Span通过parent id进项进行标识

这里直接通过8001与80进行测试

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

设置yml

spring:
  application:
    name: cloud-payment-service
  zipkin:
     base-url: http://localhost:9411
  sleuth:
    sampler:
      #采样率在0~1之间 一般情况下去0.5 1表示全部采集
      probability: 1

就可以监控80访问8001的过程

二、第二部分

https://github.com/alibaba/spring-cloud-alibaba

https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

Cloud Alibaba

安装

<dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

Nacos

就是注册中心+配置中心

启动nacos cmd下startup.cmd

http://localhost:8848/nacos/#/login nacos密码nacos 这个就是本机的服务注册中心

nacos服务的提供者

父pom与子pom

<dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
</dependency>
<dependency>
           主要的 <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-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-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.ljx</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project-version}</version>
        </dependency>

application.yml

server:
  port: 9001
spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
management:
  endpoints:
    web:
      exposure:
        include: '*'
@SpringBootApplication
@EnableDiscoveryClient  注意
public class PaymentMain9002 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9002.class,args);
    }
}

@RestController
@RequestMapping("/payment")
public class PaymentController9001 {
    @Value("${server.port}")
    private String serverport;
    @GetMapping("/nacos/{id}")
    public String getPayment(@PathVariable("id") String id){
        return "nacos id+"+serverport+"\t id"+id;
    }
}

默认是支持负载均衡的

Nacos的消费者

都一样只不过在

yml里面

#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
service-url:
  nacos-user-service: http://nacos-payment-provider
@Configuration
public class ApplicationContext {
    @Bean
    @LoadBalanced
    public RestTemplate getTemplate(){
        return new RestTemplate();
    }
}
@RestController
@RequestMapping("/consumer")
public class OrderNacosController{
    @Resource
    private RestTemplate restTemplate;
    @Value("${service-url.nacos-user-service}")
    private String serviceURL;
    @GetMapping("/nacos/{id}")
    public String getPayment(@PathVariable("id") String id){
        return restTemplate.getForObject(serviceURL+"/payment/nacos/"+id,String.class);
    }
}
就可以实现消费者对提供者的负载轮询访问
Nacos集群和持久化的配置

可以替代COnfig做服务的配置中心 从外面获取想要的信息,和原生的Config 获取github里面的信息的原理一致

1、配置服务中心

<!--nacos-config-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

Nacos里面中的dataid的组成格式与SpirngBoot配置文件的匹配规则

https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html

在这里插入图片描述

这里是nacos-config-client-dev.yaml 注意这里一定要是yaml因为在配置中心里面只能够设置yaml的格式文件

在这里插入图片描述

这样nacos就可以在配置列表里面获取想要的信息进行全局获取

配置pom与yml

# nacos配置
server:
  port: 3377

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
      config:
        server-addr: localhost:8848 #Nacos作为配置中心地址
        file-extension: yaml #指定yaml格式的配置  这样3347就可以到8848里面获取yml文件的配置  意思就是从配置中心获取全局的配置文件
#        group: DEV_GROUP
#        namespace: 7d8f0f5a-6a53-4785-9686-dd460158e5d4

# ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
# nacos-config-client-dev.yaml

# nacos-config-client-test.yaml   ----> config.info

spring:
  profiles:
    active: dev # 表示开发环境
    #active: test # 表示测试环境
    #active: info

进行测试

@RestController
@RefreshScope  //支持Nacos的动态刷新
public class ConfigClientController {
    @Value("${config.info}")
    private String configInfo;
    @GetMapping("/config/info")
    public String getConfigInfo(){
        return configInfo;
    }
}

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

询访问




#### Nacos集群和持久化的配置

可以替代COnfig做服务的配置中心  从外面获取想要的信息,和原生的Config 获取github里面的信息的原理一致

**1、配置服务中心**

```xml
<!--nacos-config-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

Nacos里面中的dataid的组成格式与SpirngBoot配置文件的匹配规则

https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html

在这里插入图片描述

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

这里是nacos-config-client-dev.yaml 注意这里一定要是yaml因为在配置中心里面只能够设置yaml的格式文件

这样nacos就可以在配置列表里面获取想要的信息进行全局获取

配置pom与yml

# nacos配置
server:
  port: 3377

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
      config:
        server-addr: localhost:8848 #Nacos作为配置中心地址
        file-extension: yaml #指定yaml格式的配置  这样3347就可以到8848里面获取yml文件的配置  意思就是从配置中心获取全局的配置文件
#        group: DEV_GROUP
#        namespace: 7d8f0f5a-6a53-4785-9686-dd460158e5d4

# ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
# nacos-config-client-dev.yaml

# nacos-config-client-test.yaml   ----> config.info

spring:
  profiles:
    active: dev # 表示开发环境
    #active: test # 表示测试环境
    #active: info

进行测试

@RestController
@RefreshScope  //支持Nacos的动态刷新
public class ConfigClientController {
    @Value("${config.info}")
    private String configInfo;
    @GetMapping("/config/info")
    public String getConfigInfo(){
        return configInfo;
    }
}

@SpringBootApplication
@EnableDiscoveryClient
public class NacosConfigClientMain3377 {
    public static void main(String[] args) {
        SpringApplication.run(NacosConfigClientMain3377.class,args);
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值