Spring Cloud Consul 之Greenwich版本全攻略

30次阅读

共计 10179 个字符,预计需要花费 26 分钟才能阅读完成。

转载请标明出处:http://blog.csdn.net/forezp/a… 本文出自方志朋的博客

什么是 Consul
Consul 是 HashiCorp 公司推出的开源软件,使用 GO 语言编写,提供了分布式系统的服务注册和发现、配置等功能,这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格。Consul 不仅具有服务治理的功能,而且使用分布式一致协议 RAFT 算法实现,有多数据中心的高可用方案,并且很容易和 Spring Cloud 等微服务框架集成,使用起来非常的简单,具有简单、易用、可插排等特点。使用简而言之,Consul 提供了一种完整的服务网格解决方案。
Consul 具有以下的特点和功能

服务发现:Consul 的客户端可以向 Consul 注册服务,例如 api 服务或者 mysql 服务,其他客户端可以使用 Consul 来发现服务的提供者。Consul 支持使用 DNS 或 HTTP 来注册和发现服务。
运行时健康检查:Consul 客户端可以提供任意数量的运行状况检查机制,这些检查机制可以是给定服务(“是 Web 服务器返回 200 OK”)或本地节点(“内存利用率低于 90%”)相关联。这些信息可以用来监控群集的运行状况,服务发现组件可以使用这些监控信息来路由流量,可以使流量远离不健康的服务。
KV 存储:应用程序可以将 Consul 的键 / 值存储用于任何需求,包括动态配置,功能标记,协调,领导者选举等。它采用 HTTP API 使其易于使用。
安全服务通信:Consul 可以为服务生成和分发 TLS 证书,以建立相互的 TLS 连接。
多数据中心:Consul 支持多个数据中心。这意味着 Consul 的用户不必担心构建额外的抽象层以扩展到多个区域。

Consul 原理
每个提供服务的节点都运行了 Consul 的代理,运行代理不需要服务发现和获取配置的 KV 键值对,代理只负责监控检查。代理节点可以和一个或者多个 Consul server 通讯。Consul 服务器是存储和复制数据的地方。服务器本身选出了领导者。虽然 Consul 可以在一台服务器上运行,但建议使用 3 到 5,以避免导致数据丢失的故障情况。建议为每个数据中心使用一组 Consul 服务器。如果你的组件需要发现服务,可以查询任何 Consul Server 或任何 Consul 客户端,Consul 客户端会自动将查询转发给 Consul Server。需要发现其他服务或节点的基础架构组件可以查询任何 Consul 服务器或任何 Consul 代理。代理会自动将查询转发给服务器。每个数据中心都运行 Consul 服务器集群。发生跨数据中心服务发现或配置请求时,本地 Consul 服务器会将请求转发到远程数据中心并返回结果。
术语

Agent agent 是一直运行在 Consul 集群中每个成员上的守护进程。通过运行 consul agent 来启动。agent 可以运行在 client 或者 server 模式。指定节点作为 client 或者 server 是非常简单的,除非有其他 agent 实例。所有的 agent 都能运行 DNS 或者 HTTP 接口,并负责运行时检查和保持服务同步。
Client 一个 Client 是一个转发所有 RPC 到 server 的代理。这个 client 是相对无状态的。client 唯一执行的后台活动是加入 LAN gossip 池。这有一个最低的资源开销并且仅消耗少量的网络带宽。
Server 一个 server 是一个有一组扩展功能的代理,这些功能包括参与 Raft 选举,维护集群状态,响应 RPC 查询,与其他数据中心交互 WAN gossip 和转发查询给 leader 或者远程数据中心。
DataCenter 虽然数据中心的定义是显而易见的,但是有一些细微的细节必须考虑。例如,在 EC2 中,多个可用区域被认为组成一个数据中心?我们定义数据中心为一个私有的,低延迟和高带宽的一个网络环境。这不包括访问公共网络,但是对于我们而言,同一个 EC2 中的多个可用区域可以被认为是一个数据中心的一部分。
Consensus 在我们的文档中,我们使用 Consensus 来表明就 leader 选举和事务的顺序达成一致。由于这些事务都被应用到有限状态机上,Consensus 暗示复制状态机的一致性。
Gossip Consul 建立在 Serf 的基础之上,它提供了一个用于多播目的的完整的 gossip 协议。Serf 提供成员关系,故障检测和事件广播。更多的信息在 gossip 文档中描述。这足以知道 gossip 使用基于 UDP 的随机的点到点通信。
LAN Gossip 它包含所有位于同一个局域网或者数据中心的所有节点。
WAN Gossip 它只包含 Server。这些 server 主要分布在不同的数据中心并且通常通过因特网或者广域网通信。
RPC 远程过程调用。这是一个允许 client 请求 server 的请求 / 响应机制。

让我们分解这张图并描述每个部分。首先,我们能看到有两个数据中心,标记为“1”和“2”。Consul 对多数据中心有一流的支持并且希望这是一个常见的情况。
在每个数据中心,client 和 server 是混合的。一般建议有 3 - 5 台 server。这是基于有故障情况下的可用性和性能之间的权衡结果,因为越多的机器加入达成共识越慢。然而,并不限制 client 的数量,它们可以很容易的扩展到数千或者数万台。
同一个数据中心的所有节点都必须加入 gossip 协议。这意味着 gossip 协议包含一个给定数据中心的所有节点。这服务于几个目的:第一,不需要在 client 上配置 server 地址。发现都是自动完成的。第二,检测节点故障的工作不是放在 server 上,而是分布式的。这是的故障检测相比心跳机制有更高的可扩展性。第三:它用来作为一个消息层来通知事件,比如 leader 选举发生时。
每个数据中心的 server 都是 Raft 节点集合的一部分。这意味着它们一起工作并选出一个 leader,一个有额外工作的 server。leader 负责处理所有的查询和事务。作为一致性协议的一部分,事务也必须被复制到所有其他的节点。因为这一要求,当一个非 leader 得 server 收到一个 RPC 请求时,它将请求转发给集群 leader。
server 节点也作为 WAN gossip Pool 的一部分。这个 Pool 不同于 LAN Pool,因为它是为了优化互联网更高的延迟,并且它只包含其他 Consul server 节点。这个 Pool 的目的是为了允许数据中心能够以 low-touch 的方式发现彼此。这使得一个新的数据中心可以很容易的加入现存的 WAN gossip。因为 server 都运行在这个 pool 中,它也支持跨数据中心请求。当一个 server 收到来自另一个数据中心的请求时,它随即转发给正确数据中想一个 server。该 server 再转发给本地 leader。
这使得数据中心之间只有一个很低的耦合,但是由于故障检测,连接缓存和复用,跨数据中心的请求都是相对快速和可靠的。
Consul 服务注册发现流程
Consul 在业界最广泛的用途就是作为服务注册中心,同 Eureka 类型,consul 作为服务注册中心,它的注册和发现过程如下图:
在上面的流程图上有三个角色,分别为服务注册中心、服务提供者、服务消费者。

服务提供者 Provider 启动的时候,会向 Consul 发送一个请求,将自己的 host、ip、应用名、健康检查等元数据信息发送给 Consul
Consul 接收到 Provider 的注册后,定期向 Provider 发送健康检查的请求,检验 Provider 是否健康
服务消费者 Consumer 会从注册中心 Consul 中获取服务注册列表,当服务消费者消费服务时,根据应用名从服务注册列表获取到具体服务的实例(1 个或者多个),从而完成服务的调用。

Consul VS Eureka
Eureka 是一种服务发现工具。该体系结构主要是客户端 / 服务器,每个数据中心有一组 Eureka 服务器,通常每个可用区域一个。通常,Eureka 的客户使用嵌入式 SDK 来注册和发现服务。对于非本地集成的客户端,使用 Ribbon 等边车通过 Eureka 透明地发现服务。
Eureka 使用尽力而为的复制提供弱一致的服务视图。当客户端向服务器注册时,该服务器将尝试复制到其他服务器但不提供保证。服务注册的生存时间很短(TTL),要求客户端对服务器进行心跳检测。不健康的服务或节点将停止心跳,导致它们超时并从注册表中删除。发现请求可以路由到任何服务,由于尽力复制,这些服务可以提供过时或丢失的数据。这种简化的模型允许轻松的集群管理和高可扩展性。
Consul 提供了一系列超级功能,包括更丰富的运行状况检查,键 / 值存储和多数据中心感知。Consul 需要每个数据中心中的一组服务器,以及每个客户端上的代理,类似于使用像 Ribbon 这样的边车。Consul 代理允许大多数应用程序不知道 Consul,通过配置文件执行服务注册以及通过 DNS 或负载平衡器 sidecars 进行发现。
Consul 提供强大的一致性保证,因为服务器使用 Raft 协议复制状态。Consul 支持丰富的运行状况检查,包括 TCP,HTTP,Nagios / Sensu 兼容脚本或基于的 Eureka 的 TTL。客户端节点参与基于 gossip 的健康检查,该检查分发健康检查的工作,而不像集中式心跳,这成为可扩展性挑战。发现请求被路由到当选的 Consul 领导者,这使他们默认情况下非常一致。允许过时读取的客户端允许任何服务器处理其请求,从而允许像 Eureka 一样的线性可伸缩性。
Consul 的强烈一致性意味着它可以用作领导者选举和集群协调的锁定服务。Eureka 不提供类似的保证,并且通常需要为需要执行协调或具有更强一致性需求的服务运行 ZooKeeper。
Consul 提供了支持面向服务的体系结构所需的功能工具包。这包括服务发现,还包括丰富的运行状况检查,锁定,键 / 值,多数据中心联合,事件系统和 ACL。Consul 和 consul-template 和 envconsul 等工具生态系统都试图最大限度地减少集成所需的应用程序更改,以避免需要通过 SDK 进行本机集成。Eureka 是更大的 Netflix OSS 套件的一部分,该套件期望应用程序相对同质且紧密集成。因此,Eureka 只解决了有限的一部分问题,期望其他工具如 ZooKeeper 可以同时使用。
Eureka Server 端采用的是 P2P 的复制模式,但是它不保证复制操作一定能成功,因此它提供的是一个最终一致性的服务实例视图;Client 端在 Server 端的注册信息有一个带期限的租约,一旦 Server 端在指定期间没有收到 Client 端发送的心跳,则 Server 端会认定为 Client 端注册的服务是不健康的,定时任务将会将其从注册表中删除。Consul 与 Eureka 不同,Consul 采用 Raft 算法,可以提供强一致性的保证,Consul 的 agent 相当于 Netflix Ribbon + Netflix Eureka Client,而且对应用来说相对透明,同时相对于 Eureka 这种集中式的心跳检测机制,Consul 的 agent 可以参与到基于 goosip 协议的健康检查,分散了 server 端的心跳检测压力。除此之外,Consul 为多数据中心提供了开箱即用的原生支持等。
Consul 下载和安装
Consul 采用 Go 语言编写,支持 Linux、Mac、Windows 等各大操作系统,本文使用 windows 操作系统,下载地址:https://www.consul.io/downloa…,下完成后解压到计算机目录下,解压成功后,只有一个可执行的 consul.exe 可执行文件。打开 cmd 终端,切换到目录,执行以下命令:
consul –version
终端显示如下:
Consul v1.4.2
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use p
rotocol >2 when speaking to compatible agents)
证明 consul 下载成功了,并可执行。
consul 的一些常见的执行命令如下:

命令
解释
示例

agent
运行一个 consul agent
consul agent -dev

join
将 agent 加入到 consul 集群
consul join IP

members
列出 consul cluster 集群中的 members
consul members

leave
将节点移除所在集群
consul leave

更多命令请查看官方网站:https://www.consul.io/docs/co…
开发模式启动:
consul agent -dev
启动成功,在浏览器上访问:http://localhost:8500,显示的界面如下:

spring cloud consul
该项目通过自动配置并绑定到 Spring 环境和其他 Spring 编程模型成语,为 Spring Boot 应用程序提供 Consul 集成。通过几个简单的注释,您可以快速启用和配置应用程序中的常见模式,并使用基于 Consul 的组件构建大型分布式系统。提供的模式包括服务发现,控制总线和配置。智能路由(Zuul)和客户端负载平衡(Ribbon),断路器(Hystrix)通过与 Spring Cloud Netflix 的集成提供。
使用 spring cloud consul 来服务注册与发现
本小节以案例的形式来讲解如何使用 Spring Cloud Consul 来进行服务注册和发现的,并且使用 Feign 来消费服务。再讲解之前,已经启动 consul 的 agent,并且在浏览器上 http://localhost:8500 能够显示正确的页面。本案例一共有 2 个工程,分别如下:

工程名
端口
描述

consul-provider
8763
服务提供者

consul-consumer
8765
服务消费者

其中,服务提供者和服务消费者分别向 consul 注册,注册完成后,服务消费者通过 FeignClient 来消费服务提供者的服务。
服务提供者 consul-provider
创建一个工程 consul-provider,在工程的 pom 文件引入以下依赖,包括 consul-discovery 的起步依赖,该依赖是 spring cloud consul 用来向 consul 注册和发现服务的依赖,采用 REST API 的方式进行通讯。另外加上 web 的起步依赖,用于对外提供 REST API。代码如下:

<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>

在工程的配置文件 application.yml 做下以下配置:
server:
port: 8763
spring:
application:
name: consul-provider
cloud:
consul:
host: localhost
port: 8500
discovery:
serviceName: consul-provider
上面的配置,指定了程序的启动端口为 8763,应用名为 consul-provider,consul 注册中心的地址为 localhost:8500
在程序员的启动类 ConsulProviderApplication 加上 @EnableDiscoveryClient 注解,开启服务发现的功能。
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulProviderApplication {

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

}
写一个 RESTAPI,该 API 为一个 GET 请求,返回当前程序的启动端口,代码如下。

@RestController
public class HiController {

@Value(“${server.port}”)
String port;
@GetMapping(“/hi”)
public String home(@RequestParam String name) {
return “hi “+name+”,i am from port:” +port;
}

}

启动工程,在浏览器上访问 http://localhost:8500,页面显示如下:

从上图可知,consul-provider 服务已经成功注册到 consul 上面去了。
服务消费者 consul-provider
服务消费者的搭建过程同服务提供者,在 pom 文件中引入的依赖同服务提供者,在配置文件 application.yml 配置同服务提供者,不同的点在端口为 8765,服务名为 consul-consumer。
写一个 FeignClient,该 FeignClient 调用 consul-provider 的 REST API,代码如下:

@FeignClient(value = “consul-provider”)
public interface EurekaClientFeign {

@GetMapping(value = “/hi”)
String sayHiFromClientEureka(@RequestParam(value = “name”) String name);
}

Service 层代码如下:
@Service
public class HiService {

@Autowired
EurekaClientFeign eurekaClientFeign;

public String sayHi(String name){
return eurekaClientFeign.sayHiFromClientEureka(name);
}
}

对外提供一个 REST API,该 API 调用了 consul-provider 的服务,代码如下:
@RestController
public class HiController {
@Autowired
HiService hiService;

@GetMapping(“/hi”)
public String sayHi(@RequestParam( defaultValue = “forezp”,required = false)String name){
return hiService.sayHi(name);
}
}

在浏览器上访问 http://localhost:8765/hi,浏览器响应如下:
hi forezp,i am from port:8763
这说明 consul-consumer 已经成功调用了 consul-provider 的服务。这说明 consul-provider 的服务已经注册到了 consul 的注册中心上面去了。consul-consumer 能够获取注册中心的注册列表来获来消费服务。
使用 Spring Cloud Consul Config 来做服务配置中心
Consul 不仅能用来服务注册和发现,Consul 而且支持 Key/Value 键值对的存储,可以用来做配置中心。Spring Cloud 提供了 Spring Cloud Consul Config 依赖去和 Consul 相集成,用来做配置中心。现在以案例的形式来讲解如何使用 Consul 作为配置中心,本案例在上一个案例的 consul-provider 基础上进行改造。首先在工程的 pom 文件加上 consul-config 的起步依赖,代码如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
然后在配置文件 application.yml 加上以下的以下的配置,配置如下:
spring:
profiles:
active: dev
上面的配置指定了 SpringBoot 启动时的读取的 profiles 为 dev。然后再工程的启动配置文件 bootstrap.yml 文件中配置以下的配置:
spring:
application:
name: consul-provider
cloud:
consul:
host: localhost
port: 8500
discovery:
serviceName: consul-provider
config:
enabled: true
format: yaml
prefix: config
profile-separator: ‘:’
data-key: data

关于 spring.cloud.consul.config 的配置项描述如下:

enabled 设置 config 是否启用,默认为 true
format 设置配置的值的格式,可以 yaml 和 properties
prefix 设置配的基本目录,比如 config
defaultContext 设置默认的配置,被所有的应用读取,本例子没用的
profileSeparator profiles 配置分隔符, 默认为‘,’
date-key 为应用配置的 key 名字,值为整个应用配置的字符串。

网页上访问 consul 的 KV 存储的管理界面,即 http://localhost:8500/ui/dc1/kv,创建一条记录,
key 值为:config/consul-provider:dev/datavalue 值如下:
foo:
bar: bar1
server:
port: 8081

在 consul-provider 工程新建一个 API,该 API 返回从 consul 配置中心读取 foo.bar 的值,代码如下:
@RestController
public class FooBarController {

@Value(“${foo.bar}”)
String fooBar;

@GetMapping(“/foo”)
public String getFooBar() {
return fooBar;
}
}
启动工程,可以看到程序的启动端口为 8081,即是 consul 的配置中心配置的 server.port 端口。工程启动完成后,在浏览器上访问 http://localhost:8081/foo,页面显示 bar1。由此可知,应用 consul-provider 已经成功从 consul 的配置中心读取了配置 foo.bar 的配置。
动态刷新配置
当使用 spring cloud config 作为配置中心的时候,可以使用 spring cloud config bus 支持动态刷新配置。Spring Cloud Comsul Config 默认就支持动态刷新,只需要在需要动态刷新的类上加上 @RefreshScope 注解即可,修改代码如下:
@RestController
@RefreshScope
public class FooBarController {

@Value(“${foo.bar}”)
String fooBar;

@GetMapping(“/foo”)
public String getFooBar() {
return fooBar;
}
}
启动 consul-provider 工程,在浏览器上访问 http://localhost:8081/foo,页面显示 bar1。然后在网页上访问 consul 的 KV 存储的管理界面,即 http://localhost:8500/ui/dc1/kv,修改 config/consul-provider:dev/data 的值,修改后的值如下:
foo:
bar: bar2
server:
port: 8081

此时不重新启动 consul-provider,在浏览器上访问 http://localhost:8081/foo,页面显示 bar2。可见 foo.bar 的最新配置在应用不重启的情况下已经生效。
注意事项

consul 支持的 KV 存储的 Value 值不能超过 512KB
Consul 的 dev 模式,所有数据都存储在内存中,重启 Consul 的时候会导致所有数据丢失,在正式的环境中,Consul 的数据会持久化,数据不会丢失。

参考资料
https://www.consul.io/intro/i…
https://www.consul.io/docs/in…
https://www.consul.io/intro/v…
http://www.ityouknow.com/spri…
https://springcloud.cc/spring…
https://www.cnblogs.com/lsf90…
https://blog.csdn.net/longgeq…
更多阅读
史上最简单的 SpringCloud 教程汇总
SpringBoot 教程汇总
Java 面试题系列汇总

正文完
 0