Consul服务注册中心

486 阅读6分钟

Consul 介绍

Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其它分布 式服务注册与发现的方案,Consul 的方案更“一站式”,内置了服务注册与发现框架、分布式一致性协议 实现、健康检查、Key/Value 存储(配置中心)、多数据中心方案,不再需要依赖其它工具(比如 ZooKeeper 等),使用起来也较为简单。

Consul 使用 Go 语言编写,因此具有天然可移植性(支持Linux、Windows 和 Mac OS);安装包 仅包含一个可执行文件,方便部署,与 Docker 等轻量级容器可无缝配合。

Consul 特性

  • 服务发现: 解决在分布式环境中,如何找到可用的服务地址的问题,支持通过DNS和HTTP查询服务地址。

  • 健康检查:定时监控服务是否正常,对于异常的服务会主动下线。

  • 键值存储:配置中心解决方案,是一种key/valjue存储结构,区别就是key是以目录结构形式组织的,可以用来存储系统配置信息。

  • 多数据中心:支持多数据中心部署。

Consul 角色

  • client:客户端,无状态,将 HTTP 和 DNS 接口请求转发给局域网内的服务端集群。
  • server:服务端,保存配置信息,高可用集群,每个数据中心的 server 数量推荐为 3 个或者 5 个。

首先,图中有两个数据中心,分别为 Datacenter1 和 Datacenter2 。Consul 非常好的支持多个数 据中心,每个数据中心内,有客户端和服务器端,服务器一般为 3~5 个,这样可以在稳定和性能上达到 平衡,因为更多的机器会使数据同步很慢。不过客户端是没有限制的,可以有成千上万个。

数据中心内的所有节点都会加入到 Gossip (流言)协议。这就意味着有一个 Gossip 池,其中包含这 个数据中心所有的节点。客户端不需要去配置服务器地址信息,发现服务工作会自动完成。检测故障节 点的工作不是放在服务器端,而是分布式的;这使得失败检测相对于本地化的心跳机制而言,更具可拓 展性。在选择 leader 这种重要的事情发生的时候,数据中心被用作消息层来做消息广播。

每个数据中心内的服务器都是单个 Raft 中节点集的一部分。这意味着他们一起工作,选择一个单一 的领导者——一个具有额外职责的选定的服务器。leader 负责处理所有查询和事物。事物也必须作为同 步协议的一部分复制到节点集中的所有节点。由于这个要求,当非 leader 服务器接收到 RPC 请求时, 就会将请求其转发给集群 leader。

服务器端节点同时也作为 WAN Gossip 池的一部分,WAN 池和 LAN 池不同的是,它针对网络高延 迟做了优化,而且只包含其他Consul 服务器的节点。这个池的目的是允许数据中心以最少的消耗方式发 现对方。启动新的数据中心与加入现有的 WAN Gossip 一样简单。因为这些服务器都在这个池中运行, 它还支持跨数据中心请求。当服务器收到对不同数据中心的请求时,它会将其转发到正确数据中心中的 随机服务器。那个服务器可能会转发给本地的 leader。

Consul工作原理

服务发现以及注册

当服务 Producer 启动时,会将自己的 Ip/host 等信息通过发送请求告知 Consul,Consul 接收到 Producer 的注册信息后,每隔 10s(默认)会向 Producer 发送一个健康检查的请求,检验 Producer 是否健康。

服务调用

当 Consumer 请求 Product 时,会先从 Consul 中拿到存储 Product 服务的 IP 和 Port 的临时表 (temp table),从temp table 表中任选一个· Producer 的 IP 和 Port, 然后根据这个 IP 和 Port,发送访 问请求;temp table 表只包含通过了健康检查的 Producer 信息,并且每隔 10s(默认)更新。

Consul安装

www.consul.io/

Consul单节点

单节点windows CMD启动Consul

consul agent -dev -client=0.0.0.0

Consul案例

服务提供者 service-provider

application.yml

server:
  port: 7070 # 端口
spring:
  application:
    name: service-provider # 应用名称
  cloud:
  # 配置 Consul 注册中心
    consul:
    # 注册中心的访问地址
      host: localhost
      port: 8500
    # 服务发现相关配置
      discovery:
        register: true # 是否需要注册
        instance-id: ${spring.application.name}-01 # 注册实例 id(必须唯一)
        service-name: ${spring.application.name} # 服务名称
        port: ${server.port} # 服务端口
        prefer-ip-address: true # 是否使用 ip 地址注册
        ip-address: ${spring.cloud.client.ip-address} # 服务请求 ip

实体类

Product.java

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Product implements Serializable {

    private Integer id;
    private String productName;
    private Integer productNum;
    private Double productPrice;

}

service

ProductService.java

public interface ProductService {

    /**
    * 查询商品列表
    * @return
    */
    List<Product> selectProductList();

}

impl

ProductServiceImpl.java

    @Service
    public class ProductServiceImpl implements ProductService {
        @Override
        public List<Product> selectProductList() {
            return Arrays.asList(
                new Product(1, "华为手机", 1, 5800D),
                new Product(2, "联想笔记本", 1, 6888D),
                new Product(3, "小米平板", 5, 2020D)
            );
        }
    }

controller层

ProductController.java

@RestController
@RequestMapping("/product")
public class ProductController {
    @Autowired
    private ProductService productService;
    /**
    * 查询商品列表
    *
    * @return
    */
    @GetMapping("/list")
    public List<Product> selectProductList() {
        return productService.selectProductList();
    }
}

访问

服务消费者 service-consumer

配置文件同provider

实体类

Product.java

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Product implements Serializable {
    private Integer id;
    private String productName;
    private Integer productNum;
    private Double productPrice;
}

Order.java

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order implements Serializable {
    private Integer id;
    private String orderNo;
    private String orderAddress;
    private Double totalPrice;
    private List<Product> productList;
}

Service层

OrderService.java

public interface OrderService {

    /**
    * 根据主键查询订单
    * @param id
    * @return
    */
    Order selectOrderById(Integer id);

}

impl

OrderServiceImpl.java

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private RestTemplate restTemplate;

    /**
    * 根据主键查询订单
    * @param id
    * @return
    */
    @Override
    public Order selectOrderById(Integer id) {
        return new Order(id, "order-001", "中国", 22788D,
                         selectProductListByLoadBalancerAnnotation());
    }

    private List<Product> selectProductListByLoadBalancerAnnotation() {
        // ResponseEntity: 封装了返回数据
        ResponseEntity<List<Product>> response = restTemplate.exchange(
            "http://service-provider/product/list",
            HttpMethod.GET,
            null,
            new ParameterizedTypeReference<List<Product>>() {
            });
        return response.getBody();
    }
}

controller层

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private OrderService orderService;
    /**
    * 根据主键查询订单
    * @param id
    * @return
    */
    @GetMapping("/{id}")
    public Order selectOrderById(@PathVariable("id") Integer id) {
        return orderService.selectOrderById(id);
    }
}

访问

Consul集群

安装

将安装包上传到Linux,再解压安装

yum -y install unzip # 安装 
unzip mkdir -p /usr/local/consul # 创建 consul 目录 
unzip consul_1.7.0_linux_amd64.zip -d /usr/local/consul/ # 解压至 consul 目录 
mkdir -p /usr/local/consul/data # 创建 consul 数据目录

注册中心服务端

mkdir -p /usr/local/consul/data/ ## 创建数据目录

# node-01
./consul agent -server -bind=192.168.10.11 -client=0.0.0.0 -ui -bootstrapexpect=3 -data-dir=/usr/local/consul/data/ -node=server-01
# node-02
./consul agent -server -bind=192.168.10.12 -client=0.0.0.0 -ui -bootstrapexpect=3 -data-dir=/usr/local/consul/data/ -node=server-02
# node-03
/consul agent -server -bind=192.168.10.13 -client=0.0.0.0 -ui -bootstrapexpect=3 -data-dir=/usr/local/consul/data/ -node=server-03

参数含义:

  • -server :以服务端身份启动(注册中心)
  • -bind :表示绑定到哪个 ip
  • -client :指定客户端访问的 ip,0.0.0.0 表示不限客户端 ip
  • -ui :开启 web 界面访问
  • -bootstrap-expect=3 :表示 server 集群最低节点数为 3,低于这个值将工作不正常(注:类似 ZooKeeper一样,通常集群数为奇数方便选举,Consul 采用的是 Raft 算法)
  • -data-dir :表示指定数据的存放目录(该目录必须存在,需提前创建好)
  • -node :表示节点在 web ui 中显示的名称

注册中心客户端

consul agent -client=0.0.0.0 -bind=192.168.10.1 -data-dir=D:\yjxxt\consol\data - node=client-01

关联集群

在 server-02 和 server-03 和 client-01 节点中输入以下命令建立集群关系

./consul join 192.168.10.11

集群状态

./consul members