在上个月咱们知道 Eureka 2.X 遇到困难中止开发了,但其实对国内的用户影响甚小,一方面国内大都使用的是 Eureka 1.X 系列,另外一方面 Spring Cloud 支持不少服务发现的软件,Eureka 只是其中之一,下面是 Spring Cloud 支持的服务发现软件以及特性对比:html
Feature | euerka | Consul | zookeeper | etcd |
---|---|---|---|---|
服务健康检查 | 可配支持 | 服务状态,内存,硬盘等 | (弱)长链接,keepalive | 链接心跳 |
多数据中心 | — | 支持 | — | — |
kv 存储服务 | — | 支持 | 支持 | 支持 |
一致性 | — | raft | paxos | raft |
cap | ap | ca | cp | cp |
使用接口(多语言能力) | http(sidecar) | 支持 http 和 dns | 客户端 | http/grpc |
watch 支持 | 支持 long polling/大部分增量 | 全量/支持long polling | 支持 | 支持 long polling |
自身监控 | metrics | metrics | — | metrics |
安全 | — | acl /https | acl | https 支持(弱) |
spring cloud 集成 | 已支持 | 已支持 | 已支持 | 已支持 |
在以上服务发现的软件中,Euerka 和 Consul 使用最为普遍。若是你们对注册中心的概念和 Euerka 不太了解的话, 能够参考我前期的文章:springcloud(二):注册中心Eureka ,本篇文章主要给你们介绍 Spring Cloud Consul 的使用。java
Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其它分布式服务注册与发现的方案,Consul 的方案更“一站式”,内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,再也不须要依赖其它工具(好比 ZooKeeper 等)。使用起来也较 为简单。Consul 使用 Go 语言编写,所以具备自然可移植性(支持Linux、windows和Mac OS X);安装包仅包含一个可执行文件,方便部署,与 Docker 等轻量级容器可无缝配合。ios
Consul 的优点:git
特性:github
Consul 角色web
Consul 客户端、服务端还支持夸中心的使用,更加提升了它的高可用性。算法
Consul 工做原理:spring
Spring Cloud Consul 项目是针对 Consul 的服务治理实现。Consul 是一个分布式高可用的系统,它包含多个组件,可是做为一个总体,在微服务架构中为咱们的基础设施提供服务发现和服务配置的工具。windows
Eureka 是一个服务发现工具。该体系结构主要是客户端/服务器,每一个数据中心有一组 Eureka 服务器,一般每一个可用区域一个。一般 Eureka 的客户使用嵌入式 SDK 来注册和发现服务。对于非本地集成的客户,官方提供的 Eureka 一些 REST 操做 API,其它语言可使用这些 API 来实现对 Eureka Server 的操做从而实现一个非 jvm 语言的 Eureka Client。api
Eureka 提供了一个弱一致的服务视图,尽量的提供服务可用性。当客户端向服务器注册时,该服务器将尝试复制到其它服务器,但不提供保证复制完成。服务注册的生存时间(TTL)较短,要求客户端对服务器心跳检测。不健康的服务或节点中止心跳,致使它们超时并从注册表中删除。服务发现能够路由到注册的任何服务,因为心跳检测机制有时间间隔,可能会致使部分服务不可用。这个简化的模型容许简单的群集管理和高可扩展性。
Consul 提供了一些列特性,包括更丰富的健康检查,键值对存储以及多数据中心。Consul 须要每一个数据中心都有一套服务,以及每一个客户端的 agent,相似于使用像 Ribbon 这样的服务。Consul agent 容许大多数应用程序成为 Consul 不知情者,经过配置文件执行服务注册并经过 DNS 或负载平衡器 sidecars 发现。
Consul 提供强大的一致性保证,由于服务器使用 Raft 协议复制状态 。Consul 支持丰富的健康检查,包括 TCP,HTTP,Nagios / Sensu 兼容脚本或基于 Eureka 的 TTL。客户端节点参与基于 Gossip 协议的健康检查,该检查分发健康检查工做,而不像集中式心跳检测那样成为可扩展性挑战。发现请求被路由到选举出来的 leader,这使他们默认状况下强一致性。容许客户端过期读取取使任何服务器处理他们的请求,从而实现像 Eureka 这样的线性可伸缩性。
Consul 强烈的一致性意味着它能够做为领导选举和集群协调的锁定服务。Eureka 不提供相似的保证,而且一般须要为须要执行协调或具备更强一致性需求的服务运行 ZooKeeper。
Consul 提供了支持面向服务的体系结构所需的一系列功能。这包括服务发现,还包括丰富的运行情况检查,锁定,密钥/值,多数据中心联合,事件系统和 ACL。Consul 和 consul-template 和 envconsul 等工具生态系统都试图尽可能减小集成所需的应用程序更改,以免须要经过 SDK 进行本地集成。Eureka 是一个更大的 Netflix OSS 套件的一部分,该套件预计应用程序相对均匀且紧密集成。所以 Eureka 只解决了一小部分问题,能够和 ZooKeeper 等其它工具能够一块儿使用。
Consul 强一致性(C)带来的是:
服务注册相比 Eureka 会稍慢一些。由于 Consul 的 raft 协议要求必须过半数的节点都写入成功才认为注册成功 Leader 挂掉时,从新选举期间整个 Consul 不可用。保证了强一致性但牺牲了可用性。
Eureka 保证高可用(A)和最终一致性:
服务注册相对要快,由于不须要等注册信息 replicate 到其它节点,也不保证注册信息是否 replicate 成功 当数据出现不一致时,虽然 A, B 上的注册信息不彻底相同,但每一个 Eureka 节点依然可以正常对外提供服务,这会出现查询服务信息时若是请求 A 查不到,但请求 B 就能查到。如此保证了可用性但牺牲了一致性。
其它方面,eureka 就是个 servlet 程序,跑在 servlet 容器中; Consul 则是 go 编写而成。
Consul 不一样于 Eureka 须要单独安装,访问Consul 官网下载 Consul 的最新版本,我这里是 consul_1.2.1。
根据不一样的系统类型选择不一样的安装包,从下图也能够看出 Consul 支持全部主流系统。
我这里以 Windows 为例,下载下来是一个 consul_1.2.1_windows_amd64.zip 的压缩包,解压是是一个 consul.exe 的执行文件。
cd 到对应的目录下,使用 cmd 启动 Consul
cd D:\Common Files\consul
#cmd启动:
consul agent -dev # -dev表示开发模式运行,另外还有-server表示服务模式运行
复制代码
为了方便期间,能够在同级目录下建立一个 run.bat 脚原本启动,脚本内容以下:
consul agent -dev
pause
复制代码
启动结果以下:
启动成功以后访问:http://localhost:8500
,能够看到 Consul 的管理界面
这样就意味着咱们的 Consul 服务启动成功了。
接下来咱们开发 Consul 的服务端,咱们建立一个 spring-cloud-consul-producer 项目
依赖包以下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
复制代码
spring-boot-starter-actuator
健康检查依赖于此包。spring-cloud-starter-consul-discovery
Spring Cloud Consul 的支持。Spring Boot 版本使用的是 2.0.3.RELEASE,Spring Cloud 最新版本是 Finchley.RELEASE 依赖于 Spring Boot 2.x.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<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>
复制代码
完整的 pom.xml 文件你们能够参考示例源码。
配置文件内容以下
spring.application.name=spring-cloud-consul-producer
server.port=8501
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
#注册到consul的服务名称
spring.cloud.consul.discovery.serviceName=service-producer
复制代码
Consul 的地址和端口号默认是 localhost:8500 ,若是不是这个地址能够自行配置。 spring.cloud.consul.discovery.serviceName
是指注册到 Consul 的服务名称,后期客户端会根据这个名称来进行服务调用。
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsulProducerApplication.class, args);
}
}
复制代码
添加了 @EnableDiscoveryClient
注解表示支持服务发现。
咱们在建立一个 Controller,推文提供 hello 的服务。
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "helle consul";
}
}
复制代码
为了模拟注册均衡负载复制一份上面的项目重命名为 spring-cloud-consul-producer-2 ,修改对应的端口为 8502,修改 hello 方法的返回值为:"helle consul two",修改完成后依次启动两个项目。
这时候咱们再次在浏览器访问地址:http://localhost:8500,显示以下:
咱们发现页面多了 service-producer 服务,点击进去后页面显示有两个服务提供者:
这样服务提供者就准备好了。
咱们建立一个 spring-cloud-consul-consumer 项目,pom 文件和上面示例保持一致。
配置文件内容以下
spring.application.name=spring-cloud-consul-consumer
server.port=8503
spring.cloud.consul.host=127.0.0.1
spring.cloud.consul.port=8500
#设置不须要注册到 consul 中
spring.cloud.consul.discovery.register=false
复制代码
客户端能够设置注册到 Consul 中,也能够不注册到 Consul 注册中心中,根据咱们的业务来选择,只须要在使用服务时经过 Consul 对外提供的接口获取服务信息便可。
@SpringBootApplication
public class ConsulConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsulConsumerApplication.class, args);
}
}
复制代码
咱们先来建立一个 ServiceController ,试试若是去获取 Consul 中的服务。
@RestController
public class ServiceController {
@Autowired
private LoadBalancerClient loadBalancer;
@Autowired
private DiscoveryClient discoveryClient;
/** * 获取全部服务 */
@RequestMapping("/services")
public Object services() {
return discoveryClient.getInstances("service-producer");
}
/** * 从全部服务中选择一个服务(轮询) */
@RequestMapping("/discover")
public Object discover() {
return loadBalancer.choose("service-producer").getUri().toString();
}
}
复制代码
Controller 中有俩个方法,一个是获取全部服务名为service-producer
的服务信息并返回到页面,一个是随机从服务名为service-producer
的服务中获取一个并返回到页面。
添加完 ServiceController 以后咱们启动项目,访问地址:http://localhost:8503/services
,返回:
[{"serviceId":"service-producer","host":"windows10.microdone.cn","port":8501,"secure":false,"metadata":{"secure":"false"},"uri":"http://windows10.microdone.cn:8501","scheme":null},{"serviceId":"service-producer","host":"windows10.microdone.cn","port":8502,"secure":false,"metadata":{"secure":"false"},"uri":"http://windows10.microdone.cn:8502","scheme":null}]
复制代码
发现咱们刚才建立的端口为 8501 和 8502 的两个服务端都存在。
屡次访问地址:http://localhost:8503/discover
,页面会交替返回下面信息:
http://windows10.microdone.cn:8501
http://windows10.microdone.cn:8502
...
复制代码
说明 8501 和 8501 的两个服务会交替出现,从而实现了获取服务端地址的均衡负载。
大多数状况下咱们但愿使用均衡负载的形式去获取服务端提供的服务,所以使用第二种方法来模拟调用服务端提供的 hello 方法。
建立 CallHelloController :
@RestController
public class CallHelloController {
@Autowired
private LoadBalancerClient loadBalancer;
@RequestMapping("/call")
public String call() {
ServiceInstance serviceInstance = loadBalancer.choose("service-producer");
System.out.println("服务地址:" + serviceInstance.getUri());
System.out.println("服务名称:" + serviceInstance.getServiceId());
String callServiceResult = new RestTemplate().getForObject(serviceInstance.getUri().toString() + "/hello", String.class);
System.out.println(callServiceResult);
return callServiceResult;
}
}
复制代码
使用 RestTemplate 进行远程调用。添加完以后重启 spring-cloud-consul-consumer 项目。在浏览器中访问地址:http://localhost:8503/call
,依次返回结果以下:
helle consul
helle consul two
...
复制代码
说明咱们已经成功的调用了 Consul 服务端提供的服务,而且实现了服务端的均衡负载功能。经过今天的实践咱们发现 Consul 提供的服务发现易用、强大。