SpringCloud

SpringCloud(1)

1 什么是SpringCloud

分布式架构的一键式解决方案

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。

2 SpringBoot与SpringCloud的版本依赖关系

https://start.spring.io/actuator/info (官方指定的版本之间的依赖,避免冲突)

{
     "spring-cloud":{
         "Hoxton.SR11":"Spring Boot >=2.2.0.RELEASE and <2.3.11.BUILD-SNAPSHOT",
         "Hoxton.BUILD-SNAPSHOT":"Spring Boot >=2.3.11.BUILD-SNAPSHOT and <2.4.0.M1",
         "2020.0.0-M3":"Spring Boot >=2.4.0.M1 and <=2.4.0.M1",
         "2020.0.0-M4":"Spring Boot >=2.4.0.M2 and <=2.4.0-M3",
         "2020.0.0":"Spring Boot >=2.4.0.M4 and <=2.4.0",
         "2020.0.2":"Spring Boot >=2.4.1 and <2.5.0-M1",
         "2020.0.3-SNAPSHOT":"Spring Boot >=2.4.6-SNAPSHOT"
      },
      "spring-cloud-alibaba":{
         "2.2.1.RELEASE":"Spring Boot >=2.2.0.RELEASE and <2.3.0.M1"
      }
}

版本依赖关系

本次springcloud项目使用的是 springboot 2.2.2 **===========**springcloud Hoxton.SR1

3 父工程POM文件

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.springcloud</groupId>
    <artifactId>cloud2021</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--父工程的作用是用作于一个统一的依赖版本管理,给子项目的依赖传递-->
    <packaging>pom</packaging>


    <!--  统一管理jar包版本-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.sourse>1.8</maven.compiler.sourse>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
        <mysql.version>8.0.2</mysql.version>
        <druid.version>1.1.16</druid.version>
        <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
    </properties>

    <!---子模块继承之后,提供作用:锁定版本+子module不用写groupId和version,聚合管理,统一生效-->
    <!--子项目依赖不声明版本则使用父工程的依赖版本,若子项目中需要使用别的版本,那么可以额外申明单独的版本    -->
    <!--dependencyManagement只是申明依赖,并不实现引入,因此子项目需要显示的申明使用的依赖及版本-->
    <dependencyManagement>
        <dependencies>
            <!--springboot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.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-->
            <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-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
                <scope>runtime</scope>
            </dependency>
            <!-- druid-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <!--mybatis-->
            <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>
        </dependencies>
    </dependencyManagement>
    
  <!--热部署需要安装的插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

mvn
父工程创建完成执行mvn:install将父工程发布到仓库方便子工程继承

4 Eureka(服务发现)

服务发现是微服务架构中的一项核心服务。如果没有该服务,我们就只能为每一个服务调用者手工配置可用服务的地址,这不仅繁琐而且非常容易出错。Eureka包括了服务端Server 和客户端Client两部分。服务端可以做到高可用集群部署,每一个节点可以自动同步,有相同的服务注册信息。
在这里插入图片描述

4.1Eureka 单机
4.1.1 构建Server ,提供服务发现的服务端

1️⃣ 构建modual

2️⃣ 导入依赖

      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</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>

3️⃣ yml配置文件

server:
  port: 7001

eureka:
  instance:
    hostname: localhost
  client:
# 标明自己是注册中心,不需要检索自己服务
    fetch-registry: false
# 标明eureka不需要将自己的服务注册到注册中心上
    register-with-eureka: false
    service-url:
# 设置与eureka server交互的地址 (查询服务和祖册服务都需要这个地址)
       defaultZone: http://localhost:7001/eureka/

4️⃣启动Eureka

/**
 * @EnableEurekaServer 注解标明当前类是一个eureka的服务类
 */
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerMain {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServerMain.class,args);
    }
}
4.1.2 构建Client,注册服务与发现服务

1️⃣ 构建modual

2️⃣ 导入依赖

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

3️⃣ yml配置文件

#端口
server:
  port: 8001


#服务名称
spring:
  application:
    name: payment-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/redis?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8



#mybatis数据库配置
mybatis:
#  指定Mapper存放的静态路径
  mapper-locations: classpath:mapper/*.xml
# entity的类名映射包
  type-aliases-package: com.pojo



logging:
  level:
    com.mapper: debug


eureka:
  client:
    service-url:
    # 设置与eureka server交互的地址 (查询服务和祖册服务都需要这个地址)
    # defaultZone: http://localhost:7001/eureka(单机注册)
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka(集群注册)

    fetch-registry: true

    register-with-eureka: true
/**
 * EnableEurekaClient 标识当前类服务是eureka的客户端,需要将服务注册到注册中心上
 */
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain {

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

}
4.2 Eureka集群

为了避免出现单机故障,服务注册的方式需要采用集群的方式,提高可用性

业务实现逻辑

与单机注册不同的一点。集群服务的注册是互相注册相互守望。为了避免注册中心的服务实例一致,需要在同一台服务器上采用域名的方式来区分,因此需要修改

C:\Windows\System32\drivers\etc 路径下的hosts配置文件

#######SpringCloud#############
#eureka7001.com 7001端口的域名
127.0.0.1 eureka7001.com


#eureka7002.com 7002端口的域名
127.0.0.1 eureka7002.com

1️⃣ eureka7001服务端的配置文件

server:
  port: 7001


eureka:
  instance:
    hostname: eureka7001.com
  client:
# 标明自己是注册中心,不需要检索自己服务
    fetch-registry: false
# 标明eureka不需要将自己的服务注册到注册中心上
    register-with-eureka: false
    service-url:
# 设置与eureka server交互的地址 (查询服务和祖册服务都需要这个地址)
       defaultZone: http://eureka7002.com:7002/eureka/

1️⃣ eureka7002服务端的配置文件

server:
  port: 7002



eureka:
    instance:
      hostname: eureka7002.com
    client:
      # 标明自己是注册中心,不需要检索自己服务
      fetch-registry: false
      # 标明eureka不需要将自己的服务注册到注册中心上
      register-with-eureka: false
      service-url:
        # 设置与eureka server交互的地址 (查询服务和祖册服务都需要这个地址)
        defaultZone: http://eureka7001.com:7001/eureka/


#eureka集群的搭建需要相互祖冊 相互守望

eureka集群

4.3 Eureka提供服务端集群

service集群实现逻辑

4.4 服务发现

eureka客户端不仅仅能提供服务注册的功能,还能进行服务发现,获得注册中心上注册服务的供能

4.5 Eureka总结

eureka架构

📑

1:Eureka是为了解决微服务架构中多个微服务之间的服务治理和服务发现的组件之一。

2:Eureka中分为3个角色

角色角色功能
注册中心提供服务发现的功能,多个微服务启动之后,会向Eureka Server注册自己的信息
服务提供者EurekaClient端,服务启动后,注册自己的信息;通过心跳等机制保持与Server端的通信,实现服务的”注销“或者”续约“
服务消费者EurekaClient端,服务启动后,注册自己的信息;缓存EurekaServer上的注册表的信息,找到服务的提供者,实现Remote Call(远程调用)

3:Eureka Server同时也是EurekaClient。多个Zone中的Eureka单机实例通过之间通过Replicate【复制】的方式来实现服务注册表之间的同步。Eureka集群的方式避免了Eureka单点故障的可能性。

5.Ribbon(负载均衡)

5.1 Ribbon负载均衡算法的替换

Ribbon默认的负载均衡算法是轮询算法(rest接口第几次请求数%服务群总数量=实际调用服务器位置下标,每次服务器启动重启后rest接口计数从1开始)

可以自定义服务调用时的轮询算法

1️⃣ 自定义配置类

/**
 *  * 这个自定义配置类不能放在@Component注解所扫描的包下以及子包下,
 *  * 否则我们自定义的配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制化的目的
 */
@Configuration
public class MyIrule {


    /**
     * 配置类,采用随机的方式进行一个负载均衡
     * @return
     */
    @Bean
    public IRule getMyRule(){
        return new RandomRule();
    }

}

2️⃣指定服务开启自定义算法规则

/**
 * 标明了当消费者去消费PAYMENT_SERVICE时,负载均衡采用随机的算法
 */
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "PAYMENT-SERVICE",configuration = MyIrule.class)
public class OrderMain {

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

6 OpenFeign(服务调用)

OpenFeign是一个声明式的web服务客户端,让编写web服务客户端变的非常容易,只需要创建一个接口并在接口上添加注解即可。

OpenFeign是Spring Cloud在Feign的基础上支持了Spring MVC的注解,列如@RequestMapping等,OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

6.1OpenFeign的服务调用

1️⃣ 构建Webservice类

@Component
@FeignClient("PAYMENT-SERVICE")
public interface Feign_PaymentService {

    @GetMapping("/getPaymentById/{id}")
    ReturnMessageModel<Payment> getPaymentById(@PathVariable("id") Long id);

}

2️⃣激活OpenFeign,调用服务

@SpringBootApplication
@EnableFeignClients
public class OpenFeignOrderMain {


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

}

3️⃣测试类

@RestController
public class OpenFeignController {

    @Autowired
    private Feign_PaymentService service;


    @GetMapping("cosumer/feign/getPaymentByid/{id}")
    public ReturnMessageModel<Payment>getPaymentByid(@PathVariable("id") Long id){
        ReturnMessageModel<Payment> paymentById = service.getPaymentById(id);
        return paymentById;
    }
}

openfeign

6.2OpenFeign的超时控制

用open feign的方式调用服务时,默认是1ms的时间内获得请求结果,否则会出现客户端调用服务时超时

1️⃣模拟服务端的长流程服务执行,超过默认的1Ms钟

payment8001 服务

@GetMapping("/feignTimeOut")
public String feignTimeOut() {

    //模拟服务端执行长时间服务的情形
    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }



    return port;

}

2️⃣ open feign 接口的方式接入请求

/**
 * FeignClient客戶端请求的服务名称
 */
@Component
@FeignClient("PAYMENT-SERVICE")
public interface Feign_PaymentService {

    @GetMapping("/getPaymentById/{id}")
    ReturnMessageModel<Payment> getPaymentById(@PathVariable("id") Long id);


    @GetMapping("/feignTimeOut")
    String feignTimeOut();

}

3️⃣ 测试

/**
 * 用open feign的方式调用服务时,默认是1ms的时间内获得请求结果,否则会出现客户端调用服务时超时
 * @return
 */
@GetMapping("/consumer/feign/getFeignTimeOut")
    public String getFeignTimeOut(){
    return service.feignTimeOut();
}

openfeign超时

🎫 为了避免上述情形,并且合理的拿到请求结果,需要设置feign客户端的超时控制,yml配置文件中设置

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

openfeign_ribbon

6.3 OpenFeign的日志增强

Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节。说白了就是对Feign接口调用情况的监控和输出

1️⃣ 添加配置文件

@Configuration
public class FeignLevelConfig {

    @Bean
    Logger.Level feignLoggerLevel(){

        return Logger.Level.FULL;
    }
}

2️⃣ 修改yml配置

logging:
  level:
    #feign日志以什么级别监控哪个接口
    com.service.Feign_PaymentService: debug

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值