Spring Cloud框架学习-Spring Cloud Consul

导读:本篇文章讲解 Spring Cloud框架学习-Spring Cloud Consul,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

1. 简介

Consul 是 HashiCorp 公司推出来的开源产品。主要提供了:服务发现、服务隔离、服务配置等功能。相比于 其他注册中心组件Eureka 和Zookeeper,Consul 配置更加一站式,因为它内置了很多微服务常见的功能:服务发现与注册、分布式一致性协议实现、健康检查、键值对存储、多数据中心等,我们不再需要借助第三方组件来实现这些功能。

Spring Cloud Consul 具有如下特性:

  • 支持服务治理:Consul作为注册中心时,微服务中的应用可以向Consul注册自己,并且可以从Consul获取其他应用信息
  • 支持客户端负载均衡:提供Ribbon和Spring Cloud LoadBalancer实现负载均衡
  • 支持Zuul:当Zuul作为网关时,可以从Consul中注册和发现应用
  • 支持分布式配置管理:Consul作为配置中心时,使用键值对来存储配置信息
  • 支持控制总线:可以在整个微服务系统中通过 Control Bus 分发事件消息

Spring Cloud Consul 中文文档:https://www.springcloud.cc/spring-cloud-consul.html

2. 安装

不同于 Eureka ,Consul 使用 Go 语言开发,所以我们需要先安装Consul 。

2.1 Windows环境安装

从官网直接下载软件,官网下载地址:https://www.consul.io/downloads.html。下载完成后只有一个exe文件,首先双击运行该文件;

在命令行中输入以下命令可以查看版本号:

consul --version

然后使用开发模式启动:

consul agent -dev

在这里插入图片描述

浏览器访问 http://localhost:8500 ,进入Consul首页。
在这里插入图片描述

2.2 Linux环境安装

在 Linux 中,首先执行如下命令下载 Consul:

wget https://releases.hashicorp.com/consul/1.6.2/consul_1.6.2_linux_amd64.zip

下载完成后解压压缩包

unzip consul_1.6.2_linux_amd64.zip

在这里插入图片描述
解压完成后,我们可以看到consul文件,然后执行以下命令启动consul:

./consul agent -dev -ui -node=consul-dev -client=192.168.91.128

参数说明:

  • -dev: 表示开发模式启动;
  • -ui:表示显示管理界面的web-ui;
  • -node:表示节点在 web-ui界面上显示的名称;
  • -client:指定客户端访问的ip,0.0.0.0表示所有客户端都可访问;

其他参数:

  • -bootstrap-expect:表示server集群中最少的节点个数,低于这个值集群就不会工作(原理类似于Zookeeper,通常集群中的节点个数为奇数,方便进行选举,consul采用的是 raft算法);
  • -data-dir:表示指定数据的存放目录(目录必须存在);
  • -bind:表示绑定到哪个IP地址(有些服务器可能有多块网卡,需要进行配置);

注意:192.168.91.128应该为内网ip。还要确保8500端口可用
启动成功后,浏览器请求http://101.43.30.7:8500/ui/dc1/services,访问consul管理后台
在这里插入图片描述

集群部署Consul的相关命令:
./consul members:查看集群信息
./consul join consul服务IP:添加节点
./consul info:查看节点的具体信息

3. 使用

3.1 服务提供者

创建Spring Boot项目,作为服务提供者,添加以下依赖:

在这里插入图片描述


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

成功创建项目后,application.properties添加如下配置:

spring.application.name=consul-provider
server.port=2000
#consul的主机地址
spring.cloud.consul.host=101.43.30.7
#conusl的端口
spring.cloud.consul.port=8500
#服务的名称
spring.cloud.consul.discovery.service-name=consul-provider
spring.cloud.consul.discovery.heartbeat.enabled=true

在启动类上开启服务发现的功能:

@SpringBootApplication
//开启服务发现功能
@EnableDiscoveryClient
public class ConsulProviderApplication {

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

}

启动项目,访问consul管理后台界面,可以看到已经注册成功。
在这里插入图片描述
(如果服务总是报红叉,则需要在application.yml配置文件中增加spring.cloud.consul.discovery.heartbeat.enabled=true,打开Consul的心跳机制)

创建HelloController添加接口/hello

@RestController
public class HelloController {

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

  @GetMapping("/hello")
  public String hello(){
    return "hello" + port;
  }
}

对项目进行打包,命令行启动多一个provider实例:

java -jar consul-provider-0.0.1-SNAPSHOT.jar --server.port=6000

consul管理后台可以看到有两个provider实例
在这里插入图片描述

3.2 服务消费者

创建Spring Boot项目consul-consumer,作为服务消费者,添加以下依赖:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

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

成功创建项目后,application.properties添加如下配置:

spring.application.name=consul-consumer
server.port=2002
#consul的主机地址
spring.cloud.consul.host=101.43.30.7
#conusl的端口
spring.cloud.consul.port=8500
#服务的名称
spring.cloud.consul.discovery.service-name=consul-consumer

在启动类上开启服务发现的功能,并注入RestTemplate:

@SpringBootApplication
@EnableDiscoveryClient
public class ConsulConsumerApplication {

    public static void main(String[] args) {


        SpringApplication.run(ConsulConsumerApplication.class, args);
    }

    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

测试服务调用

@RestController
public class HelloController {
    @Autowired
    LoadBalancerClient loadBalancerClient;

    @Autowired
    RestTemplate restTemplate;

    @GetMapping("/hello")
    public void hello() {
        ServiceInstance choose = loadBalancerClient.choose("consul-provider");
        System.out.println("服务地址:" + choose.getUri());
        System.out.println("服务名称:" + choose.getServiceId());
        String s = restTemplate.getForObject(choose.getUri() + "/hello",
                String.class);
        System.out.println(s);
    }
}

这里通过loadBalancerClient获取要调用的ServiceInstance,获取到调用地址之后再使用RestTemplate去调用。浏览器请求http://localhost:2002/hello ,查看控制台的请求结果。
在这里插入图片描述

3.3 配置中心

我们还可以在consul中实现服务的统一配置,创建Maven模块consul-config,在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">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>top.javahai</groupId>
    <artifactId>consul-config</artifactId>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR6</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

添加配置文件application.yml,配置启用dev环境:

spring:
  profiles:
    active: dev

添加配置文件bootstrap.yml,对Consul的配置功能进行配置:

server:
  port: 9101
spring:
  application:
    name: consul-config
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        serviceName: consul-config
        #打开心跳机制
        heartbeat:
          enabled: true
      config:
        #是否启用配置中心功能
        enabled: true
        #设置配置值的格式
        format: yaml
        #设置配置所在目录
        prefix: config
        #设置配置的分隔符
        profile-separator: ':'
        #配置key的名字,由于Consul是K/V存储,配置存储在对应K的V中
        data-key: data

创建ConfigController,提供接口/configInfo,从Consul配置中心中获取配置信息.使用@RefreshScope注解实现动态加载配置文件。

@RefreshScope刷新机制原理

@RestController
@RefreshScope
public class ConfigController {


    @Value("${config.info:}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo() {
        return configInfo;
    }
}

在Consul后台添加如下配置:
添加配置存储的key为:

config/consul-config:dev/data

添加配置存储的value为:

config:
  info:"config info onsul-config for dev"

在这里插入图片描述
启动项目调用/configinfo接口查看配置信息。

我们修改Consul中的配置信息,再次调用查看配置的接口,就会发现配置也刷新了。这是因为Consul使用其自带的Control Bus 实现了一种事件传递机制,从而实现了动态配置刷新功能。

4. Consul的CAP理论运用

4.1 CAP理论

CAP理论是分布式架构中重要理论。C(Consistency)一致性、A(Availablity)可用性、P(Partition Tolerance)分区容错性。分布式系统不可能同时满足三个特性,最多只能满足其中两个特性。根据实际情况选择不同的特性组合对应的技术栈。

  • 一致性:对于客户端的每次读操作,要么读到的是最新的数据,要么读取失败。换句话说,一致性是站在分布式系统的角度,对访问本系统的客户端的一种承诺:要么我给您返回一个错误,要么我给你返回绝对一致的最新数据,不难看出,其强调的是数据正确。

  • 可用性:任何客户端的请求都能得到响应数据,不会出现响应错误。换句话说,可用性是站在分布式系统的角度,对访问本系统的客户的另一种承诺:我一定会给您返回数据,不会给你返回错误,但不保证数据最新,强调的是响应不出现错误。

  • 分区容忍性:由于分布式系统通过网络进行通信,网络是不可靠的。当任意数量的消息丢失或延迟到达时,系统仍会继续提供服务,不会挂掉。换句话说,分区容忍性是站在分布式系统的角度,对访问本系统的客户端的再一种承诺:我会一直运行,不管我的内部出现何种数据同步问题,强调的是不挂掉。

而CAP 在分布式系统不可能同时满足,只能取其中2个原因是 如果C是第一需求的话,那么会影响A的性能,因为要数据同步,不然请求结果会有差异,但是数据同步会消耗时间,期间可用性就会降低。如果A是第一需求,那么只要有一个服务在,就能正常接受请求,但是返回结果的正确性便不能保证,原因是在分布式部署的时候,节点间的数据同步的过程需要一定的时间。再如果,同时满足一致性和可用性,那么分区容错性就很难保证了。对于数据没有同步的节点,只能暂停接收请求,这就违背了分区容错性。

4.2 Consul的运用

Consul 遵循CAP原理中的CP原则,保证了强一致性和分区容错性,且使用的是Raft算法,比Zookeeper使用的Paxos算法更加简单。虽然保证了强一致性,但是可用性就相应下降了,例如服务注册的时间会稍长一些,因为 Consul 的 raft 协议要求必须过半数的节点都写入成功才认为注册成功 ;在leader挂掉了之后,重新选举出leader之前会导致Consul 服务不可用。Consul 保证了强一致性但牺牲了可用性。

4.3 注册中心的对比

Eureka:主要支持的是AP,强调高可用和分区容错;
Consul和Zookeeper:主要支持CP,强调数据一致性和分区容错。
在这里插入图片描述
Eureka拥有一个自我保护机制,当在90s内如果有过多的心跳包丢失,Eureka不会直接注销该服务,而是选择采用保护机制不去注销服务,等到90s到期如果仍然不能接受心跳包就直接注销,这种为了保证最大吞吐量而牺牲数据一致性的思想就是AP;

Zookeeper采用创建临时节点的机制来注册服务,由于是临时节点在连接断开时就会立刻被删除,对应着服务就被注销,这种思想对应的就是CP;

Consul在微服务器断开时会立刻停止服务,必须过半数的节点都写入成功才认为注册成功 ;在leader挂掉了之后,重新选举出leader之前会导致Consul 服务不可用的方式,来保证数据一致性原则。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/44270.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!