SpringCloud 15 —— 注册中心之Consul

Consul 简介

Consul 是 HashiCorp 公司推出的开源产品,用于实现分布式系统的服务发现、服务隔离、服务配置,这些功能中的每一个都可以根据需要单独使用,也可以同时使用所有功能。Consul 官网目前主要推 Consul 在服务网格中的使用。

与其它分布式服务注册与发现的方案相比,Consul 的方案更“一站式”——内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,不再需要依赖其它工具。Consul 本身使用 go 语言开发,具有跨平台、运行高效等特点,也非常方便和 Docker 配合使用。

主要特点

  • Service Discovery: 服务注册与发现,Consul 的客户端可以做为一个服务注册到 Consul,也可以通过 Consul 来查找特定的服务提供者,并且根据提供的信息进行调用。
  • Health Checking: Consul 客户端会定期发送一些健康检查数据和服务端进行通讯,判断客户端的状态、内存使用情况是否正常,用来监控整个集群的状态,防止服务转发到故障的服务上面。
  • KV Store: Consul 还提供了一个容易使用的键值存储。这可以用来保持动态配置,协助服务协调、建立 Leader 选举,以及开发者想构造的其它一些事务。
  • Secure Service Communication: Consul 可以为服务生成分布式的 TLS 证书,以建立相互的 TLS 连接。 可以使用 intentions 定义允许哪些服务进行通信。 可以使用 intentions 轻松管理服务隔离,而不是使用复杂的网络拓扑和静态防火墙规则。
  • Multi Datacenter: Consul 支持开箱即用的多数据中心,这意味着用户不需要担心需要建立额外的抽象层让业务扩展到多个区域。

Consul 角色

  • Server: 服务端, 保存配置信息, 高可用集群, 在局域网内与本地客户端通讯, 通过广域网与其它数据中心通讯。 每个数据中心的 Server 数量推荐为 3 个或是 5 个。
  • Client: 客户端, 无状态, 将 HTTP 和 DNS 接口请求转发给局域网内的服务端集群。

Consul旨在对 DevOps社区和应用程序开发人员友好,使其成为现代、弹性基础架构的理想选择。

Consul 的优势

  • 使用 Raft算法来保证一致性, 比复杂的 Paxos算法更直接。相比较而言, Zookeeper采用的是 Paxos, 而 etcd使用的则是 Raft。
  • 支持多数据中心,内外网的服务采用不同的端口进行监听。多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟, 分片等情况等。 Zookeeper和 etcd均不提供多数据中心功能的支持。
  • 支持健康检查。 etcd不提供此功能。
  • 支持 http和 dns协议接口。 Zookeeper的集成较为复杂, etcd只支持 http 协议。
  • 官方提供 Web管理界面, etcd无此功能。
  • Consul保持了 CAP中的 CP,保持了强一致性和分区容错性。
  • Consul支持 HttpgRPC\DNS多种访问方式。

Consul 和 Eureka的对比

FeatureEuerkaConsul
服务健康检查可配支持服务状态,内存,硬盘等
多数据中心支持
kv 存储服务支持
一致性raft
capapcp
使用接口(多语言能力)http(sidecar)支持 http 和 dns
watch 支持支持 long polling/大部分增量全量/支持long polling
自身监控metricsmetrics
安全acl /https
编程语言Javago
Spring Cloud 集成已支持已支持

Consul 安装

以windows为例,到官网下载安装。添加consul.exe到环境变量。

控制台执行consul agent -dev

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

consul agent -dev运行的开发环境,方便开发者使用,实际生产需要部署3台以上形成集群。

Consul 替换Eureka

我们需要建两个模块,Server和Client,其实也就是Producer和Consumer,通过两个模块我们来演示如何用Consul轻松的替换Eureka。并且模拟Client远程调用 Server端。

Server

新建项目模块register-consul,引入依赖:

    <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>group.group.zhouning</groupId>
            <artifactId>feign-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

添加应用配置:

server:
  port: 8861
spring:
  application:
    name: register-consul-server
  cloud:
    consul:
      host: 127.0.0.1
      port: 8500
      discovery:
        instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}  #实例ID
        health-check-path: /actuator/health                                                       #健康检查
        health-check-interval: 10s

新建启动类:

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

配置对外接口

我们这里对外对外提供两个接口,一种是返回字符串类型的,一种是返回实体类型的。

@RestController
public class HelloWorldController{
    /**
     * 获取字符串信息
     * @return
     */
    @GetMapping("/helloWorld")
    public String HelloWorld() {
        return "Hello World!";
    }

    /**
     * 获取用户信息
     * @return
     */
    @GetMapping("/user")
    public User getUser() {
        return new User(1L,"consul","test","abc@gmail.com","Consul 替换Eureka");
    }
}

新建Client项目

接下来新建项目模块cloud-client-consul,用于演示Feign远程调用。对于Feign 相信已经都了解了。引入maven依赖:

    <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>group.group.zhouning</groupId>
            <artifactId>feign-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
    </dependencies>

应用配置:

server:
  port: 8862
spring:
  application:
    name: register-consul-client
  cloud:
    consul:
      host: 127.0.0.1
      port: 8500
      discovery:
        instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}  #实例ID
        health-check-path: /actuator/health                                                      #健康检查
        health-check-interval: 10s
  main:
    allow-bean-definition-overriding: true #当出现相同名字的类进行注册时,准许覆盖注册

启动类:

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

编写Feign Api:

利用Feign 配置服务的远程调用,调用策略使用Feign 默认的。

@FeignClient(value = "register-consul-server")
public interface ConsulApi {

    /**
     * 获取字符串信息
     * @return
     */
    @GetMapping(&q