赞
踩
Consul 是 HashiCorp 公司推出来的开源产品。主要提供了:服务发现、服务隔离、服务配置等功能。相比于 其他注册中心组件Eureka 和Zookeeper,Consul 配置更加一站式,因为它内置了很多微服务常见的功能:服务发现与注册、分布式一致性协议实现、健康检查、键值对存储、多数据中心等,我们不再需要借助第三方组件来实现这些功能。
Spring Cloud Consul 具有如下特性:
Spring Cloud Consul 中文文档:https://www.springcloud.cc/spring-cloud-consul.html
不同于 Eureka ,Consul 使用 Go 语言开发,所以我们需要先安装Consul 。
从官网直接下载软件,官网下载地址:https://www.consul.io/downloads.html。下载完成后只有一个exe文件,首先双击运行该文件;
在命令行中输入以下命令可以查看版本号:
consul --version
然后使用开发模式启动:
consul agent -dev
浏览器访问 http://localhost:8500 ,进入Consul首页。
在 Linux 中,首先执行如下命令下载 Consul:
wget https://releases.hashicorp.com/consul/1.6.2/consul_1.6.2_linux_amd64.zip
下载完成后解压压缩包
unzip consul_1.6.2_linux_amd64.zip
解压完成后,我们可以看到consul文件,然后执行以下命令启动consul:
./consul agent -dev -ui -node=consul-dev -client=192.168.91.128
参数说明:
其他参数:
注意:192.168.91.128应该为内网ip。还要确保8500端口可用
启动成功后,浏览器请求http://101.43.30.7:8500/ui/dc1/services,访问consul管理后台
集群部署Consul的相关命令:
./consul members:查看集群信息
./consul join consul服务IP:添加节点
./consul info:查看节点的具体信息
创建Spring Boot项目,作为服务提供者,添加以下依赖:
<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>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
成功创建项目后,application.properties添加如下配置:
spring.application.name=consul-provider
server.port=2000
#consul的主机地址
spring.cloud.consul.host=101.43.30.7
#conusl的端口
spring.cloud.consul.port=8500
#服务的名称
spring.cloud.consul.discovery.service-name=consul-provider
spring.cloud.consul.discovery.heartbeat.enabled=true
在启动类上开启服务发现的功能:
@SpringBootApplication
//开启服务发现功能
@EnableDiscoveryClient
public class ConsulProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ConsulProviderApplication.class, args);
}
}
启动项目,访问consul管理后台界面,可以看到已经注册成功。
(如果服务总是报红叉,则需要在application.yml配置文件中增加spring.cloud.consul.discovery.heartbeat.enabled=true,打开Consul的心跳机制)
创建HelloController添加接口/hello
@RestController
public class HelloController {
@Value("${server.port}")
Integer port;
@GetMapping("/hello")
public String hello(){
return "hello" + port;
}
}
对项目进行打包,命令行启动多一个provider实例:
java -jar consul-provider-0.0.1-SNAPSHOT.jar --server.port=6000
consul管理后台可以看到有两个provider实例
创建Spring Boot项目consul-consumer,作为服务消费者,添加以下依赖:
<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>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
成功创建项目后,application.properties添加如下配置:
spring.application.name=consul-consumer
server.port=2002
#consul的主机地址
spring.cloud.consul.host=101.43.30.7
#conusl的端口
spring.cloud.consul.port=8500
#服务的名称
spring.cloud.consul.discovery.service-name=consul-consumer
在启动类上开启服务发现的功能,并注入RestTemplate:
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsulConsumerApplication.class, args);
}
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
测试服务调用
@RestController public class HelloController { @Autowired LoadBalancerClient loadBalancerClient; @Autowired RestTemplate restTemplate; @GetMapping("/hello") public void hello() { ServiceInstance choose = loadBalancerClient.choose("consul-provider"); System.out.println("服务地址:" + choose.getUri()); System.out.println("服务名称:" + choose.getServiceId()); String s = restTemplate.getForObject(choose.getUri() + "/hello", String.class); System.out.println(s); } }
这里通过loadBalancerClient获取要调用的ServiceInstance,获取到调用地址之后再使用RestTemplate去调用。浏览器请求http://localhost:2002/hello ,查看控制台的请求结果。
我们还可以在consul中实现服务的统一配置,创建Maven模块consul-config,在pom.xml中添加如下依赖:
<?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> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <modelVersion>4.0.0</modelVersion> <groupId>top.javahai</groupId> <artifactId>consul-config</artifactId> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR6</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</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> </project>
添加配置文件application.yml,配置启用dev环境:
spring:
profiles:
active: dev
添加配置文件bootstrap.yml,对Consul的配置功能进行配置:
server: port: 9101 spring: application: name: consul-config cloud: consul: host: localhost port: 8500 discovery: serviceName: consul-config #打开心跳机制 heartbeat: enabled: true config: #是否启用配置中心功能 enabled: true #设置配置值的格式 format: yaml #设置配置所在目录 prefix: config #设置配置的分隔符 profile-separator: ':' #配置key的名字,由于Consul是K/V存储,配置存储在对应K的V中 data-key: data
创建ConfigController,提供接口/configInfo,从Consul配置中心中获取配置信息.使用@RefreshScope注解实现动态加载配置文件。
@RestController
@RefreshScope
public class ConfigController {
@Value("${config.info:}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo() {
return configInfo;
}
}
在Consul后台添加如下配置:
添加配置存储的key为:
config/consul-config:dev/data
添加配置存储的value为:
config:
info:"config info onsul-config for dev"
启动项目调用/configinfo接口查看配置信息。
我们修改Consul中的配置信息,再次调用查看配置的接口,就会发现配置也刷新了。这是因为Consul使用其自带的Control Bus 实现了一种事件传递机制,从而实现了动态配置刷新功能。
CAP理论是分布式架构中重要理论。C(Consistency)一致性、A(Availablity)可用性、P(Partition Tolerance)分区容错性。分布式系统不可能同时满足三个特性,最多只能满足其中两个特性。根据实际情况选择不同的特性组合对应的技术栈。
一致性:对于客户端的每次读操作,要么读到的是最新的数据,要么读取失败。换句话说,一致性是站在分布式系统的角度,对访问本系统的客户端的一种承诺:要么我给您返回一个错误,要么我给你返回绝对一致的最新数据,不难看出,其强调的是数据正确。
可用性:任何客户端的请求都能得到响应数据,不会出现响应错误。换句话说,可用性是站在分布式系统的角度,对访问本系统的客户的另一种承诺:我一定会给您返回数据,不会给你返回错误,但不保证数据最新,强调的是响应不出现错误。
分区容忍性:由于分布式系统通过网络进行通信,网络是不可靠的。当任意数量的消息丢失或延迟到达时,系统仍会继续提供服务,不会挂掉。换句话说,分区容忍性是站在分布式系统的角度,对访问本系统的客户端的再一种承诺:我会一直运行,不管我的内部出现何种数据同步问题,强调的是不挂掉。
而CAP 在分布式系统不可能同时满足,只能取其中2个原因是 如果C是第一需求的话,那么会影响A的性能,因为要数据同步,不然请求结果会有差异,但是数据同步会消耗时间,期间可用性就会降低。如果A是第一需求,那么只要有一个服务在,就能正常接受请求,但是返回结果的正确性便不能保证,原因是在分布式部署的时候,节点间的数据同步的过程需要一定的时间。再如果,同时满足一致性和可用性,那么分区容错性就很难保证了。对于数据没有同步的节点,只能暂停接收请求,这就违背了分区容错性。
Consul 遵循CAP原理中的CP原则,保证了强一致性和分区容错性,且使用的是Raft算法,比Zookeeper使用的Paxos算法更加简单。虽然保证了强一致性,但是可用性就相应下降了,例如服务注册的时间会稍长一些,因为 Consul 的 raft 协议要求必须过半数的节点都写入成功才认为注册成功 ;在leader挂掉了之后,重新选举出leader之前会导致Consul 服务不可用。Consul 保证了强一致性但牺牲了可用性。
Eureka:主要支持的是AP,强调高可用和分区容错;
Consul和Zookeeper:主要支持CP,强调数据一致性和分区容错。
Eureka拥有一个自我保护机制,当在90s内如果有过多的心跳包丢失,Eureka不会直接注销该服务,而是选择采用保护机制不去注销服务,等到90s到期如果仍然不能接受心跳包就直接注销,这种为了保证最大吞吐量而牺牲数据一致性的思想就是AP;
Zookeeper采用创建临时节点的机制来注册服务,由于是临时节点在连接断开时就会立刻被删除,对应着服务就被注销,这种思想对应的就是CP;
Consul在微服务器断开时会立刻停止服务,必须过半数的节点都写入成功才认为注册成功 ;在leader挂掉了之后,重新选举出leader之前会导致Consul 服务不可用的方式,来保证数据一致性原则。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。