Spring Cloud(六):服务注册中心Consul

Posted by Kaka Blog on October 13, 2018

为什么使用Consul

6月,知名服务注册与服务发现工具 Eureka 的 GitHub Wiki 上显示其 2.0 版本的开源工作已经停止。这意味着如果开发者继续使用作为 2.x 分支上现有工作 repo 一部分发布的代码库和工件,则将自负风险。对此,专家建议开发者尽快将相关业务迁移到 Consul/ZooKeeper/Etcd 等工具上。

对比

Feature euerka Consul zookeeper etcd
服务健康检查 可配支持 服务状态,内存,硬盘等 (弱)长连接,keepalive 连接心跳
多数据中心 支持
kv 存储服务 支持 支持 支持
一致性 raft paxos raft
cap ap ca cp cp
使用接口(多语言能力) http(sidecar) 支持 http 和 dns 客户端 http/grpc
watch 支持 支持 long polling/大部分增量 全量/支持long polling 支持 支持 long polling
自身监控 metrics metrics metrics
安全 acl /https acl https 支持(弱)
spring cloud 集成 已支持 已支持 已支持 已支持

Consul介绍

Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。

功能

  • 服务发现:Consul client 可以提供服务,例如api或mysql,也可以使用Consul client来发现指定服务的提供者。 使用DNS或HTTP,应用程序可以轻松找到他们所依赖的服务。
  • 健康检查:Consul client 可以提供任何数量的健康检查,或者与给定的服务(“Web服务器是否返回200 OK”),或与本地节点(“内存利用率是否低于90%”)相关联。 可以使用此信息来监控集群运行状况,服务发现组件使用此信息将流量从有问题的主机中移除出去。
  • KV Store:应用程序可以使用Consul的分层键/值存储,包括动态配置,功能标记,协调,leader选举等等。 简单的HTTP API使其易于使用。
  • 多数据中心:Consul支持多个数据中心。 这意味着Consul的用户不必担心构建额外的抽象层以扩展到多个区域。

角色

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

img

工作原理

img

  • 1、当 Producer 启动的时候,会向 Consul 发送一个 post 请求,告诉 Consul 自己的 IP 和 Port
  • 2、Consul 接收到 Producer 的注册后,每隔10s(默认)会向 Producer 发送一个健康检查的请求,检验Producer是否健康
  • 3、当 Consumer 发送 GET 方式请求 /api/address 到 Producer 时,会先从 Consul 中拿到一个存储服务 IP 和 Port 的临时表,从表中拿到 Producer 的 IP 和 Port 后再发送 GET 方式请求 /api/address
  • 4、该临时表每隔10s会更新,只包含有通过了健康检查的 Producer

简单入门

1、安装Consul

Consul官方网站下载Consul最新版本,这里下载的是Windows版1.3.0

进入Consul.exe当前目录,使用cmd启动Consul:

consul agent -dev # -dev表示开发模式运行,另外还有-server表示服务模式运行

启动成功后访问:http://localhost:8500,可以看到 Consul 的管理界面: img

2、开发服务提供者

创建一个 spring-cloud-consul-producer 项目。

  • Spring Boot版本:2.0.3.RELEASE
  • Spring Cloud版本:Finchley.RELEASE

1、添加依赖包,pom.xml文件如下:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</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>Finchley.RELEASE</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>

2、修改配置文件,application.properties文件如下:

spring.application.name=spring-cloud-consul-producer
server.port=8501
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
#注册到consul的服务名称

spring.cloud.consul.discovery.service-name=service-producer

3、启动类

@SpringBootApplication
@EnableDiscoveryClient
public class Application {

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

@EnableDiscoveryClient 注解表示支持服务发现

4、创建服务

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello() {
        return "helle world!";
    }
}

启动成功后,访问http://localhost:8500可以看到添加了一个服务。

3、开发服务消费者

创建一个 spring-cloud-consul-consumer 项目,使用两种方式调用服务。

1、添加依赖包,pom.xml文件如下:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</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>Finchley.RELEASE</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>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</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>

2、修改配置文件,application.properties文件如下:

spring.application.name=spring-cloud-consul-consumer
server.port=8503
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
spring.cloud.consul.discovery.register=false

3、启动类

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

添加@EnableFeignClients 注解为了提供另外一种调用方式

4、创建服务

@RestController
public class HelloController {
    @Autowired
    private LoadBalancerClient loadBalancerClient;
    @Autowired
    private HelloRemote helloRemote;

    @RequestMapping("/call")
    public String call() {
        ServiceInstance service = loadBalancerClient.choose("producer-service");
        System.out.println("服务地址:" + service.getUri());
        System.out.println("服务名称:" + service.getServiceId());
        String result = new RestTemplate().getForObject(service.getUri().toString() + "/hello", String.class);
        return result;
    }

    @RequestMapping("/call2")
    public  String call2() {
        return helloRemote.hello2();
    }
}
  • call方法采用LoadBalancerClient获取获取和RestTemplate调用服务
  • call2采用Feign调用服务,需添加接口:
    @FeignClient(name = "producer-service")
    public interface HelloRemote {
      @RequestMapping("/hello")
      public String hello2();
    }
    

4、测试

分别访问http://localhost:8503/callhttp://localhost:8503/call2,正常的话都能返回hello world!

总结

Consul使用起来比Eureka方便,不需要写服务注册中心,而且UI比较简洁。部署多个服务提供者就可以实现负载均衡。

参考

Consul官方网站

springcloud(十三):注册中心 Consul 使用详解

Eureka 2.0 开源工作宣告停止,继续使用风险自负

Consul 介绍