zoukankan      html  css  js  c++  java
  • Consul 多数据中心下的服务注册发现与配置共享

    1. Consul简介

      Consul是HashiCorp公司推出的开源软件,它提供了一套分布式高可用可横向扩展的解决方案,能为微服务提供服务治理、健康检查、配置共享等能力。
      Eurake2.x停止更新后,Spirng Cloud官网也推荐使用Consul实现服务注册与发现。并且可以代替Sping Cloud Config实现配置中心。
      官网:https://www.consul.io/

    2. 功能特点

    • 服务发现
        提供服务注册和服务发现的功能,通过DNS和Http获取服务信息。
    • 健康检查
        通过健康检查可以避免请求被路由到不健康的服务,并且主动断开使其不再具备服务能力。
    • 键值存储
        提供动态配置功能,通过长轮询实现配置变更的即时通知。
    • 多数据中心
        通过简单配置即可实现多数据中心,并且可以获得其他数据中心的服务。
    • UI界面
        通过界面即可获取服务信息、配置信息等其他信息。

    3. CAP原则

      CAP原则指的是在分布式系统中Consistency(一致性)、Availability(可用性)、Partition Tolerance(分区容错性)总是不能同时成立。
      一致性:它要求在任一时刻点分布式系统中的所有数据都处于同一状态。
      可用性:在系统集群的一部分节点宕机后,系统依然能够响应用户的请求。
      分区容错性:在网络区间通信出现异常系统能容错处理。
      一般来说,网络总是存在不稳定性,分区容错也总是存在的,所以默认CAP中的P总是成立的。
      一致性要求在任一时刻数据状态一致,必然需要加锁,因此不能保证可用性,反之同理。因此一致性和可用性总是互斥的。

    4. 常见服务发现与注册方案对比

    功能 Eureka Consul Zookeeper Nacos
    CAP AP CP CP CP+AP
    一致性算法 Raft Paxos Raft
    访问协议 Http Http/DNS TCP Http/DNS
    健康检查 可配支持 支持 支持 支持
    多数据中心 x 支持 x 支持
    键值存储 支持 支持 支持 支持
    雪崩保护 支持 x x 支持
    自动注销实例 支持 x 支持 支持
    监听支持 支持 支持 支持 支持
    安全性 x ACL/Https ACL ACL/Https
    SpringCloud集成 支持 支持 支持 支持
    Dubbo集成 x x 支持 支持
    K8S集成 x 支持 x 支持

      Consul采用Raft算法来保证数据的强一致性,虽然优势明显,但是也牺牲了一些特性:
      (1) 服务注册比Eureka慢。因为Consul要求必须节点数过半才认为注册成功;
      (2) Leader挂掉后,在重新选举期间,Consul将不可用,为了一致性牺牲可用性。

    5. Consul架构


      图中有两个数据中心:DATACENTER1、DATACENTER2,每个数据中心都有3个Server节点,该数量使得在故障转移和性能之间达到平衡。

    6. Consul端口说明

    端口 说明
    TCP/8300 用于服务器节点。客户端通过该端口 RPC 协议调用服务端节点。
    TCP/UDP/8301 用于单个数据中心所有节点之间的互相通信,即对 LAN 池信息的同步。它使得整个数据中心能够自动发现服务器地址,分布式检测节点故障,事件广播(如Leader选举事件)。
    TCP/UDP/8302 用于单个或多个数据中心之间的服务器节点的信息同步,即对 WAN 池信息的同步。它针对互联网的网络高延迟进行了优化,能够实现跨数据中心请求。
    8500 基于 HTTP 协议,用于 API 接口或 WEB UI 访问。
    8600 作为 DNS 服务器,通过节点名查询节点信息。

    7. Spring Cloud Consul实现服务注册发现

    创建生产者1:

    • 创建Maven项目
    • 修改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>spring-cloud-consul-producer1</artifactId>
    	<name>spring-cloud-consul-producer1</name>
    
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.2.1.RELEASE</version>
    	</parent>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    		<java.version>1.8</java.version>
    		<spring-cloud.version>Hoxton.SR5</spring-cloud.version>
    	</properties>
    
    	<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>
    
    	<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>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    
    </project>
    
    • 创建Controller
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * 业务Controller
     * 
     * @author CL
     *
     */
    @RestController
    public class BookController {
    
    	/**
    	 * 业务接口
    	 * 
    	 * @return
    	 */
    	@RequestMapping(value = "/get")
    	public String get() {
    		return "Consul-1";
    	}
    
    }
    
    • 创建启动类
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    /**
     * 启动类
     * 
     * @author CL
     *
     */
    @SpringBootApplication
    @EnableDiscoveryClient
    public class ConsulProducerApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(ConsulProducerApplication.class, args);
    	}
    
    }
    
    • 创建application.yml
    server:
      port: 9001
    
    spring:
      application:
        name: spring-cloud-consul-producer
      cloud:
        consul:
          discovery:
            serviceName: consul-producer
          host: 127.0.0.1
          port: 8500
    

    创建生产者2:

    • 创建Maven项目
    • 修改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>spring-cloud-consul-producer2</artifactId>
    	<name>spring-cloud-consul-producer2</name>
    
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.2.1.RELEASE</version>
    	</parent>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    		<java.version>1.8</java.version>
    		<spring-cloud.version>Hoxton.SR5</spring-cloud.version>
    	</properties>
    
    	<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>
    
    	<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>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    </project>
    
    • 创建Controller
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * 业务Controller
     * 
     * @author CL
     *
     */
    @RestController
    public class BookController {
    
    	/**
    	 * 业务接口
    	 * 
    	 * @return
    	 */
    	@RequestMapping(value = "/get")
    	public String get() {
    		return "Consul-2";
    	}
    
    }
    
    • 创建启动类
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.SpringCloudApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    /**
     * 启动类
     * 
     * @author CL
     *
     */
    @SpringBootApplication
    @EnableDiscoveryClient
    public class ConsulProducerApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(ConsulProducerApplication.class, args);
    	}
    
    }
    
    • 创建application.yml
    server:
      port: 9002
    
    spring:
      application:
        name: spring-cloud-consul-producer
      cloud:
        consul:
          discovery:
            serviceName: consul-producer
          host: 127.0.0.1
          port: 8500
    

    创建消费者:

    • 创建Maven项目
    • 修改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>spring-cloud-consul-consumer</artifactId>
    	<name>spring-cloud-consul-consumer</name>
    
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.2.1.RELEASE</version>
    	</parent>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    		<java.version>1.8</java.version>
    		<spring-cloud.version>Hoxton.SR5</spring-cloud.version>
    	</properties>
    
    	<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>
    
    	<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>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    
    </project>
    
    • 创建Controller
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.client.discovery.DiscoveryClient;
    import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    /**
     * 服务Controller
     * 
     * @author CL
     *
     */
    @RestController
    public class ServicesController {
    
    	@Autowired
    	private DiscoveryClient discoveryClient;
    
    	@Autowired
    	private LoadBalancerClient loadBalancerClient;
    
    	/**
    	 * 获得所以服务列表
    	 * 
    	 * @return
    	 */
    	@RequestMapping(value = "/getAllServices")
    	public List<ServiceInstance> getAllServices() {
    		return discoveryClient.getInstances("consul-producer");
    	}
    
    	/**
    	 * 获取服务Uri
    	 * 
    	 * @return
    	 */
    	@RequestMapping("/getServiceUri")
    	public String getServiceUri() {
    		return loadBalancerClient.choose("consul-producer").getUri().toString();
    	}
    
    	/**
    	 * 负载均衡调用提供者接口
    	 * 
    	 * @return
    	 */
    	@RequestMapping("/loadBalancer")
    	public String call() {
    		ServiceInstance serviceInstance = loadBalancerClient.choose("consul-producer");
    		return new RestTemplate().getForObject(serviceInstance.getUri().toString() + "/get", String.class);
    	}
    }
    
    • 创建启动类
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * 启动类
     * 
     * @author CL
     *
     */
    @SpringBootApplication
    public class ConsulConsumerApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(ConsulConsumerApplication.class, args);
    	}
    
    }
    
    • 创建application.yml
    server:
      port: 9003
    
    spring:
      application:
        name: spring-cloud-consul-consumer
      cloud:
        consul:
          discovery:
            register: false
          host: 127.0.0.1
          port: 8500
    

    部署Consul:
      Consul安装部署(Windows单机、Docker集群)
    启动项目:
      启动顺序:生产者1 -> 生产者2 -> 消费者
      访问Consul WEB UI:http://127.0.0.1:8500


    测试:

    • 获取全部服务信息
    curl http://localhost:9003/getAllServices
    
    #返回:
    
    [
        {
            "instanceId": "spring-cloud-consul-producer-9001",
            "serviceId": "consul-producer",
            "host": "192.168.0.100",
            "port": 9001,
            "secure": false,
            "metadata": {
                "secure": "false"
            },
            "uri": "http://192.168.0.100:9001",
            "scheme": null
        },
        {
            "instanceId": "spring-cloud-consul-producer-9002",
            "serviceId": "consul-producer",
            "host": "192.168.0.100",
            "port": 9002,
            "secure": false,
            "metadata": {
                "secure": "false"
            },
            "uri": "http://192.168.0.100:9002",
            "scheme": null
        }
    ]
    
    • 获取服务Uri(负载均衡)
    #第一次调用:
    curl http://localhost:9003/getServiceUri
    
    #返回:
    
    http://192.168.0.100:9001
    
    #第二次调用:
    curl http://localhost:9003/getServiceUri
    
    #返回:
    
    http://192.168.0.100:9002
    
    • 调用提供者接口(负载均衡)
    #第一次调用:
    curl http://localhost:9003/loadBalancer
    
    #返回:
    
    Consul-1
    
    #第二次调用:
    curl http://localhost:9003/loadBalancer
    
    #返回:
    
    Consul-2
    

    8. Spring Cloud Consul实配置中心

    • 创建Maven项目
    • 修改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>spring-cloud-consul-config</artifactId>
    	<name>spring-cloud-consul-config</name>
    
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.2.1.RELEASE</version>
    	</parent>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    		<java.version>1.8</java.version>
    		<spring-cloud.version>Hoxton.SR5</spring-cloud.version>
    	</properties>
    
    	<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.cloud</groupId>
    			<artifactId>spring-cloud-starter-consul-config</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>
    
    	<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>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    
    </project>
    
    • 创建application.yml
    server:
      port: 9004
    
    • 创建bootstrap.yml
        作为配置中心的相关配置必须写到bootstrap.yml
    spring:
      application:
        name: spring-cloud-consul-config
      cloud:
        consul:
          discovery:
            service-name: consul-config
          host: 127.0.0.1
          port: 8500
          config:
            # 是否启用配置中心功能
            enabled: true
            # 设置配置所在目录
            prefix: config
            # 设置应用程序使用的文件夹名称,默认application
            defaultContext: application
            # 配置key的名字,由于Consul是K/V存储,配置存储在对应K的V中,配置文件路径为:/config/application/key
            data-key: data
            # 设置配置值的格式,四种配置:YAML PROPERTIES KEY-VALUE FILES
            format: YAML
            # 设置配置的分隔符
            profile-separator: ','
    
    • 创建Controller
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * 配置Controller
     * 
     * @author CL
     *
     */
    @RestController
    @RefreshScope
    public class ConfigController {
    
    	@Value("${project-name}")
    	private String projectName;
    
    	@RequestMapping(value = "/getInfo")
    	public String getInfo() {
    		return projectName;
    	}
    
    }
    
    • 创建启动类
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    /**
     * 启动类
     * 
     * @author CL
     *
     */
    @SpringBootApplication
    @EnableDiscoveryClient
    public class ConsulConfigApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(ConsulConfigApplication.class, args);
    	}
    
    }
    
    • 创建配置
        在Consul WEB UI的Key/Value下创建配置:
    • 启动项目
    • 查看Consul WEB UI
    • 测试
    curl http://localhost:9004/getInfo
    
    #返回:
    
    spring-cloud-consul-demo
    

    9. 项目地址

      spring-cloud-consul-demo

  • 相关阅读:
    linux eclipse cdt make error 127
    centos 安装网络错误
    c++ string 结束符‘00’
    北京市工资交税情况
    gprof参数说明及常见错误
    【转】Eclipse Plugin 在 Console上打印出message
    C++做client Java做客户端传送数据
    word统计章节字数
    【转】Profiling application LLC cache misses under Linux using Perf Events
    【转】eclipse插件开发,调试运行,导出与安装
  • 原文地址:https://www.cnblogs.com/cao-lei/p/13048118.html
Copyright © 2011-2022 走看看