Consul uses service identities and traditional networking practices to help organizations securely connect applications running in any environment.
1、Discover Services with Consul:服务发现,提供http和dns两种发现方式。
2、Health Monitoring with Consul:实时的健康检查
3、Observability with Consul:可视化界面
首先是下载linux版的consul:https://www.consul.io/downloads
我的系统是Ubuntu16.04,按照官网命令安装即可。
安装完成后,查看是否安装成功:consul --version
koping@koping-HP:~$ consul --version
Consul v1.11.1
Revision 2c56447e
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)
接下来使用开发模式启动:。数据是存储在内存中,重启之后数据将丢失
consul agent -dev
koping@koping-HP:~$ consul agent -dev
==> Starting Consul agent...
Version: '1.11.1'
Node ID: '9b6e4720-3b08-49a1-427e-a81fe2aa0634'
Node name: 'koping-HP'
Datacenter: 'dc1' (Segment: '' )
Server: true (Bootstrap: false)
Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, DNS: 8600)
Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)
Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false
==> Log data will now stream in as it occurs:
2022-01-13T12:18:16.880+0800 [INFO] agent.server.raft: initial configuration: index=1 servers="[{Suffrage:Voter ID:9b6e4720-3b08-49a1-427e-a81fe2aa0634 Address:127.0.0.1:8300}]"
2022-01-13T12:18:16.880+0800 [INFO] agent.server.raft: entering follower state: follower="Node at 127.0.0.1:8300 [Follower]" leader=
2022-01-13T12:18:16.880+0800 [INFO] agent.server.serf.wan: serf: EventMemberJoin: koping-HP.dc1 127.0.0.1
2022-01-13T12:18:16.881+0800 [INFO] agent.server.serf.lan: serf: EventMemberJoin: koping-HP 127.0.0.1
2022-01-13T12:18:16.881+0800 [INFO] agent.router: Initializing LAN area manager
2022-01-13T12:18:16.881+0800 [INFO] agent.server: Adding LAN server: server="koping-HP (Addr: tcp/127.0.0.1:8300) (DC: dc1)"
2022-01-13T12:18:16.881+0800 [INFO] agent: Started DNS server: address=127.0.0.1:8600 network=udp
2022-01-13T12:18:16.881+0800 [INFO] agent.server: Handled event for server in area: event=member-join server=koping-HP.dc1 area=wan
2022-01-13T12:18:16.881+0800 [WARN] agent: grpc: addrConn.createTransport failed to connect to {dc1-127.0.0.1:8300 0 koping-HP <nil>}. Err :connection error: desc = "transport: Error while dialing dial tcp 127.0.0.1:0->127.0.0.1:8300: operation was canceled". Reconnecting...
2022-01-13T12:18:16.881+0800 [INFO] agent: Started DNS server: address=127.0.0.1:8600 network=tcp
2022-01-13T12:18:16.881+0800 [INFO] agent: Starting server: address=127.0.0.1:8500 network=tcp protocol=http
2022-01-13T12:18:16.881+0800 [WARN] agent: DEPRECATED Backwards compatibility with pre-1.9 metrics enabled. These metrics will be removed in a future version of Consul. Set `telemetry { disable_compat_1.9 = true }` to disable them.
2022-01-13T12:18:16.881+0800 [INFO] agent: started state syncer
2022-01-13T12:18:16.881+0800 [INFO] agent: Consul agent running!
2022-01-13T12:18:16.881+0800 [INFO] agent: Started gRPC server: address=127.0.0.1:8502 network=tcp
2022-01-13T12:18:16.941+0800 [WARN] agent.server.raft: heartbeat timeout reached, starting election: last-leader=
2022-01-13T12:18:16.941+0800 [INFO] agent.server.raft: entering candidate state: node="Node at 127.0.0.1:8300 [Candidate]" term=2
2022-01-13T12:18:16.941+0800 [DEBUG] agent.server.raft: votes: needed=1
2022-01-13T12:18:16.941+0800 [DEBUG] agent.server.raft: vote granted: from=9b6e4720-3b08-49a1-427e-a81fe2aa0634 term=2 tally=1
2022-01-13T12:18:16.941+0800 [INFO] agent.server.raft: election won: tally=1
2022-01-13T12:18:16.941+0800 [INFO] agent.server.raft: entering leader state: leader="Node at 127.0.0.1:8300 [Leader]"
2022-01-13T12:18:16.942+0800 [INFO] agent.server: cluster leadership acquired
2022-01-13T12:18:16.942+0800 [INFO] agent.server: New leader elected: payload=koping-HP
2022-01-13T12:18:16.946+0800 [INFO] agent.leader: started routine: routine="federation state anti-entropy"
2022-01-13T12:18:16.946+0800 [INFO] agent.leader: started routine: routine="federation state pruning"
2022-01-13T12:18:16.946+0800 [DEBUG] agent.server.autopilot: autopilot is now running
2022-01-13T12:18:16.946+0800 [DEBUG] agent.server.autopilot: state update routine is now running
2022-01-13T12:18:16.947+0800 [DEBUG] connect.ca.consul: consul CA provider configured: id=fb:50:9b:45:1a:65:15:c1:68:57:73:5f:da:cd:b8:0d:0f:e2:26:eb:68:66:43:11:85:9d:67:a9:7a:56:9c:b9 is_primary=true
2022-01-13T12:18:16.949+0800 [INFO] connect.ca: initialized primary datacenter CA with provider: provider=consul
2022-01-13T12:18:16.949+0800 [INFO] agent.leader: started routine: routine="intermediate cert renew watch"
2022-01-13T12:18:16.949+0800 [INFO] agent.leader: started routine: routine="CA root pruning"
2022-01-13T12:18:16.949+0800 [INFO] agent.leader: started routine: routine="CA root expiration metric"
2022-01-13T12:18:16.949+0800 [INFO] agent.leader: started routine: routine="CA signing expiration metric"
2022-01-13T12:18:16.949+0800 [INFO] agent.leader: started routine: routine="virtual IP version check"
2022-01-13T12:18:16.949+0800 [DEBUG] agent.server: successfully established leadership: duration=7.187553ms
2022-01-13T12:18:16.949+0800 [INFO] agent.server: member joined, marking health alive: member=koping-HP partition=default
2022-01-13T12:18:16.949+0800 [DEBUG] agent.leader: stopping routine: routine="virtual IP version check"
2022-01-13T12:18:16.949+0800 [DEBUG] agent.leader: stopped routine: routine="virtual IP version check"
2022-01-13T12:18:16.964+0800 [INFO] agent.server: federation state anti-entropy synced
2022-01-13T12:18:17.138+0800 [DEBUG] agent: Skipping remote check since it is managed automatically: check=serfHealth
2022-01-13T12:18:17.139+0800 [INFO] agent: Synced node info
2022-01-13T12:18:17.139+0800 [DEBUG] agent: Node info in sync
2022-01-13T12:18:18.014+0800 [DEBUG] agent: Skipping remote check since it is managed automatically: check=serfHealth
2022-01-13T12:18:18.014+0800 [DEBUG] agent: Node info in sync
显示Consul agent running!后,再访问consul的前端界面,端口号是默认的8500:http://localhost:8500/
和之前eureka、zookeeper一样,现在需要构建服务提供者模块注册进consul中。
在cloud2021父工程下,构建cloud-provider-payment-consul-8006模块:
依赖文件参考上一节博文的zookeeper的依赖包,只是将spring-cloud-starter-zookeeper-discovery给替换为了:spring-cloud-starter-consul-discovery。
<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>cloud2021artifactId>
<groupId>org.example.springcloudgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>cloud-provider-payment-consul-8006artifactId>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-consul-discoveryartifactId>
dependency>
<dependency>
<groupId>org.example.springcloudgroupId>
<artifactId>cloud-api-commonsartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
<version>1.14.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
project>
配置文件与之前也一致,需要填写服务端口号,服务注册中心IP地址,端口号,注册服务名称等:
server.port=8006
spring.application.name=consul-provider-payment
# consul服务注册中心地址
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
spring.cloud.consul.discovery.hostname=127.0.0.1
spring.cloud.consul.discovery.service-name=${spring.application.name}
在主启动类上面还是要添加@SpringBootApplication和@EnableDiscoveryClient这2个注解。
package com.example.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8006 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8006.class, args);
}
}
业务类与上一节的zookeeper一致,只是返回consul的端口信息+一个随机UUID字符串:
package com.example.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/payment/consul")
public String paymentConsul() {
return "Spring cloud with consul: " + serverPort + "\t" + UUID.randomUUID();
}
}
启动服务提供模块的主启动类:PaymentMain8006。
启动成功后,刷新consul的监控主页面,可以看到服务提供模块已经成功注册进入consul中:
然后,通过postman调用服务接口,可以得到consul端口号和一个随机的uuid字符串结果:
在cloud2021父工程下新建服务消费模块:cloud-consumer-order-consul-80
<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>cloud2021artifactId>
<groupId>org.example.springcloudgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>cloud-consumer-order-consul-80artifactId>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-consul-discoveryartifactId>
dependency>
<dependency>
<groupId>org.example.springcloudgroupId>
<artifactId>cloud-api-commonsartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
<version>1.14.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
project>
server.port=8080
# 服务别名--注册到consul的服务名称
spring.application.name=cloud-consumer-order
# consul服务注册中心地址
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
spring.cloud.consul.discovery.hostname=127.0.0.1
spring.cloud.consul.discovery.service-name=${spring.application.name}
package com.example.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class OrderConsulMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderConsulMain80.class, args);
}
}
首先还是要配置restTemplate远程调用bean,然后调用服务提供模块得到结果:
package com.example.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
package com.example.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderConsulController {
public static final String INVOKE_URL = "http://consul-provider-payment";
@Resource
private RestTemplate restTemplate;
@GetMapping(value = "/consumer/payment/consul")
public String paymentInfo() {
String result = restTemplate.getForObject(INVOKE_URL + "/payment/consul", String.class);
return result;
}
}
启动消费服务模块,查看consul注册中心,发现已成功注册消费服务模块:
cloud-consumer-order。
其次,通过消费服务模块8080端口调用服务提供者的8006的接口,发现可以获取到服务提供者返回的数据:
在前几篇博文中,介绍了当服务宕机后,eureka会在一段时候(默认90s)之后才会移除服务,并且具有自我保护机制。而zookeeper在规定心跳时间后未收到心跳,则直接移除了。那么consul是哪种情况?
接下来,将服务提供者停掉进行测试。如下图,当服务提供者宕机后,provider服务几秒后就被移除。
经过测试可以发现,当服务不可用时,eureka很在一段时间后,才会将服务移除。而zookeeper和consul则是在心跳周期内未收到心跳就会很快移除服务。
接下来引出CAP定理:CAP定理指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可同时获得。
CAP定理提出三者不可同时获得的原因如下:
在分布式系统中(机器数量多),由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡。
因此之前博文中介绍的Eureka注册中心就属于AP,即服务明明已经不可用了,但Eureka并没有移除,而是继续返回数据,保证了服务的可用性,但是降低了数据的一致性。
而Zookeeper,Consul则属于CP,即心跳周期内检测到服务不可用了,就立刻移除服务。保证了数据一致性,但是服务可用性降低了。
Eureka,Zookeeper,Consul三者的异同点如下: