《深入理解 Spring Cloud 与微服务构建》第十二章 服务注册和发现 Consul

文章目录

  • 《深入理解 Spring Cloud 与微服务构建》第十二章 服务注册和发现 Consul
  • 一、什么是 Consul
    • 1.基本术语
    • 2.Consul 的特点和功能
    • 3.Consul 的原理
    • 4.Consul 的基本架构
    • 5.Consul 服务注册发现流程
  • 二、Consul 与 Eureka 比较
  • 三、下载和安装 Consul
  • 四、使用 Spring Cloud Consul 进行服务注册和发现
    • 1.服务提供者 consul-provider
    • 2.服务消费者
  • 五、使用 Spring Cloud Consul Config 做服务配置中心
  • 六、动态刷新配置

一、什么是 Consul

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

1.基本术语

  • 代理(Agent):是一直运行在 Consul 集群中的每个节点上的守护进程,通过运行 consul agent 命令来启动。代理可以以客户端或服务端模式运行。无论是客户端节点,还是服务端节点,都必须运行代理,因此将节点称为客户端或服务器更容易理解。所有代理都可以通过 DNS 或 HTTP 接口来检查服务,并保持服务同步
  • 客户端(Client):客户端是所有 RPC 转发到服务端的代理。这个客户端是相对无状态的。客户端唯一执行的后台活动是加入 LAN gossip 池,资源开销很小
  • 服务端(Server):服务端是具有扩展责任的代理,包括参与 Raft 选举、维护集群状态、响应 RPC 查询、与其他数据中心交换 WAN,以及将查询转发给领导者(Leader)或远程数据中心
  • 数据中心(Data Center):是一个私有的、低延迟且高带宽的网络环境,由多个客户端和服务端构成
  • 共识(Consensus):在文档中,我们使用共识来表示对当选领导者的协议以及交易顺序的协议。由于这些事务应用于有限状态机,因此我们对共识的定义意味着复制状态机的一致性
  • Goosip:Consul 建立在 Serf 的基础上,它提供了一个完整的 Gossip 协议
  • LAN Gossip:是指局域网 Gossip,包含位于同一个数据中心的所有节点
  • WAN Gossip:是指仅包含服务端的 WAN Gossip 池。这些服务端位于不同的数据中心,通常通过互联网或广域网进行通信
  • 远程调用(RPC):是一个允许客户端请求服务端的呢请求-响应机制

2.Consul 的特点和功能

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

3.Consul 的原理

每个提供服务的节点都运行了 Consul 的代理(Agent),运行代理时不需要服务发现和获取配置的 KV 键值对,代理只负责监控检查。代理节点可以和一个或多个 Consul 服务端通信。Consul 服务端使存储和复制数据的节点,采用 RAFT 算法保证了数据一致性,并选出了领导者,建议使用 3 台或 5 台 Consul 服务端,以避免发生数据丢失的情况。Consul 支持多个数据中心,建议每个数据中心使用多个 Consul Server 作为一个集群

如果微服务组件需要发现服务,可以查询任何 Consul 服务端或任何 Consul 代理。如果是查询 Consul Agent,Consul Agent 会自动将查询请求转发给 Consul 服务端。发生跨数据中心服务发现或配置请求时,本地 Consul 服务端会将请求转发到远程数据中心,并返回结果

4.Consul 的基本架构

Consul 的基本架构如图所示:


其中有两个数据中心,标记为 “DATACENTER 1” 和 “DATACENTER 2”。在大型分布式系统中,多数据中心是十分常见的,Consul 对多数据中心有着非常强大的支持

在每个数据中心中,客户端和服务端是混合的。一般建议使用奇数个服务端,比如 3 台或 5 台。这是基于有故障情况下的可用性和性能之间的权衡结果,因为越多的机器加入,则达成共识的速度越慢。但这并不是限制客户端的数量,客户端可以很容易地扩展到数千台或数万台

同一个数据中心的所有节点都加入了 Gossip 协议,意味着 Gossip 协议池包含该数据中心的所有节点,这样做有如下 3 个目的:

  • 不需要在客户端上配置服务端地址,服务发现都是自动完成的
  • 检测节点故障的工作不放在服务端上,而是分布式的,使得故障检测比心跳机制有更高的可扩展性
  • 数据中心可被用作消息传递层,比如发生领导者选举等重要事件时起到通知作用

数据中心中的每个服务端节点都是 Raft 节点集合的一部分。他们共同选举一个领导者,即一个具有额外职责的选定服务端。领导者负责处理所有查询和事务,作为共识协议的一部分,还必须将事务复制到所有对等体。因此当非领导者的服务端收到 RPC 请求时,它会将请求转发给群集的领导者

服务端节点也作为 WAN Gossip 协议池的一部分,不同于 LAN Gossip 协议池的是,它对较高的网络延迟进行了优化,并且只包含其它 Consul 服务端节点。这个协议池的作用是允许数据中心能够以低接触的方式发现彼此,使得一个新数据中心可以很容易地加入现存的 WAN Gossip 协议池。因为服务端都运行在这个协议池中,支持跨数据中心请求。当一个服务端收到来自另一个数据中心的请求时,它会将其转发到正确数据中心的随机服务端。该服务端再转发给本地领导者

数据中心之间的耦合度非常低,但由于故障检测、连接缓存和多路复用等机制,跨数据中心请求相对快速且可靠

5.Consul 服务注册发现流程

Consul 最广泛的用途之一就是作为服务注册中心,同时也可以作为配置中心。作为服务注册中心时,Consul 同 Eureka 类似,其注册和发现过程中有 3 个角色,分别是服务注册中心、服务提供者、服务消费者

  • 服务提供者(Provider)启动时,会向 Consul 发送一个请求,将其 Host、IP、应用名、健康检查等元数据信息发送给 Consul
  • Consul 接收到服务提供者的注册后,定期向其发送健康检查的请求,检验服务提供者是否健康
  • 服务消费者(Consumer)会从注册中心 Consul 中获取服务注册列表,当服务消费者消费服务时,会根据服务命从服务注册列表中获取具体服务的实例(一个或者多个)信息,再根据负载均衡策略完成服务的调用

二、Consul 与 Eureka 比较

Eureka 是 Netflix 公司开源的服务注册中心组件,是 Spring Cloud 官方比较推荐的服务注册中心解决方案,在 Eureka 的架构体系中,分为 Eureka 服务端和 Eureka 客户端。Eureka 服务端可以支持多数据中心,每个数据中心有一组 Eureka 服务端。通常,Eureka 客户端使用嵌入式 SDK 来注册和发现服务

Eureka 使用注册列表复制的方式提供弱一致的服务视图。当 Eureka 客户端向 Eureka 服务端注册时,该 Eureka 服务端将尝试复制到其它 Eureka 服务端,但不提供强一致性保护。服务注册成功后,要求 Eureka 客户端对 Eureka 服务端进行心跳健康检测。不健康的服务或节点将停止心跳,从而导致他们的监控检查超时,并从注册表中删除。服务注册的请求可以路由到任何 Eureka 服务端,Eureka 服务端可以提供过时或丢失的数据。这种简化的模型能够轻松地搭建 Eureka 服务端集群的高可用和强扩展性

相比 Eureka,Consul 提供了更多高级功能,包括更丰富的运行时健康检查、键值存储和多数据中心的相互感知。Consul 提供了强一致性的保证,因为 Consul 服务端使用 Raft 协议及逆行状态的复制。Consul 支持丰富的运行时健康检查,包括 TCP、HTTP、Ngios、Sensu 兼容脚本等。Consul 客户端基于 Gossip 的健康检查。服务注册请求会被路由到 Consul 领导者的节点

Consul 的强一致性意味着它需要用领导者选举和集群协调来锁定服务。Eureka 采用的是 P2P 的复制模式,不保证复制操作一定成功;Eureka 不提供强一致性的保证,而是提供一个最终一致性的服务实例视图。Eureka 客户端在 Eureka 服务端的注册信息有一个带期限的服务续约,一旦 Eureka 服务端在指定时间内没有收到 Eureka 客户端的心跳,则 Eureka 服务端会认定 Eureka 客户端注册的服务是不健康的。Consul 的代理(Agent)相当于 Netflix Ribbon + Netflix Eureka 客户端,而且对应用来说相对透明,同时,相比 Eureka 这种集中式的心跳检测机制,Consul 的代理可以参与到基于 Goosip 协议的健康检查中,分散了服务端的心跳检测压力。除此之外,Consul 为多数据中心提供了开箱即用的原生支持

三、下载和安装 Consul

Consul 使用 Go 语言编写,支持 Linux、Mac、Windows 等操作系统。到 Consul 官网 中下载安装包,下载完成后解压到计算机目录下,解压成功后,只有一个可执行的 consul.exe 文件。打开 cmd 终端,切换到安装目录下,执行以下命令:

consul --version

终端显示如下信息:

这样证明 C瓯南苏拉下载成功,并且可以执行

Consul 的常见执行命令如下表所示:

命令 解释 示例
agent 运行一个 consul agent consul agent -dev
join 将 agent 加入 consul 集群 consul join IP
members 列出 consul cluster 集群中的 members consul members

更多的 Consul 执行命令:Consul 官方网站

现在以开发者模式启动 Consul,使用 cmd 命令终端启动,启动命令如下:

consul agent -dev

在终端界面上,可以看到启动的日志,Consul 默认的访问端口为 8500.启动成功后,在浏览器上访问 http://lcoalhost:8500,显示的主界面如图所示:

随着 Eureka 2.0 版本的闭源,作为服务注册中心,Consul 在以企业级 Spring Cloud 为服务系统中将有着更加广泛的应用。接下来以案例的形式来讲解如何使用 Consul 作为服务注册中心和分布式配置中心

四、使用 Spring Cloud Consul 进行服务注册和发现

本案例一共有两个应用,应用信息如下表所示:

应用名 端口 描述
consul-provider 8763 服务提供者
consul-consumer 8765 服务消费者

1.服务提供者 consul-provider

创建一个主 Maven 工程,然后创建一个 Spring Boot 子工程 consul-provider,在工程的 pom 文件中引入以下依赖,包括 consul-discovery 的起步依赖,该依赖是 spring cloud consul 用来向 consul 注册和发现服务的依赖,采用 REST API 方式进行通信。另外加上 WEB 的起步依赖,用于对外提供 REST API。代码如下:

<?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>Consul</artifactId><groupId>org.example</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>consul-provider</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><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></dependencies>
</project>

在工程的配置文件 application.yml 中做如下配置,代码如下:

server:port: 8763spring:application:name: consul-providercloud:consul:host: localhostport: 8500discovery:serviceName: consul-providerheartbeat:enabled: true

在上述配置中,指定了程序的启动端口为 8763,应用名为 consul-provider,consul 注册中心的地址为 localhost:8500

在程序的启动类 ConsulProviderApplication 中加上 @EnableDiscoveryClient 注解,开启服务发现的功能,代码如下:

package com.sisyphus;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient
public class ConsulProviderApplication {public static void main(String[] args) {SpringApplication.run(ConsulProviderApplication.class, args);}
}

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

package com.sisyphus.controller;import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@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 注册中心:

2.服务消费者

服务消费者的搭建过程与服务提供者类似,在 pom 文件中引入依赖,在配置文件 application.yml 做与服务提供者相同的配置,不同之处在于端口为 8765,服务名为 consul-consumer

然后写一个 FeignClient,该 FeignClient 调用 consul-provider 的 REST API,代码如下:

package com.sisyphus.feign;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;@FeignClient(value = "consul-provider")
public interface EurekaClientFeign {@GetMapping(value = "/hi")String sayHiFromClientEureka(@RequestParam(value = "name") String name);
}

Service 层代码如下:

package com.sisyphus.service;import com.sisyphus.feign.EurekaClientFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class HiService {@AutowiredEurekaClientFeign eurekaClientFeign;public String sayHi(String name){return eurekaClientFeign.sayHiFromClientEureka(name);}
}

对外提供一个 REST API,该 API 调用了 consul-provider 的服务,代码如下:

package com.sisyphus.controller;import com.sisyphus.service.HiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HiController {@AutowiredHiService hiService;@GetMapping("/hi")public String sayHi(@RequestParam(defaultValue = "sisyphus", required = false) String name){return hiService.sayHi(name);}
}

在浏览器上访问 http://localhost:8765/hi,浏览器响应如下:

这说明 consul-consumer 已经成功调用了 consul-provider 服务

五、使用 Spring Cloud Consul Config 做服务配置中心

Consul 不仅能用来服务注册和发现,而且 Consul 支持键值对的存储,可以用来做分布式配置中心。Spring Cloud 提供了 Spring Cloud Consul Config 依赖去和 Consul 相集成,用来做分布式配置中心

本案例再上一个案例的 soncul-provider 基础上进行改造。首先在工程的 pom 文件上加上 consul-config 的起步依赖,代码如下:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>

然后修改配置文件 application.yml ,代码如下:

server:port: 8763spring:profiles:active: dev

上述配置文件指定了 Spring Boot 工程在启动时读取的 profiles 为 dev。然后在工程的启动配置文件 bootstrap.yml 文件中加上以下配置,代码如下:

spring:application:name: consul-providercloud:consul:host: localhostport: 8500discovery:service-name: consul-providerheartbeat:enabled: trueconfig:enabled: trueformat: yamlprefix: configdefaultContext: applicationprofileSeparator: ':'data-key: data

spring.cloud.consul.config 的配置项描述信息如下:

  • Eabled:设置 config 是否启用,默认为 true
  • Format:设置配置的值得格式,可以为 yaml 和 properties
  • Prefix:设置配置的基本目录,比如 config
  • defaultContext:设置默认的配置,被所有的应用读取,本例中未用
  • profileSeparator profiles:设置分隔符,默认为 “,”
  • data-key:为应用配置得 key 名字,值为整个应用配置的字符串

在浏览器上访问 consul 的 Key/Value 存储的管理界面,即 http://localhost:8500/ui/dc;/kv,创建一条记录其中 Key 值为 cofig/consul-provider:dev/data,Value 值如下所示:

root:bar: bar1
server:port: 8081

在 consul-provider 工程中创建一个 REST API,该 API 返回从 Consul 配置中心读取 foo.bar 的值,代码如下:

package com.sisyphus.controller;import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class FooBarController {@Value("${foo.bar")String fooBar;@GetMapping("/foo")public String getFooBar(){return fooBar;}
}

启动工程,可以看到程序的启动端口为 8081,也就是在 Consul 的配置中心配置的 server.port 端口。工程启动完成后,在浏览器上访问呢 http:locahost:8081/foo,页面 显示 bar1,由此可知,应用 consul-provider 已经成功从 Consul 的配置中心读取了 foo.bar 的配置

六、动态刷新配置

在使用 Spring Cloud Config 作为配置中心时,可以使用 Spring Cloud Config Bus 动态刷新配置。Spring Cloud Consul 默认支持动态刷新,在需要动态刷新的类加上 @RefreshScope 注解即可,修改代码如下:

package com.sisyphus.controller;import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@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 存储的管理界面,修改 config/consul-provider:dev/data 的值,修改后的值如下:

foo:bar: bar2
server:port: 8081

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

《深入理解 Spring Cloud 与微服务构建》第十二章 服务注册和发现 Consul相关推荐

  1. 《深入理解Spring Cloud与微服务构建》出版啦!

    作者简介 方志朋,毕业于武汉理工大学,CSDN博客专家,专注于微服务.大数据等领域,乐于分享,爱好开源,活跃于各大开源社区.著有<史上最简单的Spring Cloud教程>,累计访问量超过 ...

  2. 《深入理解 Spring Cloud 与微服务构建》第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统

    <深入理解 Spring Cloud 与微服务构建>第十八章 使用 Spring Security OAuth2 和 JWT 保护微服务系统 文章目录 <深入理解 Spring Cl ...

  3. 《深入理解 Spring Cloud 与微服务构建》第十七章 使用 Spring Cloud OAuth2 保护微服务系统

    <深入理解 Spring Cloud 与微服务构建>第十七章 使用 Spring Cloud OAuth2 保护微服务系统 文章目录 <深入理解 Spring Cloud 与微服务构 ...

  4. 《深入理解 Spring Cloud 与微服务构建》第十六章 Spring Boot Security 详解

    <深入理解 Spring Cloud 与微服务构建>第十六章 Spring Boot Security 详解 文章目录 <深入理解 Spring Cloud 与微服务构建>第十 ...

  5. 《深入理解 Spring Cloud 与微服务构建》第十五章 微服务监控 Spring Boot Admin

    <深入理解 Spring Cloud 与微服务构建>第十五章 微服务监控 Spring Boot Admin 文章目录 <深入理解 Spring Cloud 与微服务构建>第十 ...

  6. 《深入理解 Spring Cloud 与微服务构建》第十四章 服务链路追踪 Spring Cloud Sleuth

    <深入理解 Spring Cloud 与微服务构建>第十四章 服务链路追踪 Spring Cloud Sleuth 文章目录 <深入理解 Spring Cloud 与微服务构建> ...

  7. 《深入理解 Spring Cloud 与微服务构建》第十三章 配置中心 Spring Cloud Config

    <深入理解 Spring Cloud 与微服务构建>第十三章 配置中心 Spring Cloud Config 文章目录 <深入理解 Spring Cloud 与微服务构建>第 ...

  8. 《深入理解 Spring Cloud 与微服务构建》第十一章 服务网关

    <深入理解 Spring Cloud 与微服务构建>第十一章 服务网关 文章目录 <深入理解 Spring Cloud 与微服务构建>第十一章 服务网关 一.服务网关简介 二. ...

  9. 《深入理解 Spring Cloud 与微服务构建》第十章 路由网关 Spring Cloud Zuul

    <深入理解 Spring Cloud 与微服务构建>第十章 路由网关 Spring Cloud Zuul 文章目录 <深入理解 Spring Cloud 与微服务构建>第十章 ...

最新文章

  1. 裸centos安装PCRE时报错解决
  2. Oracle数据库的关闭详解
  3. ThoughtWorks代码挑战——FizzBuzzWhizz
  4. JS function立即调用的几种写法
  5. antlr4例子_ANTLR和网络:一个简单的例子
  6. 抖音一个老人和一个机器人歌曲_一个老人孤独去世,一个老人安然离世
  7. 【美团分享】美团大脑及其在推荐系统中的应用.pdf(附下载链接)
  8. Vue整合nginx:(1)开发环境npm run dev下,通过nginx解决前后端分离造成的跨域问题
  9. python defaultdict(list)_Python collections.defaultdict() 与 dict的使用和区别
  10. python求解LeetCode习题Sort Colors
  11. 发点牢骚,关于微软,关于WPF/E
  12. 【大兴区亦庄亦庄线东晶国际4居室】自如网
  13. 正向代理 反向代理 理解
  14. [论文]鲁棒的对抗性强化学习
  15. 【转】专家:制造业将大批死亡 都怪马云
  16. 如何在vue中优雅的使用ocx控件:结合iframe
  17. WPF - 简单的UI框架
  18. 【Matlab】评估网络节点重要性
  19. uniapp+egg.js+react实现全栈笔记App
  20. SNS游戏主题餐厅即将上线了!

热门文章

  1. java的平方分之x的平方加xy_Java面试宝典_基础编程练习题_完全平方数
  2. pandas php,pandas分组聚合代码详解
  3. 后台系统应该具备的素养
  4. SQA计划和验收测试规程设计
  5. wget命令3(转载)
  6. java 蓝桥杯历届试题 分糖果(题解)
  7. window.opener方法的使用 刷新父页面
  8. linux进程和线程理解
  9. 带你了解PCIE通信原理
  10. List大坑集「锦」