SpringCloud-Alibaba之Consul

  • Post author:
  • Post category:其他


此文章主要讲解springcloud中注册中心Eureka替代方案Consul的相关知识。



Eureka闭源的影响



Eureka闭源

image-20210116154229310

  • 在Eureka的GitHub上,宣布Eureka 2.x闭源。这意味着如果开发者继续使用2.x分支上现有工作repo的一部分发布的代码库和组件,则自负风险。



Eureka的替换方案



Zookeeper

  • Zookeeper是一个分布式的,开放源代码的分布式应用程序协调服务,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。



Consul

  • Consul是近几年比较流行的服务发现工具。

  • Consul的三个主要应用场景:服务发现、服务隔离、服务配置。



Nacos

  • Nacos是阿里巴巴推出来的一个新开源项目,这是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos致力于帮助您发现、配置和管理微服务。Nacos提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据以及流量管理。Nacos帮助您更敏捷和容易的构建、交付和管理微服务平台。Nacos是构建以“服务”为中心的现代应用架构(例如微服务范式、云原生范式)的服务基础设施。



Consul简介



概述

  • Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现和配置。和其他分布式服务注册和发现的方案,Consul的方案更“一站式”,内置了服务注册和发现框架、分布式一致性协议实现、健康检查、key/value存储、多数据中心方案,不再需要依赖其他工具(比如Zookeeper等)。使用起来也比较简单。Consul使用Go语言编写,因此具有天然移植性(支持Linux、Windows和Mac OS X),安装包仅包含一个可执行的文件,方便部署,和Docker等轻量级容器可以无缝配合。



Consul的优势

  • 采用Raft算法来保证一致性,比服务的Paxos算法更直接。Zookeeper采用的是Paxos算法,而Consul以及etcd采用的是Raft算法。

  • 支持多数据中心,内外网的服务采用不同的端口进行监听。多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟、分片等情况。Zookeeper和etcd均不提供多数据中心功能的支持。

  • 支持健康检查。etcd不提供此功能。

  • 支持http和dns协议接口。Zookeeper的集成较为复杂,etcd只支持http协议。

  • 官方提供web管理界面。etcd无此功能。



Consul的特性

  • 服务发现。

  • 健康检查。

  • key/value存储。

  • 多数据中心。



Consul和Eureka的区别



一致性


  • Consul:强一致性(CP):

  • 服务注册相比Eureka会稍慢一些。因为Consul的Raft协议要求必须过半的节点都写入成功才认为注册成功。

  • Leader挂掉后,重新选举期间整个Consul不可用。保证了强一致性,但牺牲了可用性。


  • Eureka:高可用性和最终一致性(AP):

  • 服务注册相对要快,因为不需要等注册信息复制到其他节点,也不保证注册信息是否复制成功。

  • 当数据出现不一致的时候,虽然A,B上的注册信息不完全相同,但是每个Eureka节点依然能够正常对外提供服务,这会出现查询服务信息时如果请求A查不到,但请求B就能查到。如果保证了可用性但牺牲了一致性。



开发语言和使用

  • Eureka是Servlet程序,跑在Servlet容器中。

  • Consul是Go语言编写而言的,安装启动即可。



官网

官网地址: https://www.consul.io/intro

中文地址: https://www.springcloud.cc/spring-cloud-consul.html

consul也是服务注册中心的一个实现,是由go语言写的。


功能:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yyFgtomg-1621990916785)(D:/学习重要文件/B站尚硅谷教程/SpringCloud Alibaba/springcloud alibaba 周阳/images/1597380885054.png)]



Consul的下载和安装



官网下载

Consul不同于Eureka需要单独安装,访问

官网

可以下载Consul的最新版本,目前使用的是Consul 1.8.3。根据不同的操作系统类型选择不同的安装包,Consul支持所有主流操作系统。

image-20210116155245194



官网安装说明

官方视频安装教程:https://learn.hashicorp.com/tutorials/consul/get-started-install



Windows系统安装

下载地址:https://www.consul.io/downloads.html

下载解压后,只有一个exe文件,实际上是不用安装的,在exe文件所在目录打开dos窗口使用即可。

使用开发模式启动:

consul agent -dev

image-20210116160046717

到浏览器去访问:http://localhost:8500

这样就安装配置完成了。



Linux系统安装



下载Consul

# 从官网下载consul
wget https://releases.hashicorp.com/consul/1.8.4/consul_1.8.4_linux_amd64.zip
# 使用unzip命令解压
unzip consul_1.8.4_linux_amd64.zip
# 将解压好的consul可执行命令赋值到/usr/local/bin目录下
cp consul /usr/local/bin
# 测试一下
consul



启动Consul

# 以开发者模式快速启动,-client指定客户端可以访问的IP地址
consul agent -dev -client=0.0.0.0

启动之后,自测访问 http://localhost:8500 即可以看到Consul的管理界面



docker安装consul

可以使用容器技术docker安装,拉取镜像,具体自行查询百度,网上教程很多。



Consul的基本使用

Consul支持健康检查,并提供了HTTP和DNS调用的

API接口

来完成服务的注册,服务发现以及KV存储这些功能。

例如在VMWare中的Linux的IP地址是192.168.32.100。



服务注册和发现



注册服务

通过postman发送PUT请求到 http://192.168.32.100:8500/v1/catalog/register 地址可以完成服务注册。

{
    "Datacenter": "dc1",
    "Node": "node01",
    "Address": "192.168.1.57",
    "Service": {
        "ID": "mysql-01",
        "Service": "mysql",
        "tags": [
            "master",
            "v1"
        ],
        "Address": "192.168.1.57",
        "Port": 3306
    }
}

image-20210116163233243



服务查询

通过postman发送GET请求到 http://192.168.32.100:8500/v1/catalog/services 地址获取所有的服务列表。

image-20210116163328695

通过postman发送GET请求到 http://192.168.32.100:8500/v1/catalog/service/mysql 获取具体的服务。



服务删除

通过postman发送PUT请求到 http://192.168.32.100:8500/v1/catalog/deregister 删除服务。

image-20210116163741138



Consul的KV存储

  • 可以参照Consul提供的KV存储的

    API

    完成基于Consul的数据存储。
含义 请求路径 请求方式
查看key v1/kv/:key GET
保存或更新 v1/kv/:key put
删除 /v1/kv/:key DELETE
  • key值中可以带/,可以看做是不同的目录结构。

  • value的值经过了base64编码,获取到数据后需要经过base64解码才能获取到原始值。数据不能大于521kb。

  • 不同的数据中心的kv存储系统是独立的,使用dc=?参数指定。



工程搭建



提供者



新建模块

cloud-providerconsul-payment8006



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">
    <parent>
        <artifactId>spring_cloud_atguigu_2020</artifactId>
        <groupId>com.itjing.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-providerconsul-payment8006</artifactId>

    <dependencies>
        <!--springcloud consul server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        <!-- 引入自己定义的api通用包-->
        <dependency>
            <groupId>com.itjing.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</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-actuator</artifactId>
        </dependency>
        <!--mybatis整合spring依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

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



YML文件

# 端口号
server:
  port: 8006
spring:
  application:
    name: cloud-payment-service
  # 数据源
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:    # 指定注册对外暴露的服务名称
        service-name: ${spring.application.name}



主启动类

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



Controller

@RestController
@Slf4j
public class PaymentController {
    @Value("${server.port}")
    private String serverPort;

    @RequestMapping("/payment/consul")
    public String paymentConsul() {
        return "springcloud with consul: " + serverPort + "\t" + UUID.randomUUID().toString();
    }
}



验证测试

首先保证 consul 是启动的,再启动 8006

访问 http://localhost:8500 查看,注册成功!

image-20210116162553403



消费者



新建模块

cloud-consumerconsul-order80



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">
    <parent>
        <artifactId>spring_cloud_atguigu_2020</artifactId>
        <groupId>com.itjing.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumerconsul-order80</artifactId>

    <dependencies>

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

        <!-- 引入自己定义的api通用包-->
        <dependency>
            <groupId>com.itjing.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</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-actuator</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>



YML文件

server:
  port: 80

spring:
  application:
    name: cloud-consumer-order
  # consul 注册中心地址
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:    # 指定注册对外暴露的服务名称
        service-name: ${spring.application.name}



主启动类

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



配置类

@Configuration
public class ApplicationContextConfig {

    @Bean
    @LoadBalanced  //这个注解,就赋予了RestTemplate 负载均衡的能力
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}



Controller

@RestController
@Slf4j
public class OrderConsulController {
    public static final String INVOKE_URL = "http://cloud-payment-service";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/payment/consul")
    public String paymentInfo() {
        String result = restTemplate.getForObject(INVOKE_URL + "/payment/consul", String.class);
        return result;
    }
}



验证测试

  1. 启动 consul
  2. 启动提供者 8006
  3. 启动消费者 80
  4. 访问测试

访问 http://localhost:8500 ,可以看到消费者成功注册进来。

image-20210116165709812

消费者访问 http://localhost/consumer/payment/consul,测试成功!

image-20210116165905590



总结



三个注册中心的异同点

组件名 语言 CAP 服务健康检查 对外暴露接口 Spring Cloud 集成
Eureka Java AP 可配支持 HTTP 已集成
Consul Go CP 支持 HTTP/DNS 已集成
Zookeeper Java CP 支持 客户端 已集成

1597384344513

image-20210116170646441

1597384362750


AP:

1597384508291

当网络分区出现后,为了保证可用性,系统B

可以返回旧值

,保证系统的可用性。


结论:违背了一致性C的要求,只满足可用性和分区容错,即AP


CP:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wxabxfJd-1621990916813)(D:/学习重要文件/B站尚硅谷教程/SpringCloud Alibaba/springcloud alibaba 周阳/images/1597384554249.png)]

当网络分区出现后,为了保证一致性,就必须拒接请求,否则无法保证一致性


结论:违背了可用性A的要求,只满足一致性和分区容错,即CP



Consul搭建集群

详情见文章:https://www.yuque.com/sunxiaping/yg511q/ruo5uv#904e5ea1



版权声明:本文为qq_43144261原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。