springCloud Consul+Config示例

本文详细介绍了使用Consul进行微服务注册与发现的过程,包括Docker下载安装、服务注册、健康检查、负载均衡、配置中心等功能实现,以及常见问题解决策略。
Consul下载
docker pull consul
安装和运行
docker run -d --name consul -p 8500:8500 consul
进入容器
-- 此处需要用sh执行 因为容器是 alpine 的
docker exec -it 镜像id sh
Consul控制台
Consul服务端
  • pom.xml依赖
<dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
            <version>2.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 此处不能少 Consul健康检查需要通过Consul控制台得知 -->
        <!-- 异常如下 ClientException: Load balancer does not have available server for client: consul-provider -->
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
  • application.yml配置
server:
  port: 9081
spring:
  application:
    name: consul-provider
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}
  • ConsulProviderApplication启动类
package com.zbj.consul.provider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * ConsulProviderApplication
 *
 * @author weigang
 * @create 2019-08-10
 **/
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsulProviderApplication.class, args);
    }
}
  • ConsulProviderController提供服务
package com.zbj.consul.provider;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * ConsulProviderController
 *
 * @author weigang
 * @create 2019-08-10
 **/
@RestController
@RequestMapping("/consul/provider")
public class ConsulProviderController {

    @Value("${server.port}")
    private Integer port;

    @RequestMapping(value = "/hello", method = {RequestMethod.GET})
    public String hello(String world) {
        return "hello " + world + " " + port;
    }
}
  • 执行ConsulProviderApplication类main方法
    服务已经注册到Consul上(下图中红框中表示健康检测有问题,后面告知解决方案)
    在这里插入图片描述
Consul客户端
  • pom.xml依赖(当前只作为消费者 则actuator依赖可以不需要)
		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
            <version>2.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.1.2.RELEASE</version>
        </dependency>
  • application.yml配置
server:
  port: 9083
spring:
  application:
    name: consul-consuler
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}
        enabled: true
        #设置不需要注册到 consul 中
        register: false

# feign启用hystrix,才能熔断、降级
feign:
  hystrix:
    enabled: true
  • ConsulConsumerApplication启动类
package com.zbj.consul.consumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**
 * ConsulConsumerApplication
 *
 * @author weigang
 * @create 2019-08-10
 **/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsulConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsulConsumerApplication.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
  • ConsulConsumerController对外提供服务
package com.zbj.consul.consumer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * ConsulConsumerController
 *
 * @author weigang
 * @create 2019-08-10
 **/
@RestController
@RequestMapping("/consul/consumer")
public class ConsulConsumerController {

    @Autowired
    private HelloService helloService;

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/hello")
    public String hello(@RequestParam(defaultValue = "world", required = false) String world) {
        return helloService.hello(world);
    }

    @GetMapping("/hello2")
    public String hello2(@RequestParam(defaultValue = "world", required = false) String world) {
        return restTemplate.getForObject("http://consul-provider/consul/provider/hello?world=" + world, String.class);
    }

    /**
     * 获取所有服务
     *
     * @return
     */
    @GetMapping("/services")
    public Object services() {
        return discoveryClient.getInstances("consul-provider");
    }

    /**
     * 从所有服务中选择一个服务(轮询)
     */
    @GetMapping("/discover")
    public Object discover() {
        // 不能调用 choose() 返回null 原因-> 提供者pom.xml需要依赖actuator
        return loadBalancerClient.choose("consul-provider").getUri().toString();
    }
}
  • Service层
package com.zbj.consul.consumer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * HelloService
 *
 * @author weigang
 * @create 2019-08-10
 **/
@Component
public class HelloService {

    @Autowired
    private ConsulFeignClient consulFeignClient;

    public String hello(String world) {
        return consulFeignClient.sayHelloFromClientConsul(world);
    }
}
  • Feign客户端
package com.zbj.consul.consumer;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * ConsulFeignClient
 *
 * @author weigang
 * @create 2019-08-10
 **/
@FeignClient(value = "consul-provider", fallback = FeignClientFallBack.class)
public interface ConsulFeignClient {

    /**
     * 调用提供者服务
     * 方法没有@RequestParam注解 则抛出异常 feign.FeignException$MethodNotAllowed: status 405 reading ConsulFeignClient#sayHelloFromClientConsul(String)
     *
     * @param world
     * @return
     */
    @RequestMapping(value = "/consul/provider/hello", method = {RequestMethod.GET})
    String sayHelloFromClientConsul(@RequestParam String world);
}
  • Feign熔断器
package com.zbj.consul.consumer;

import org.springframework.stereotype.Component;

/**
 * FeignClientFallBack
 *
 * @author weigang
 * @create 2019-08-10
 **/
@Component
public class FeignClientFallBack implements ConsulFeignClient {

    @Override
    public String sayHelloFromClientConsul(String world) {
        return "hello error";
    }
}
服务注册与发现问题集锦
  • ConsulFeignClient.sayHelloFromClientConsul() 参数取消@RequestParam, 取消@FeignClient属性fallback, 如下图
    在这里插入图片描述
  • 异常描述: feign.FeignException$MethodNotAllowed: status 405 reading ConsulFeignClient#sayHelloFromClientConsul(String)
    在这里插入图片描述
    • 原因分析: 在Feign调用的时候,接收的参数需要加上@Requestparam注解
  • ConsulFeignClient类上加注解 @RequestMapping("/consul/provider")
    • 当提供者对外服务类上有注解时存在这种需求
    • 异常描述: Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map ‘com.zbj.consul.consumer.ConsulFeignClient’ method
    • 原因分析: 应用于整个提供者,再类上加某个提供者的@RequestMapping显然不合适(个人认为 勿喷)
    • 解决办法: 在FeignClient对应方法上加全路径 如下图
      在这里插入图片描述
  • 注释提供者pom.xml文件中 spring-boot-starter-actuator 依赖, 取消@FeignClient属性fallback
    • 异常描述: com.netflix.client.ClientException: Load balancer does not have available server for client: consul-provider
    • 普通解决方法 错误网上搜了很多文章,提供办法最多的是在配置文件里加入一下代码
      ribbon.eureka.enabled=false
      -- 但此处没有使用eureka
      
    • 以及如下方式 (没有测试过)
# 这个BaseRemote是加了@FeignClient注解的类
# 服务提供者的地址,不是服务注册中心的地址
BaseRemote.ribbon.listOfServers=http://localhost:8086
* 异常解析: 直说出现Load balancer does not have available server for client这个错误的情况比较多,意思是负载均衡找不到那个服务,后面跟着服务名,配置错了,某一个名字写错了都可能触发,只要让他找不到就报这个错。上述解决办法适合一部分情况,手动配置多个服务以及负载均衡策略等
* 原因分析: 无意间进入下图位置,依次进入

在这里插入图片描述
* 最终看到下图链接中有访问 /actuator/health: 404 ,则加入actuator依赖即可
在这里插入图片描述

Consul Config(服务配置中心)
此处基于consul-provider改造 pom.xml增加依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
    <version>2.1.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
  • application.yml增加环境配置
spring:
  profiles:
    active: test
  • 新建bootstrap.xml配置
spring:
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}
      #      关于spring.cloud.consul.config的配置项描述如下:
      #
      #      enabled 设置config是否启用,默认为true
      #      format 设置配置的值的格式,可以yaml和properties
      #      prefix 设置配的基本目录,比如config
      #      defaultContext 设置默认的配置,此处为应用名
      #      profileSeparator profiles配置分隔符,默认为‘,’
      #      date-key为应用配置的key名字,值为整个应用配置的字符串
      config:
        enabled: true
        format: YAML
        prefix: config
        profile-separator: ":"
        data-key: data
        default-context: ${spring.application.name}
  application:
    name: consul-provider
  • 由于要读取application.name,则将discovery配置迁到bootstrap.xml中
  • 访问K/V存储界面 即 http://localhost:8500/ui/dc1/kv 创建一条记录
    • key为 config/consul-provider:test/data
    • value如下
    # 换行不能按tab键 启动报错 
    # 最后复制项有个空格(bar:后有一个空格)
    foo:
      bar: 123123
    
  • 新建API 读取配置中心值
package com.zbj.consul.provider;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * FooBarController
 *
 * @author weigang
 * @create 2019-08-10
 **/
@RestController
// Spring Cloud Comsul Config默认就支持动态刷新,只需要在需要动态刷新的类上加上@RefreshScope注解即可
@RefreshScope
public class FooBarController {

    @Value("${foo.bar}")
    String fooBar;

    @Autowired
    private Foo foo;

    @GetMapping("/foo")
    public String foo() {
        return fooBar;
    }

    @GetMapping("/foo1")
    public String foo1() {
        return foo.getBar();
    }

    public String getFooBar() {
        return fooBar;
    }

    public void setFooBar(String fooBar) {
        this.fooBar = fooBar;
    }
}
Consul配置中心问题集锦
注意事项
  • consul支持的KV存储的Value值不能超过512KB
  • Consul的dev模式,所有数据都存储在内存中,重启Consul的时候会导致所有数据丢失,在正式的环境中,Consul的数据会持久化,数据不会丢失
源码地址
参考博文
<think>嗯,用户想了解SpringCloudConfigSpringCloudConsulConfig的功能区别和适用场景。这个问题涉及到微服务配置管理的技术选型,需要从架构设计、功能特性、适用环境等维度进行对比。先梳理两者的核心差异点。SpringCloudConfig是Spring官方推出的配置中心方案,基于Git/SVN等版本控制系统存储配置,采用客户端-服务器架构。而ConsulConfig本质上是利用Consul服务发现工具内置的KV存储功能来实现配置管理,属于多合一解决方案。注意到用户提供的引用材料很有价值。引用[1][3]提到ConsulConfig的依赖是spring-cloud-starter-consul-config,引用[2]显示原生Config需要单独部署ConfigServer并引入spring-cloud-config-server依赖。这反映出两者的部署模式差异:Config需要额外维护配置服务实例,而ConsulConfig直接利用现有Consul集群。关于动态更新能力,引用[4][5]给出了关键线索。Config需要配合SpringCloudBus和消息队列(如RabbitMQ)实现批量刷新,通过/actuator/bus-refresh端点触发;而ConsulConfig借助Consul自身的Watch机制,客户端会自动监测KV变化,但需要手动调用/actuator/refresh或配合@RefreshScope注解。这里要特别说明Consul的实时性优势——由于直接监听KV变更,理论上比Bus的广播机制更快。在配置存储方面,引用[3]明确指出Consul使用其key/value存储。而原生Config默认绑定Git仓库,这意味着它能天然获得版本历史、分支管理能力,适合需要审计追踪的场景。不过Consul也可以通过外部工具实现类似功能。用户可能还关心多环境支持。引用[5]提到Consul可以通过路径区分环境(如config/user-service,dev/data),这与Config的profile机制异曲同工。但Config的Git方案能更自然地管理不同环境的配置文件。安全方面,Consul自带ACL和令牌体系(引用[5]),而Config需要集成SpringSecurity或依赖Git仓库权限控制。如果企业已有Consul基础设施,安全性管理会更统一。最后考虑适用场景。对于已采用Consul做服务发现的系统,引入ConsulConfig能减少组件数量,简化架构。而需要严格版本控制、涉及复杂配置历史的金融类系统可能更适合Git基础的Config方案。混合使用也是选项——比如用Config管理应用配置,用Consul存储特性开关等动态参数。需要提醒用户注意运维成本。ConfigServer作为独立组件需要监控和高可用保障,而Consul集群本身具备分布式特性,但KV存储的性能可能成为瓶颈。相关问题设计要覆盖技术细节(如监听机制差异)、选型考量(如团队技能树)和高级用法(如安全集成)。特别加入性能对比问题,因为这是实际部署的关键因素。</think>以下是 Spring Cloud Config 与 Spring Cloud Consul Config 的核心功能对比及适用场景分析: --- ### **一、核心功能差异** | **特性** | **Spring Cloud Config** | **Spring Cloud Consul Config** | |------------------------|-----------------------------------------|---------------------------------------| | **配置存储** | 基于 Git/SVN/Vault/本地文件 | 基于 Consul 的 Key/Value 存储 | | **服务依赖** | 需独立部署 Config Server | 直接集成 Consul 服务发现集群 | | **动态刷新** | 需配合 Spring Cloud Bus + MQ 批量刷新 | 通过 Consul Watch 机制自动监听变更 | | **配置版本控制** | 原生支持 Git 历史版本追溯 | 需 Consul 企业版或外部工具实现 | | **安全性** | 依赖存储源权限(如 Git HTTPS/Vault) | 通过 Consul ACL 令牌控制访问 [^5] | | **高可用** | Config Server 需自行实现集群 | 依赖 Consul 原生分布式高可用 | | **环境隔离** | 通过 `{application}-{profile}.yml` 实现 | 利用 Consul Key 路径分隔(如 `/dev/`) | --- ### **二、关键组件对比** 1. **Config Server 部署** - **Config**:需独立服务,依赖 `spring-cloud-config-server` [^2]: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> ``` - **Consul Config**:**无需额外服务**,仅客户端依赖 [^1][^3]: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-config</artifactId> </dependency> ``` 2. **动态刷新机制** - **Config**:需组合 **Spring Cloud Bus**(如 RabbitMQ)广播刷新指令 [^4]: ```bash POST /actuator/bus-refresh # 触发所有客户端刷新 ``` - **Consul Config**:客户端自动监听 KV 变更,单节点刷新使用: ```bash POST /actuator/refresh # 仅刷新当前服务 [^5] ``` --- ### **三、适用场景推荐** #### **优先选择 Spring Cloud Config 当:** ✅ 需要严格的配置版本审计(如金融系统) ✅ 已有 Git 仓库作为配置基线,需复用历史流程 ✅ 配置结构复杂(如多文件嵌套),需 Git 目录管理 #### **优先选择 Consul Config 当:** ✅ 已使用 Consul 做服务发现,减少组件依赖 ✅ 需**秒级动态生效**配置(如实时调整日志级别) ✅ 追求轻量化部署,避免维护 Config Server 集群 ✅ 需要统一的安全控制(Consul ACL 集成)[^5] --- ### **四、混合使用场景** 可结合两者优势: 1. **静态配置**:存放到 Git(通过 Config Server 分发) 2. **动态参数**:存放到 Consul KV(如特性开关、实时阈值) 3. **统一刷新**:通过 `@RefreshScope` + Consul Watch 实现局部更新,避免 Bus 流量风暴。 > **示例架构**: > ```mermaid > graph LR > A[微服务] -->|拉取静态配置| B(Config Server) > A -->|监听动态配置| C(Consul KV) > C -->|变更推送| A > ``` --- ### **典型问题解答** **Q1:Consul Config 如何隔离开发/生产环境?** **A**:通过 Key 路径区分,例如: - 开发配置:`config/user-service,dev/data` - 生产配置:`config/user-service,prod/data` [^5] **Q2:Config Server 高可用如何实现?** **A**:部署多实例 + 负载均衡,后端共享 Git 仓库或启用 Config Server 集群模式。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值