此文章主要讲解springcloud中注册中心Eureka替代方案Consul的相关知识。
Eureka闭源的影响
Eureka闭源
- 在Eureka的GitHub上,宣布Eureka 2.x闭源。这意味着如果开发者继续使用2.x分支上现有工作repo的一部分发布的代码库和组件,则自负风险。
Eureka的替换方案
Zookeeper
- Zookeeper是一个分布式的,开放源代码的分布式应用程序协调服务,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
Consul
-
Consul是近几年比较流行的服务发现工具。
-
Consul的三个主要应用场景:服务发现、服务隔离、服务配置。
Nacos
- Nacos是阿里巴巴推出来的一个新开源项目,这是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos致力于帮助您发现、配置和管理微服务。Nacos提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据以及流量管理。Nacos帮助您更敏捷和容易的构建、交付和管理微服务平台。Nacos是构建以“服务”为中心的现代应用架构(例如微服务范式、云原生范式)的服务基础设施。
Consul简介
概述
- Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现和配置。和其他分布式服务注册和发现的方案,Consul的方案更“一站式”,内置了服务注册和发现框架、分布式一致性协议实现、健康检查、key/value存储、多数据中心方案,不再需要依赖其他工具(比如Zookeeper等)。使用起来也比较简单。Consul使用Go语言编写,因此具有天然移植性(支持Linux、Windows和Mac OS X),安装包仅包含一个可执行的文件,方便部署,和Docker等轻量级容器可以无缝配合。
Consul的优势
-
采用Raft算法来保证一致性,比服务的Paxos算法更直接。Zookeeper采用的是Paxos算法,而Consul以及etcd采用的是Raft算法。
-
支持多数据中心,内外网的服务采用不同的端口进行监听。多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟、分片等情况。Zookeeper和etcd均不提供多数据中心功能的支持。
-
支持健康检查。etcd不提供此功能。
-
支持http和dns协议接口。Zookeeper的集成较为复杂,etcd只支持http协议。
-
官方提供web管理界面。etcd无此功能。
Consul的特性
-
服务发现。
-
健康检查。
-
key/value存储。
-
多数据中心。
Consul和Eureka的区别
一致性
-
Consul:强一致性(CP):
-
服务注册相比Eureka会稍慢一些。因为Consul的Raft协议要求必须过半的节点都写入成功才认为注册成功。
-
Leader挂掉后,重新选举期间整个Consul不可用。保证了强一致性,但牺牲了可用性。
-
Eureka:高可用性和最终一致性(AP):
-
服务注册相对要快,因为不需要等注册信息复制到其他节点,也不保证注册信息是否复制成功。
-
当数据出现不一致的时候,虽然A,B上的注册信息不完全相同,但是每个Eureka节点依然能够正常对外提供服务,这会出现查询服务信息时如果请求A查不到,但请求B就能查到。如果保证了可用性但牺牲了一致性。
开发语言和使用
-
Eureka是Servlet程序,跑在Servlet容器中。
-
Consul是Go语言编写而言的,安装启动即可。
官网
官网地址: https://www.consul.io/intro
中文地址: https://www.springcloud.cc/spring-cloud-consul.html
consul也是服务注册中心的一个实现,是由go语言写的。
功能:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yyFgtomg-1621990916785)(D:/学习重要文件/B站尚硅谷教程/SpringCloud Alibaba/springcloud alibaba 周阳/images/1597380885054.png)]
Consul的下载和安装
官网下载
Consul不同于Eureka需要单独安装,访问
官网
可以下载Consul的最新版本,目前使用的是Consul 1.8.3。根据不同的操作系统类型选择不同的安装包,Consul支持所有主流操作系统。
官网安装说明
官方视频安装教程:https://learn.hashicorp.com/tutorials/consul/get-started-install
Windows系统安装
下载地址:https://www.consul.io/downloads.html
下载解压后,只有一个exe文件,实际上是不用安装的,在exe文件所在目录打开dos窗口使用即可。
使用开发模式启动:
consul agent -dev
到浏览器去访问:http://localhost:8500
这样就安装配置完成了。
Linux系统安装
下载Consul
# 从官网下载consul
wget https://releases.hashicorp.com/consul/1.8.4/consul_1.8.4_linux_amd64.zip
# 使用unzip命令解压
unzip consul_1.8.4_linux_amd64.zip
# 将解压好的consul可执行命令赋值到/usr/local/bin目录下
cp consul /usr/local/bin
# 测试一下
consul
启动Consul
# 以开发者模式快速启动,-client指定客户端可以访问的IP地址
consul agent -dev -client=0.0.0.0
启动之后,自测访问 http://localhost:8500 即可以看到Consul的管理界面
docker安装consul
可以使用容器技术docker安装,拉取镜像,具体自行查询百度,网上教程很多。
Consul的基本使用
Consul支持健康检查,并提供了HTTP和DNS调用的
API接口
来完成服务的注册,服务发现以及KV存储这些功能。
例如在VMWare中的Linux的IP地址是192.168.32.100。
服务注册和发现
注册服务
通过postman发送PUT请求到 http://192.168.32.100:8500/v1/catalog/register 地址可以完成服务注册。
{
"Datacenter": "dc1",
"Node": "node01",
"Address": "192.168.1.57",
"Service": {
"ID": "mysql-01",
"Service": "mysql",
"tags": [
"master",
"v1"
],
"Address": "192.168.1.57",
"Port": 3306
}
}
服务查询
通过postman发送GET请求到 http://192.168.32.100:8500/v1/catalog/services 地址获取所有的服务列表。
通过postman发送GET请求到 http://192.168.32.100:8500/v1/catalog/service/mysql 获取具体的服务。
服务删除
通过postman发送PUT请求到 http://192.168.32.100:8500/v1/catalog/deregister 删除服务。
Consul的KV存储
-
可以参照Consul提供的KV存储的
API
完成基于Consul的数据存储。
含义 | 请求路径 | 请求方式 |
---|---|---|
查看key | v1/kv/:key | GET |
保存或更新 | v1/kv/:key | put |
删除 | /v1/kv/:key | DELETE |
-
key值中可以带/,可以看做是不同的目录结构。
-
value的值经过了base64编码,获取到数据后需要经过base64解码才能获取到原始值。数据不能大于521kb。
-
不同的数据中心的kv存储系统是独立的,使用dc=?参数指定。
工程搭建
提供者
新建模块
cloud-providerconsul-payment8006
POM文件
<?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>spring_cloud_atguigu_2020</artifactId>
<groupId>com.itjing.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-providerconsul-payment8006</artifactId>
<dependencies>
<!--springcloud consul server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- 引入自己定义的api通用包-->
<dependency>
<groupId>com.itjing.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--图形化-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--mybatis整合spring依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
YML文件
# 端口号
server:
port: 8006
spring:
application:
name: cloud-payment-service
# 数据源
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
cloud:
consul:
host: localhost
port: 8500
discovery: # 指定注册对外暴露的服务名称
service-name: ${spring.application.name}
主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulProviderMain8006 {
public static void main(String[] args) {
SpringApplication.run(ConsulProviderMain8006.class,args);
}
}
Controller
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@RequestMapping("/payment/consul")
public String paymentConsul() {
return "springcloud with consul: " + serverPort + "\t" + UUID.randomUUID().toString();
}
}
验证测试
首先保证 consul 是启动的,再启动 8006
访问 http://localhost:8500 查看,注册成功!
消费者
新建模块
cloud-consumerconsul-order80
POM文件
<?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>spring_cloud_atguigu_2020</artifactId>
<groupId>com.itjing.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumerconsul-order80</artifactId>
<dependencies>
<!--springcloud consul server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- 引入自己定义的api通用包-->
<dependency>
<groupId>com.itjing.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--图形化-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
YML文件
server:
port: 80
spring:
application:
name: cloud-consumer-order
# consul 注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery: # 指定注册对外暴露的服务名称
service-name: ${spring.application.name}
主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class OrderConsulMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderConsulMain80.class, args);
}
}
配置类
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //这个注解,就赋予了RestTemplate 负载均衡的能力
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Controller
@RestController
@Slf4j
public class OrderConsulController {
public static final String INVOKE_URL = "http://cloud-payment-service";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/consumer/payment/consul")
public String paymentInfo() {
String result = restTemplate.getForObject(INVOKE_URL + "/payment/consul", String.class);
return result;
}
}
验证测试
- 启动 consul
- 启动提供者 8006
- 启动消费者 80
- 访问测试
访问 http://localhost:8500 ,可以看到消费者成功注册进来。
消费者访问 http://localhost/consumer/payment/consul,测试成功!
总结
三个注册中心的异同点
组件名 | 语言 | CAP | 服务健康检查 | 对外暴露接口 | Spring Cloud 集成 |
---|---|---|---|---|---|
Eureka | Java | AP | 可配支持 | HTTP | 已集成 |
Consul | Go | CP | 支持 | HTTP/DNS | 已集成 |
Zookeeper | Java | CP | 支持 | 客户端 | 已集成 |
AP:
当网络分区出现后,为了保证可用性,系统B
可以返回旧值
,保证系统的可用性。
结论:违背了一致性C的要求,只满足可用性和分区容错,即AP
CP:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wxabxfJd-1621990916813)(D:/学习重要文件/B站尚硅谷教程/SpringCloud Alibaba/springcloud alibaba 周阳/images/1597384554249.png)]
当网络分区出现后,为了保证一致性,就必须拒接请求,否则无法保证一致性
结论:违背了可用性A的要求,只满足一致性和分区容错,即CP
Consul搭建集群
详情见文章:https://www.yuque.com/sunxiaping/yg511q/ruo5uv#904e5ea1