十、服务注册中心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 的优势:
  1. 使用 Raft 算法来保证一致性, 比复杂的 Paxos 算法更直接. 相比较而言, zookeeper 采用的是 Paxos, 而 etcd 使用的则是 Raft。
  2. 支持多数据中心,内外网的服务采用不同的端口进行监听。 多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟, 分片等情况等。 zookeeper 和 etcd 均不提供多数据中心功能的支持。
  3. 支持健康检查。 etcd 不提供此功能。
  4. 支持 http 和 dns 协议接口。 zookeeper 的集成较为复杂, etcd 只支持 http 协议。
  5. 官方提供 web 管理界面, etcd 无此功能。

综合比较, Consul 作为服务注册和配置管理的新星, 还是比较值得关注和研究的。

Consul 客户端、服务端还支持夸中心的使用,更加提高了它的高可用性。

Spring Cloud支持哪些注册中心 spring cloud注册中心有哪些_restful

10.2 Consul的调用过程

Spring Cloud支持哪些注册中心 spring cloud注册中心有哪些_restful_02

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

Spring Cloud支持哪些注册中心 spring cloud注册中心有哪些_注册中心CONSUL_03


启动成功之后访问:http://localhost:8500,可以看到 Consul 的管理界面:

Spring Cloud支持哪些注册中心 spring cloud注册中心有哪些_consul_04


此时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即可实现负载均衡。