十、服务注册中心Consul
在 Spring Cloud 体系中,几乎每个角色都会有两个及以上的产品来提供选择。比如微服务注册中心有:Eureka、Consul、zookeeper、etcd 等;网关的产品有 Zuul、Spring Cloud Gateway 等。在注册中心产品中,最常使用的就是 Eureka 和 Consul,两者各有特点,我们可以根据自述项目情况来选择。
前面我们已经学习了如何使用eureka注册中心来进行服务注册和服务发现,这篇文章主要就是讲述另一个微服务注册中心Consul。
10.1 Consul的概述
-
什么是Consul?
Consul 是 HashiCorp 公司推出的开源产品,用于实现分布式系统的服务发现、服务隔离、服务配置,这些功能中的每一个都可以根据需要单独使用,也可以同时使用所有功能。Consul 官网目前主要推 Consul 在服务网格中的使用。
与其它分布式服务注册与发现的方案相比,Consul 的方案更“一站式”——内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,不再需要依赖其它工具。Consul 本身使用 go 语言开发,具有跨平台、运行高效等特点,也非常方便和 Docker 配合使用。
-
Consul 的优势:
- 使用 Raft 算法来保证一致性, 比复杂的 Paxos 算法更直接. 相比较而言, zookeeper 采用的是 Paxos, 而 etcd 使用的则是 Raft。
- 支持多数据中心,内外网的服务采用不同的端口进行监听。 多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟, 分片等情况等。 zookeeper 和 etcd 均不提供多数据中心功能的支持。
- 支持健康检查。 etcd 不提供此功能。
- 支持 http 和 dns 协议接口。 zookeeper 的集成较为复杂, etcd 只支持 http 协议。
- 官方提供 web 管理界面, etcd 无此功能。
综合比较, Consul 作为服务注册和配置管理的新星, 还是比较值得关注和研究的。
Consul 客户端、服务端还支持夸中心的使用,更加提高了它的高可用性。
10.2 Consul的调用过程
1、当 Producer 启动的时候,会向 Consul 发送一个 post 请求,告诉 Consul 自己的 IP 和 Port;
2、Consul 接收到 Producer 的注册后,每隔 10s(默认)会向 Producer 发送一个健康检查的请求,检验 Producer 是否健康;
3、当 Consumer 发送 GET 方式请求 /api/address 到 Producer 时,会先从 Consul 中拿到一个存储服务 IP 和 Port 的临时表,从表中拿到 Producer 的 IP 和 Port 后再发送 GET 方式请求 /api/address;
4、该临时表每隔 10s 会更新,只包含有通过了健康检查的 Producer。
Spring Cloud Consul 项目是针对 Consul 的服务治理实现。Consul 是一个分布式高可用的系统,它包含多个组件,但是作为一个整体,在微服务架构中,为我们的基础设施提供服务发现和服务配置的工具。
10.3 安装Consul
与eureka不同,Consul是用go语言来编写的,因此必须安装后才可以使用。
打开Consul官网可以查看不同系统的版本,根据不同的系统类型选择不同的安装包, Consul 支持所有主流系统,大家根据自己电脑系统选择合适的版本进行下载即可。
-
下载解压
下载后是一个压缩包(这里以windows版本为例),自行解压即可:
-
启动Consul
win+R进入解压目录,输入命令启动:
consul agent -dev -client=0.0.0.0
启动成功之后访问:http://localhost:8500,可以看到 Consul 的管理界面:
此时Consul就已经安装成功啦!
10.4 基于Consul注册中心的服务注册与发现
-
Consul服务端(服务注册)
引入Consul相关依赖:pom.xml
<!--SpringCloud提供的基于Consul的服务发现--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <!--actuator用于心跳检查--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
配置文件application.yml
server: port: 9011 #端口号 spring: application: name: ebuy-product #服务名称 datasource: driver-class-name: com.mysql.jdbc.Driver #mysql驱动 url: jdbc:mysql://127.0.0.1:3306/ebuy?useUnicode=true&characterEncoding=utf8 username: root #连接数据库用户名 password: root #连接数据库密码 #配置consul cloud: consul: host: 127.0.0.1 #ConsulServer请求地址 port: 8500 #ConsulServer端口号(默认8500) discovery: register: true #是否注册 instance-id: ${spring.application.name}-2 #实例id service-name: ${spring.application.name} #服务实例的名称 port: ${server.port} #服务实例的端口号 health-check-path: /actuator/health #健康检查路径 health-check-interval: 15s #健康检查时间间隔(默认10s) prefer-agent-address: true #开启ip地址注册 ip-address: ${spring.cloud.client.ip-address} #当前微服务请求的ip mybatis: type-aliases-package: cn.ebuy.product.pojo #实体类映射 mapper-locations: cn/ebuy/product/mapper/*.xml #mybatis扫描xml文件地址 logging: level: cn.ebuy: DEBUG
-
Consul客户端(服务发现)
引入Consul相关依赖:pom.xml
<!--SpringCloud提供的基于Consul的服务发现--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <!--actuator用于心跳检查--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
配置文件application.yml
server: port: 9021 #端口 spring: application: name: ebuy-order #服务名称 #配置consul cloud: consul: host: 127.0.0.1 #ConsulServer请求地址 port: 8500 #ConsulServer端口号(默认8500) discovery: register: true #是否注册 instance-id: ${spring.application.name}-1 #实例id service-name: ${spring.application.name} #服务实例的名称 port: ${server.port} #服务实例的端口号 health-check-path: /actuator/health #健康检查路径 health-check-interval: 15s #健康检查时间间隔(默认10s) prefer-agent-address: true #开启ip地址注册 ip-address: ${spring.cloud.client.ip-address} #当前微服务请求的ip logging: level: cn.ebuy: DEBUG ##需要调用的微服务名称 ebuy-product: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载均衡策略
Controller.java
package cn.ebuy.order.controller; import cn.ebuy.order.pojo.EasybuyProduct; import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import java.util.List; @RestController @RequestMapping("/order") @SuppressWarnings("all") public class OrderController { @Autowired RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; /** * 这里的地址是没有做集群时的写法,只有一个地址 * @param id * @return */ @RequestMapping(value = "/{id}",method = RequestMethod.GET) public EasybuyProduct findById(@PathVariable Long id) { EasybuyProduct easybuyProduct=new EasybuyProduct(); // 这里是调用product里的服务,端口号是:9011 // easybuyProduct=restTemplate.getForObject("http://127.0.0.1:9011/product/"+id,EasybuyProduct.class); // 这里直接调用负载均衡策略上配置的需要调用的微服务名称 easybuyProduct = restTemplate.getForObject("http://ebuy-product/product/"+id,EasybuyProduct.class); return easybuyProduct; }
注:使用Consul注册中心进行服务注册和服务发现时,只是yml配置文件中需要做Consul的相关配置,在Controller层调用时,与eureka的调用完全相同。
同时,Consul 依赖已经包含了 Ribbon,所以无需导入 Ribbon即可实现负载均衡。