SpringCloud02:搭建以及基本使用

本文详细介绍了如何使用Spring Cloud搭建微服务架构,包括创建父工程、公共实体、服务提供者(API、Eureka Server、API消费者和负载均衡)、Eureka服务注册与发现,以及Eureka与Zookeeper的比较。重点讲解了Eureka的原理、组件和自我保护机制,以及微服务架构的CAP理论应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、微服务基本搭建

1、创建父工程

  • pom.xml文件
<?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>org.example</groupId>
    <artifactId>springCloud</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>springcloud-api</module>
        <module>springcloud-api-provider-8001</module>
        <module>springcloud-api-consumer-80</module>
        <module>springcloud-eureka-7001</module>
        <module>springcloud-eureka-7002</module>
        <module>springcloud-eureka-7003</module>
        <module>springcloud-api-provider-8002</module>
        <module>springcloud-api-provider-8003</module>
        <module>springcloud-api-consumer-feign</module>
        <module>springcloud-api-provider-hystrix-8001</module>
        <module>springcloud-api-consumer-hystrix-dashboard</module>
        <module>springcloud-zuul-9527</module>
        <module>springcloud-config-server-3344</module>
    </modules>


    <!--打包方式 pom-->
    <packaging>pom</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>4.12</junit.version>
        <lombok.version>1.18.20</lombok.version>
        <log4j.version>1.2.17</log4j.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencyManagement>
        <dependencies>
            <!--SpringCloud的依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--SpringBoot的依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.4.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--数据库-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.49</version>
            </dependency>
            <!--数据源-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.2.1</version>
            </dependency>
            <!--SpringBoot启动器-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
            <!--=========日志相关=============-->
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <!--logback-->
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.2.3</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>


</project>

2、创建公共实体

@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Dept implements Serializable {

    private Long deptNo;
    private String deptName;
    private String dbName;
}
在这里插入代码片

3、服务提供者创建

  • 编写pom,xml
  • 配置application.yml
  • 根据配置新建mybatis-config.xml文件
  • 编写部门dao以及对应的mapper
  • 编写service接口以及实现类
  • 编写controller类提供Rest服务

//提供Restful风格服务
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @PostMapping("dept/add")
    public boolean addDept(Dept dept){
        return deptService.addDept(dept);
    }

    @GetMapping("dept/query/{id}")
    public Dept queryById(@PathVariable("id")Long id){
        Dept dept = deptService.queryById(id);
        if (dept==null){
            throw new RuntimeException("失败了呀!!!");
        }
        return dept;
    }

    @GetMapping("dept/query/all")
    public List<Dept> queryAll(){
        return deptService.queryAll();
    }
    
}
  • 编写启动类
@SpringBootApplication  //启动类
@EnableEurekaClient   //服务启动后主动注册到eureka中心
@EnableDiscoveryClient  //服务发现
public class DeptProviderStarter_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProviderStarter_8001.class,args);
    }

    //增加一个servlet
    @Bean
    public ServletRegistrationBean bean(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        return registrationBean;
    }
}

4、使用Ribbon创建服务消费者

  • Controller类调用接口
@RestController
public class DeptConsumerController {

    @Autowired
    //提供多种便捷访问远程http服务的方法,简单的Restful风格
    private RestTemplate restTemplate;

//    public static final String REST_URL_PREFIX="http://localhost:8001/";

    //ribbon负载均衡下使用服务名调用
    private static final String REST_URL_PREFIX="http://SPRINGCLOUD-PROVIDER-DEPT/";

    @RequestMapping("consumer/dept/query/{id}")
    public Dept query(@PathVariable("id")Long id){
        return restTemplate.getForObject(REST_URL_PREFIX+"dept/query/"+id,Dept.class);
    }

    @RequestMapping("consumer/dept/query/all")
    public List<Dept> queryAll(){
        return restTemplate.getForObject(REST_URL_PREFIX+"dept/query/all",List.class);
    }

    @RequestMapping("consumer/dept/add")
    public Boolean add(Dept dept){
        return restTemplate.postForObject(REST_URL_PREFIX+"dept/add",dept,Boolean.class);
    }

}

二、Eureka服务注册与发现

1、什么是Eureka

  • Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。
  • Netflix 在设计Eureka 时,遵循CPA原则中的AP原则。
  • CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。
    ①、一致性(Consistency)
    ②、可用性(Availability)
    ③、分区容错性(Partition tolerance)

2、原理分析

  • SpringCloud 封装了NetFlix公司开发的Eureka模块来实现服务注册和发现
  • Eureka采用了C-S的架构设计,EurekaServer 作为服务注册功能的服务器,他是服务注册中心
  • 而系统中的其他微服务。使用Eureka的客户端连接到EurekaServer并维持心跳连接。这样系统的维护人员就可以通过EurekaServer来监控系统中各个微服务是否正常运行,SpringCloud的一些其他模块(比如Zuul)就可以通过EurekaServer来发现系统中的其他微服务,并执行相关的逻辑;
    在这里插入图片描述

3、Eureka包含的两个组件

  • Eureka Server 提供服务注册服务,各个节点启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
  • Eureka Client是一个Java客户端,用于简化EurekaServer的交互,客户端同时也具备一个内置的,使用轮询负载算法的负载均衡器。在应用启动后,将会向EurekaServer发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除掉(默认周期为90秒)

4、Eureka服务端构建

  • pox.xml文件
parent>
        <artifactId>springcloud</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>eureka</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <!--导包-->
    <dependencies>
         <!--erueka-server服务端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!--热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
  • application.yml文件
server:
  port: 7001

# Eureka配置
eureka:
  instance:
    hostname: eureka7001.com # eureka服务端的名称
  client:
    register-with-eureka: false  # 表示是否向eureka注册中心注册自己
    fetch-register: false   # false:表示自己为注册中心
    service-url:   #监控页面
      defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/   # 集群配置
  • 启动类
@EnableEurekaServer   //服务端启动类
@SpringBootApplication
public class EurekaServerStarter_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerStarter_7001.class,args);
    }
}

5、Eureka客户端构建

  • pom.xml
 <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--        jetty-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
<!--        eureka服务者-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
<!--        添加监控信息-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
    </dependencies>
  • application.yml
server:
  port: 8001

# mybatis配置
mybatis:
  type-aliases-package: com.lc.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml

# spring配置
spring:
  application:
    name: springcloud-provider-dept   # 三个服务名称一致是
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud?useSSL=true&useUnicode=true&characterEncoding=utf-8
    username: root
    password: admin123


# eureka注册配置,服务注册到那里
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept-8001   #修改eureka上项目的描述信息
    prefer-ip-address: true

# info配置
info:
  app.name: liaochang-springcloud
  company.name: blog.liaochang.com

  • 启动类
@SpringBootApplication  //启动类
@EnableEurekaClient   //服务启动后主动注册到eureka中心
@EnableDiscoveryClient  //服务发现
public class DeptProviderStarter_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProviderStarter_8001.class,args);
    }

    //增加一个servlet
    @Bean
    public ServletRegistrationBean bean(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        return registrationBean;
    }
}

6、Eureka的自我保护机制

  • 默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka之间无法正常通行,以上行为可能变得非常危险了,因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过 自我保护机制 来解决这个问题,当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该EurekaServer节点会自动退出自我保护模式。
  • 在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该EurekaServer节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话:好死不如赖活着。
  • 综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮和稳定。在SpringCloud中,可以使用 eureka.server.enable-self-preservation = false 禁用自我保护模式 【不推荐关闭自我保护机制】。
  • 一句话总结:某时刻某一个微服务不可以用了,eureka不会立刻清理,依旧会对该微服务的信息进行保存。

三、Eureka与Zookeeper的区别

1、CAP理论

  • C(Consistency)一致性
  • A(Availability)可用性
  • P(Partition tolerance)分区容错性
  • CA:单点集群,满足一致性,可用性的系统,通常可扩展性较差。
  • CP:满足一致性,分区容错性的系统,通常性能不是特别高。
  • AP:满足可用性,分区容错性的系统,通常可能对一致性要求低一些。

2、Eureka比Zookeeper好在那里

  • 著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性)、A(可用性)、P(容错性)。
  • 由于分区容错性P在分布式系统中是必须要保证的,因此我们只能在A和C之间进行权衡。

3、Zookeeper保证的是CP

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

4、Eureka保证的是AP

  • Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时,如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保住注册服务的可用性,只不过查到的信息可能不是最新的,除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
    ①、Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
    ②、 Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点依然可用)
    ③、 当网络稳定时,当前实例新的注册信息会被同步到其他节点中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微笑AJJD

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值