Consul 多数据中心下的服务注册发现与配置共享
阅读原文时间:2021年05月30日阅读:1

1. Consul简介

  Consul是HashiCorp公司推出的开源软件,它提供了一套分布式高可用可横向扩展的解决方案,能为微服务提供服务治理、健康检查、配置共享等能力。

  Eurake2.x停止更新后,Spirng Cloud官网也推荐使用Consul实现服务注册与发现。并且可以代替Sping Cloud Config实现配置中心。

  官网:https://www.consul.io/

2. 功能特点

  • 服务发现

      提供服务注册和服务发现的功能,通过DNS和Http获取服务信息。

  • 健康检查

      通过健康检查可以避免请求被路由到不健康的服务,并且主动断开使其不再具备服务能力。

  • 键值存储

      提供动态配置功能,通过长轮询实现配置变更的即时通知。

  • 多数据中心

      通过简单配置即可实现多数据中心,并且可以获得其他数据中心的服务。

  • UI界面

      通过界面即可获取服务信息、配置信息等其他信息。

3. CAP原则

  CAP原则指的是在分布式系统中Consistency(一致性)、Availability(可用性)、Partition Tolerance(分区容错性)总是不能同时成立。

  一致性:它要求在任一时刻点分布式系统中的所有数据都处于同一状态。

  可用性:在系统集群的一部分节点宕机后,系统依然能够响应用户的请求。

  分区容错性:在网络区间通信出现异常系统能容错处理。

  一般来说,网络总是存在不稳定性,分区容错也总是存在的,所以默认CAP中的P总是成立的。

  一致性要求在任一时刻数据状态一致,必然需要加锁,因此不能保证可用性,反之同理。因此一致性和可用性总是互斥的。

4. 常见服务发现与注册方案对比

功能

Eureka

Consul

Zookeeper

Nacos

CAP

AP

CP

CP

CP+AP

一致性算法

Raft

Paxos

Raft

访问协议

Http

Http/DNS

TCP

Http/DNS

健康检查

可配支持

支持

支持

支持

多数据中心

x

支持

x

支持

键值存储

支持

支持

支持

支持

雪崩保护

支持

x

x

支持

自动注销实例

支持

x

支持

支持

监听支持

支持

支持

支持

支持

安全性

x

ACL/Https

ACL

ACL/Https

SpringCloud集成

支持

支持

支持

支持

Dubbo集成

x

x

支持

支持

K8S集成

x

支持

x

支持

  Consul采用Raft算法来保证数据的强一致性,虽然优势明显,但是也牺牲了一些特性:

  (1) 服务注册比Eureka慢。因为Consul要求必须节点数过半才认为注册成功;

  (2) Leader挂掉后,在重新选举期间,Consul将不可用,为了一致性牺牲可用性。

5. Consul架构

  图中有两个数据中心:DATACENTER1、DATACENTER2,每个数据中心都有3个Server节点,该数量使得在故障转移和性能之间达到平衡。

6. Consul端口说明

端口

说明

TCP/8300

用于服务器节点。客户端通过该端口 RPC 协议调用服务端节点。

TCP/UDP/8301

用于单个数据中心所有节点之间的互相通信,即对 LAN 池信息的同步。它使得整个数据中心能够自动发现服务器地址,分布式检测节点故障,事件广播(如Leader选举事件)。

TCP/UDP/8302

用于单个或多个数据中心之间的服务器节点的信息同步,即对 WAN 池信息的同步。它针对互联网的网络高延迟进行了优化,能够实现跨数据中心请求。

8500

基于 HTTP 协议,用于 API 接口或 WEB UI 访问。

8600

作为 DNS 服务器,通过节点名查询节点信息。

7. Spring Cloud Consul实现服务注册发现

创建生产者1:

  • 创建Maven项目

  • 修改pom.xml

    http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <artifactId>spring-cloud-consul-producer1</artifactId>
    <name>spring-cloud-consul-producer1</name>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR5</spring-cloud.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </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>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

  • 创建Controller

    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    /**

    }

  • 创建启动类

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

    /**

    }

  • 创建application.yml

    server:
    port: 9001

    spring:
    application:
    name: spring-cloud-consul-producer
    cloud:
    consul:
    discovery:
    serviceName: consul-producer
    host: 127.0.0.1
    port: 8500

创建生产者2:

  • 创建Maven项目

  • 修改pom.xml

    http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <artifactId>spring-cloud-consul-producer2</artifactId>
    <name>spring-cloud-consul-producer2</name>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR5</spring-cloud.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </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>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

  • 创建Controller

    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    /**

    }

  • 创建启动类

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.SpringCloudApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

    /**

    }

  • 创建application.yml

    server:
    port: 9002

    spring:
    application:
    name: spring-cloud-consul-producer
    cloud:
    consul:
    discovery:
    serviceName: consul-producer
    host: 127.0.0.1
    port: 8500

创建消费者:

  • 创建Maven项目

  • 修改pom.xml

    http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <artifactId>spring-cloud-consul-consumer</artifactId>
    <name>spring-cloud-consul-consumer</name>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR5</spring-cloud.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </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>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

  • 创建Controller

    import java.util.List;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.client.discovery.DiscoveryClient;
    import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;

    /**

    • 服务Controller
      *

    • @author CL
      *
      */
      @RestController
      public class ServicesController {

      @Autowired
      private DiscoveryClient discoveryClient;

      @Autowired
      private LoadBalancerClient loadBalancerClient;

      /**

      • 获得所以服务列表
        *
      • @return
        */
        @RequestMapping(value = "/getAllServices")
        public List getAllServices() {
        return discoveryClient.getInstances("consul-producer");
        }

      /**

      • 获取服务Uri
        *
      • @return
        */
        @RequestMapping("/getServiceUri")
        public String getServiceUri() {
        return loadBalancerClient.choose("consul-producer").getUri().toString();
        }

      /**

      • 负载均衡调用提供者接口
        *
      • @return
        */
        @RequestMapping("/loadBalancer")
        public String call() {
        ServiceInstance serviceInstance = loadBalancerClient.choose("consul-producer");
        return new RestTemplate().getForObject(serviceInstance.getUri().toString() + "/get", String.class);
        }
        }
  • 创建启动类

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;

    /**

    • 启动类
      *

    • @author CL
      *
      */
      @SpringBootApplication
      public class ConsulConsumerApplication {

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

    }

  • 创建application.yml

    server:
    port: 9003

    spring:
    application:
    name: spring-cloud-consul-consumer
    cloud:
    consul:
    discovery:
    register: false
    host: 127.0.0.1
    port: 8500

部署Consul:

  Consul安装部署(Windows单机、Docker集群)

启动项目:

  启动顺序:生产者1 -> 生产者2 -> 消费者

  访问Consul WEB UI:http://127.0.0.1:8500

测试:

  • 获取全部服务信息

    curl http://localhost:9003/getAllServices

    #返回:

    [
    {
    "instanceId": "spring-cloud-consul-producer-9001",
    "serviceId": "consul-producer",
    "host": "192.168.0.100",
    "port": 9001,
    "secure": false,
    "metadata": {
    "secure": "false"
    },
    "uri": "http://192.168.0.100:9001",
    "scheme": null
    },
    {
    "instanceId": "spring-cloud-consul-producer-9002",
    "serviceId": "consul-producer",
    "host": "192.168.0.100",
    "port": 9002,
    "secure": false,
    "metadata": {
    "secure": "false"
    },
    "uri": "http://192.168.0.100:9002",
    "scheme": null
    }
    ]

  • 获取服务Uri(负载均衡)

    #第一次调用:
    curl http://localhost:9003/getServiceUri

    #返回:

    http://192.168.0.100:9001

    #第二次调用:
    curl http://localhost:9003/getServiceUri

    #返回:

    http://192.168.0.100:9002

  • 调用提供者接口(负载均衡)

    #第一次调用:
    curl http://localhost:9003/loadBalancer

    #返回:

    Consul-1

    #第二次调用:
    curl http://localhost:9003/loadBalancer

    #返回:

    Consul-2

8. Spring Cloud Consul实配置中心

  • 创建Maven项目

  • 修改pom.xml

    http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <artifactId>spring-cloud-consul-config</artifactId>
    <name>spring-cloud-consul-config</name>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR5</spring-cloud.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-config</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-test</artifactId>
            <scope>test</scope>
        </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>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

  • 创建application.yml

    server:
    port: 9004

  • 创建bootstrap.yml

      作为配置中心的相关配置必须写到bootstrap.yml

    spring:
    application:
    name: spring-cloud-consul-config
    cloud:
    consul:
    discovery:
    service-name: consul-config
    host: 127.0.0.1
    port: 8500
    config:
    # 是否启用配置中心功能
    enabled: true
    # 设置配置所在目录
    prefix: config
    # 设置应用程序使用的文件夹名称,默认application
    defaultContext: application
    # 配置key的名字,由于Consul是K/V存储,配置存储在对应K的V中,配置文件路径为:/config/application/key
    data-key: data
    # 设置配置值的格式,四种配置:YAML PROPERTIES KEY-VALUE FILES
    format: YAML
    # 设置配置的分隔符
    profile-separator: ','

  • 创建Controller

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    /**

    }

  • 创建启动类

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

    /**

    }

  • 创建配置

      在Consul WEB UI的Key/Value下创建配置:

  • 启动项目

  • 查看Consul WEB UI

  • 测试

    curl http://localhost:9004/getInfo

    #返回:

    spring-cloud-consul-demo

9. 项目地址

  spring-cloud-consul-demo