zoukankan      html  css  js  c++  java
  • Spring Cloud Consul 服务注册中心

    背景:

    Netflix Eureka 2.x 官方宣告停止开发,但其实对国内的用户影响很小,一方面国内大都使用的是Eureka 1.x系列,并且官

    方也在积极维护1.x 。另一方面,Spring Cloud支持很多服务发现的软件,Eureka只是其中之一,下面是 Spring Cloud 支

    持的服务发现软件以及特性对比。

    1、常见的服务注册中心:

    • Netflix Eureka
    • Alibaba Nacos
    • HashiCorp Consul
    • Apache Zookeeper
    • CoreOS Etcd
    • CNCF CoreDNS
    特性 Eureka Nacos Consul Zookeeper
    CAP AP CP + AP CP CP
    健康检查 Client Beat TCP/HTTP/MySQL/Client Beat TCP/HTTP/gRPC/Cmd Keep Alive
    雪崩保护
    自动注销实例 支持 支持 不支持 支持
    访问协议 HTTP HTTP/DNS HTTP/DNS TCP
    监听支持z 支持 支持 支持 支持
    多数据中心 支持 支持 支持 不支持
    跨注册中心同步 不支持 支持 支持 不支持
    Spring Cloud集成 支持 支持 支持 支持

    2、Consul介绍:

    Consul是HashoCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置,与其它分布式服务注册于发现的方案

    相比,Consul的方案更"一站式",内置了服务注册于发现框架、分布式一致性协议框架、健康检查、key/value存储、多

    数据中心方案,不再需要依赖其它工具(比如Zookeeper等),使用起来也较为简单。

    Consul使用Go语言编写,因此具有天然的可移植性(支持Linux、Windows和Mac OS),安装包仅包含一个可执行文件,方

    便部署,与Docker等轻量级容器可以无缝配合。

    3、Consul特性:

    • Raft算法;
    • 服务注册与发现;
    • 健康检查;
    • Key/Value存储;
    • 多数据中心;
    • 支持http和dns协议;
    • 官方提供web管理界面;

    4、Consul角色:

    • Client:客户端,无状态,将http和dns接口请求转发给局域网内的服务端集群。

    • Server:服务端,保存配置信息,高可用集群,每个数据中心的server数量推荐为3个到5个。

    5、Consul工作原理:

    5.1、服务发现与注册:

    当服务Producer启动时,会将自己的ip/host等信息通过发送post请求告知Consul,Consul接收到Producer的注册信

    息后,每隔10s(默认)会向Producer发送一个健康检查的请求,检查Producer是否健康。

    5.2、服务调用:

    当Consumer请求Producer时,会先从Consul中拿到存储Producer服务的ip和port的临时表(temp table),从temp

    table表中任选一个Producer的ip和port,然后根据这个ip和port发送访问请求。temp table表只包含通过了健康检查

    的Producer信息,并且每隔10s(默认)更新。

    6、Consul安装:

    Eureka其实就是个Servlet程序,运行在Servlet容器中;Consul则是用go语言编写的第三方工具需要单独安装使用。

    6.1、下载:

    wget https://releases.hashicorp.com/consul/1.9.4/consul_1.9.4_linux_amd64.zip
    

    6.2、解压安装包:

    unzip consul_1.9.4_linux_amd64.zip
    

    6.3、单节点启动:

    ./consul agent -dev -client=0.0.0.0  # -dev表示开发模式运行,另外还有-server表示服务模式运行
    
    • -dev:表示以开发模式运行Consul。
    • -client:表示可以进行服务注册与拉取的客户端ip,设置成-client=0.0.0.0表示对ip不设限。

    6.4、访问consul管理后台:

    7、Consul入门案例:

    7.1、创建项目:

    我们创建聚合项目来讲解Consul,首先创建一个pom父工程:

    7.2、查看Spring Cloud支持的Spring Boot版本:

    7.3、添加依赖——pom.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <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">
        <modelVersion>4.0.0</modelVersion>
        <!-- 项目坐标位置 -->
        <groupId>org.zjg</groupId>
        <!-- 项目模块名称 -->
        <artifactId>consul-demo</artifactId>
        <!-- 项目版本名称 快照版本SNAPSHOT、正式版本RELEASE -->
        <version>1.0-SNAPSHOT</version>
    
        <!-- 继承 spring-boot-starter-parent 依赖 -->
        <!-- 使用继承方式,实现复用,符合继承的都可以被使用 -->
        <parent>
            <artifactId>spring-boot-starter-parent</artifactId>
            <groupId>org.springframework.boot</groupId>
            <version>2.4.3</version>
        </parent>
    
        <!--
             集中定义以来组件版本号,但不引入
             在子工程中用到声明的依赖时,可以不加依赖的版本号,
             这样可以统一管理工程中用到的依赖版本
         -->
        <properties>
            <spring-cloud.version>2020.0.2</spring-cloud.version>
        </properties>
    
        <!-- 项目依赖管理 父项目只是声明依赖 -->
        <dependencyManagement>
            <dependencies>
                <!-- spring cloud 依赖 -->
                <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>
    
    </project>
    

    7.4、服务提供者service-provider:

    7.4.1、创建项目:

    7.4.2、添加依赖——pom.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <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">
        <modelVersion>4.0.0</modelVersion>
        <artifactId>service-provider</artifactId>
    
        <!-- 集成父依赖 -->
        <parent>
            <artifactId>consul-demo</artifactId>
            <groupId>org.zjg</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
    
        <!-- 项目依赖 -->
        <dependencies>
    
            <!-- spring cloud consul 依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-consul-discovery</artifactId>
            </dependency>
    
            <!-- spring boot actuator 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
            <!-- spring boot web 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- lombok 依赖 -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
    
            <!-- spring boot test 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
        </dependencies>
    
    
    </project>
    

    7.4.3、配置文件——application.yml:

    server:
      port: 7070                                                 # 服务请求端口
    spring:
      application:
        name: service-provider                                   # 应用名称
      # 配置consul注册中心
      cloud:
        consul:
          host: 192.168.1.93                                     # 注册中心的访问地址
          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
            healthCheckInterval: 10s                             # 健康检查的间隔时间,默认10s
            health-check-url: http://${spring.cloud.client.ip-
                              address}:${server.port}/actuator/health
    

    7.4.4、实体类——Product.java:

    package com.zjg.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Product {
    
        private Integer id;
    
        private String productName;
    
        private Integer productNum;
    
        private Double productPrice;
    
    }
    

    7.4.5、编写服务——ProductService.java:

    package com.zjg.service;
    
    import com.zjg.pojo.Product;
    import org.springframework.stereotype.Service;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * 商品服务
     */
    
    @Service
    public class ProductService {
    
        /**
         * 查询商品列表
         */
        public List<Product> selectProductAll(){
            return Arrays.asList(
                    new Product(1,"华为手机",1,5800D),
                    new Product(2,",联想笔记本",1,6888D),
                    new Product(3,"小米平板",5,2020D)
            );
        }
    
    }
    

    7.4.6、控制层——ProductController.java:

    package com.zjg.controller;
    
    import com.zjg.pojo.Product;
    import com.zjg.service.ProductService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.List;
    
    @RestController
    @RequestMapping(value = "/product")
    public class ProductController {
    
        @Autowired
        private ProductService productService;
    
        /**
         * 查询商品列表
         */
        @GetMapping(value = "/selectProductAll")
        public List<Product> selectProductAll(){
            return productService.selectProductAll();
        }
    
    }
    

    7.4.7、启动类——ServiceProviderApplication.java:

    package com.zjg;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class ServiceProviderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ServiceProviderApplication.class, args);
        }
    
    }
    

    7.4.8、访问:

    7.5、服务消费者service-consumer:

    7.5.1、创建项目:

    7.5.2、添加依赖——pom.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <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">
        <modelVersion>4.0.0</modelVersion>
        <artifactId>service-consumer</artifactId>
    
        <!-- 集成父依赖 -->
        <parent>
            <artifactId>consul-demo</artifactId>
            <groupId>org.zjg</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
    
        <!-- 项目依赖 -->
        <dependencies>
    
            <!-- spring cloud consul 依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-consul-discovery</artifactId>
            </dependency>
    
            <!-- spring boot actuator 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
            <!-- spring boot web 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- lombok 依赖 -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
    
            <!-- spring boot test 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
        </dependencies>
    
    
    </project>
    

    7.5.3、配置文件——application.yml:

    server:
      port: 7080                                                 # 服务请求端口
    spring:
      application:
        name: service-consumer                                   # 应用名称
      # 配置consul注册中心
      cloud:
        consul:
          host: 192.168.1.93                                     # 注册中心的访问地址
          port: 8500                                             # 注册中心的访问端口
          # 服务提供者信息(将自身注册到服务注册中心)
          discovery:
            register: false                                      # 是否需要注册
    

    7.5.4、实体类——Order.java:

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

    7.5.5、编写服务——OrderService.java:

    package com.zjg.service;
    
    import com.zjg.pojo.Order;
    import com.zjg.pojo.Product;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.ParameterizedTypeReference;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    import java.util.List;
    
    /**
     * 订单服务
     */
    
    @Service
    public class OrderService {
    
        @Autowired
        private RestTemplate restTemplate;
    
        /**
         * 根据主键查询订单
         */
        public Order selectOrderById(Integer id){
            return new Order(id,"order-001","中国",22788D,
                    selectProductByLoadBalancerAnnotation());
        }
    
        /**
         * 通过RestTemplate调用Consul服务注册中心的service-provider服务
        */
        private List<Product> selectProductByLoadBalancerAnnotation(){
            ResponseEntity<List<Product>> response = restTemplate.exchange(
                    "http://service-provider/product/selectProductAll",
                    HttpMethod.GET,
                    null,
                    new ParameterizedTypeReference<List<Product>>() {
                    });
            return response.getBody();
        }
    
    }
    

    7.5.6、控制层——ProductController.java:

    package com.zjg.controller;
    
    import com.zjg.pojo.Order;
    import com.zjg.service.OrderService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping(value = "/order")
    public class OrderController {
    
        @Autowired
        private OrderService orderService;
    
        /**
         * 根据主键查询订单
         */
        @GetMapping(value = "/{id}")
        public Order selectOrderById(@PathVariable(value = "id") Integer id){
            return orderService.selectOrderById(id);
        }
    
    }
    

    7.5.7、启动类——ServiceConsumerApplication.java:

    package com.zjg;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class ServiceConsumerApplication {
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
      
        public static void main(String[] args) {
            SpringApplication.run(ServiceConsumerApplication.class, args);
        }
    
    }
    

    Spring并不会自动注入RestTemplate,如果要使用RestTemplate需要通过@Bean注解手动注入。

    7.5.8、访问:

    8、Consul集群:

    上图是一个简单的Consul Cluster架构,Consul Cluster有Server和Client两种角色,无论是Server还是Client,统称为

    Agent,Consul Client是相对无状态的,只负责转发RPC到Consul Server,所以Client资源开销很少。Consul

    Server是一个有一组扩展功能的代理,这些功能包括参与Raft选举、维护集群状态、响应RPC查询,与其他数据中心交互

    WAN Gossip、转发查询给Leader或者远程数据中心。

    每个数据中心,Client和Server是混合的。一般建议有3~5台Server。这事基于有故障情况下的可用性和性能之间的权衡结

    果,因为越多的机器加入达成共识越慢,Server之间会选举出一个Leader。然而并不限制Client的数量,一般建议一个微

    服务对应一个Client,他们可以很容易的扩展到成千上万台,在开发时我们绑定一组服务注册中心中的客户端即可。

    8.1、环境准备:

    服务器IP Consul类型 Node节点
    192.168.1.94 server consul-server-01
    192.168.1.95 server consul-server-02
    192.168.1.96 server consul-server-03
    192.168.1.97 client consul-client-01

    8.2、将下载的安装包上传到各服务器:

    scp consul root@192.168.1.94:/usr/local/dev/consul/
    scp consul root@192.168.1.95:/usr/local/dev/consul/
    scp consul root@192.168.1.96:/usr/local/dev/consul/
    scp consul root@192.168.1.97:/usr/local/dev/consul/
    

    8.3、解压安装包文件:

    yum install -y unzip
    unzip consul_1.9.4_linux_amd64.zip -d /usr/local/dev/consul/    # 解压到consul目录
    

    8.4、创建Consul工作目录:

    mkdir -p /usr/local/dev/consul/data
    

    8.5、启动Consul Server端:

    # consul-server-01
    ./consul agent -server -bind=192.168.1.94 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/dev/consul/data/ -node=consul-server-01
    # consul-server-02
    ./consul agent -server -bind=192.168.1.95 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/dev/consul/data/ -node=consul-server-02
    # consul-server-03
    ./consul agent -server -bind=192.168.1.96 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/dev/consul/data/ -node=consul-server-03
    

    参数含义如下:

    • -server:表示以服务模式启动。
    • -bind:表示绑定到哪个ip。
    • -client:表示指定客户端的ip,0.0.0.0表示不限客户端ip,放行所有客户端ip访问。
    • -ui:表示开启web界面访问。
    • -bootstrap-expect=3:表示server集群最低节点数为3,低于这个值集群将不能正常工作()。
    • -data-dir:表示指定数据的存放目录(该目录必须存在,需提前创建好)。
    • -node:表示节点名称。

    8.6、启动consul Client端:

    ./consul agent -client=0.0.0.0 -bind=192.168.1.97 -data-dir=/usr/local/dev/consul/data/ -node=consul-client-01
    

    8.7、关联集群:

    # 在consul-server-02、consul-server-03、consul-client-01节点下分别执行以下命令
    ./consul join 192.168.1.94
    

    8.8、查看集群状态:

    ./consul members
    

    8.9、访问集群中的任意节点:

  • 相关阅读:
    Socket原理与编程基础
    Hello cnblogs
    c# List 分页问题
    chrome下载Word失败问题
    前端时间Date显示问题踩坑
    Vue跳转同一界面多次,使用不同数据进行渲染
    Hadoop在Linux环境下的配置
    RabbitMQ下载安装
    Codeforces 527 C. Glass Carving
    python压缩、解压文件
  • 原文地址:https://www.cnblogs.com/xiaoshuzhagen/p/14673811.html
Copyright © 2011-2022 走看看