Consul 初步实现服务注册发现,配置中心,负载均衡

Posted dobqop

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Consul 初步实现服务注册发现,配置中心,负载均衡相关的知识,希望对你有一定的参考价值。

一、简述Consul 实现服务注册发现,配置中心,负载均衡

  • 环境搭建

    • consul 版本:1.4.0

    • Spring Boot: 2.0.5.RELEASE

    • Spring Cloud: Finchley.SR2

    • 数据库:H2

    • 虚拟机搭建(这里我使用了三个虚拟机来模拟):centos 2 * X + 1 台

    • 搭建步骤省略,在这里只专注于代码层面描述,大家参考网络上的文档

  • 构建两个Spring Boot应用:

    • 部署在三台consul虚拟机(服务器)上,应用启动时,注册到consul中

    • 通过ConsulConfig统一管理应用配置

    • 服务提供者:cloud-consul-producer

    • 服务消费者:cloud-consul-consumer *在本机启动,用于测试服务发现和负载均衡

  • Spring官方文档介绍:

    • Service Discovery: instances can be registered with the Consul agent and clients can discover the instances using Spring-managed beans

    • Supports Ribbon, the client side load-balancer via Spring Cloud Netflix

    • Supports Zuul, a dynamic router and filter via Spring Cloud Netflix

    • Distributed Configuration: using the Consul Key/Value store

    • Control Bus: Distributed control events using Consul Events

    • URL:https://spring.io/projects/spring-cloud-consul

    • Spring Cloud Consul features:

二、服务提供者 cloud-consul-producer

  • 依赖:

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-consul-discovery</artifactId>
            </dependency>
  • 多个服务提供者实现一个服务,系统为客户端提供多个实现,并把他们从多个实现中解耦出来。服务提供者的改变对它们的客户端是透明的,这样提供了更好的可扩展性。

  • 开启服务发现客户端

    @SpringBootApplication
    @EnableDiscoveryClient
    public class ProducerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ProducerApplication.class, args);
        }
    }
    • @EnableDiscoveryClient基于spring-cloud-commons 实现的服务发现客户端

    • 在Consul中注册了我们的应用,我们需要找到服务端,因此通过该注解来发现客户端服务来从Consul中获取可用的服务。

    • 然后,我们可以将DiscoveryClient bean注入我们的控制器并访问实例:

           @RestController
           public class DiscoveryClientController {
             
               @Autowired
               private DiscoveryClient discoveryClient;
            
               public Optional<URI> serviceUrl() {
                   return discoveryClient.getInstances("myApp")
                     .stream()
                     .map(si -> si.getUri())
                     .findFirst();
               }
           } 
      
  • 相关配置(此处仅用于介绍,后面我们通过ConsulConfig配置中心来统一管理配置)

    spring.application.name=dobqop
    server.port=8081
    spring.cloud.consul.host=consulServiceIPAddress
    spring.cloud.consul.port=8500
    #注册到consul的服务名称 服务生产者
    spring.cloud.consul.discovery.serviceName=dobqop-service-producer
    # 指定实例ID,如果不指定,那么默认是:${spring.application.name}:comma,separated,profiles:${server.port}
    # 这意味着:如果没指定profile,那么多个实例的instance-id都是应⽤名称-端⼝,实例ID就会相同
    spring.cloud.consul.discovery.instance-id=${spring.application.name}:${spring.application..instance_id:${random.value}}
    # 指定健康检查路径(可使用健康检查依赖spring-boot-starter-actuator,路径默认为:/actuator/health)
    spring.cloud.consul.discovery.health-check-path=/hello
    spring.cloud.consul.discovery.health-check-interval=15s
    spring.cloud.consul.discovery.tags=foo=bar, baz
  • H2数据库配置文件(此处仅用于介绍,后面我们通过ConsulConfig配置中心来统一管理配置)

    spring:
      datasource:
        url: jdbc:h2:mem:h2test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
        platform: h2
        username: sa
        password:
        driverClassName: org.h2.Driver
      jpa:
        database-platform: org.hibernate.dialect.H2Dialect
        hibernate:
          ddl-auto: update
        properties:
          hibernate:
            show_sql: true
            use_sql_comments: true
            format_sql: true
      h2:
        console:
          enabled: true
          path: /console
          settings:
            trace: false
            web-allow-others: false
  • 用于测试的Bean

    @Entity
    @Table(name = "t_user")
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String name;
        /**
         * 用来区别在哪个应用的编号,储存时,不同服务器值要区别设置
         * 这样做用于测试负载均衡当前调用的哪个服务器
         */
        private String dsno;
    }
    @Repository
    public interface UserRepository extends JpaRepository<User, Long> {
    }
    @RestController
    @RequestMapping("/users")
    public class UserController {
    
        @Autowired
        UserRepository userRepository;
        @GetMapping("/{id}")
        public Optional<User> findById(@PathVariable Long id){
           return userRepository.findById(id);
        }
        @GetMapping("/{id}/{name}/{dsno}")
        public User save(@PathVariable Long id, @PathVariable String name, @PathVariable String dsno){
            User save = userRepository.save(new User(id, name, dsno));
            return save;
        }
        @GetMapping("all")
        public Optional<List<User>> findAll(){
    
            return Optional.ofNullable(userRepository.findAll());
        }
    }
  • 上述完成了我们的服务提供者应用构建,在应用启动时会通过配置文件中的:

    spring.cloud.consul.host=consulServiceIPAddress
    spring.cloud.consul.port=8500

来找到cousul所在的位置,并将自己注册到consul服务中,下面来介绍ConsulConfig应用配置中心,目前我只使用到了KEY/VALUE方式,git2以后有需要再去研究

ConsulConfig 应用配置中心

  • 依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-config</artifactId>
        </dependency>
  • 此功能允许在所有服务之间同步配置。Consul将监视任何配置更改,然后触发所有服务的更新。

  • 我们还需要将Consul和Spring应用程序名称的设置从application.yml文件移动到Spring首先加载的bootstrap.yml文件中。

  • 然后,我们需要启用Spring Cloud Consul Config:

      spring:
        application:
          name: dobqop
        profiles:
          active: dev
        cloud:
          consul:
            config:
              fail-fast: true
              #        enabled: true
              #        consul中的key-value中的value内容,采用YAML格式
              format: yaml
              #        表示consul用于存储配置的文件夹根目录名为config
              prefix: config
              #        表示配置文件对应的应用名称(eg: 你的服务如果打算取名为myApp,则这里的dobqop就要换成myApp)
              default-context: dobdop
              #        表示如果有多个profile(eg: 开发环境dev,测试环境test...) ,则key名中的profile与defaultContext之间,用什么分隔符来表示
              profile-separator: '-'
              #        监听配置的更改
              watch:
                enabled: true
              #        表示最后一层节点的key值名称,一般默认为data
              data-key: data
            host: 192.168.137.134
            port: 8500
  • 接下来需要在consul服务端配置KEY/VALUE

    • Spring Cloud Consul Config将默认在“/config/dobdop-dev”中查找data中的属性

    • 这是因为上面的配置文件中配置的prefix、default-context、profile-separator等相关配置决定,详见上面的配置备注

    • 如果没有*-dev则默认会查找/config/dobdop,不存在就会抛出异常,应用无法启动

    • 配置文件中的路径是'/config/dobdop-dev',KEY是‘data'。VALUE则是我们application.yml中的配置

    • 小坑:如果是手动配置Condul中的KEY/VALUE,请不要使用“TAB”键,必须使用空格来格式化配置

    • 建议先在本地配置好yml直接复制到consul中

    • 如果没有配置profile-separator则默认路径名称应该创建为:'config/dobdop,dev',默认以逗号来区分环境

  • 配置好bootstrap.yml后我们就可以通过注解的形式来加载配置中心的值

  • 更新配置

    • 使用@RefreshScope注解注释的所有bean 将在配置更改后刷新,字段属性是MyProperties类具有@RefreshScope注解

三、服务消费者&负载均衡的初步实现:cloud-consul-consumer

  • 依赖

       <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-consul-discovery</artifactId>
      </dependency>
  • 服务发现不需要注册到consul中,因此我们不需要在启动类上添加注解:@EnableDiscoveryClient

  • 同时配置文件也不需要开启服务发现:

      spring.application.name=spring-cloud-consul-consumer
      server.port=8504
      spring.cloud.consul.host=192.168.137.18
      spring.cloud.consul.port=8500
      #设置不需要注册到 consul 中
      spring.cloud.consul.discovery.register=false
      #服务提供之应用名称        
      rest.url.prefix.url=http://dobqop-consul-service-yml
  • 定义配置类

      @Configuration
      public class RibbonConfigBean {
      
          /**
           * Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具
           * @return
           */
          @LoadBalanced
          @Bean
          public RestTemplate getRestTemplate(){
              return new RestTemplate();
          }
      
          /**
           * 用随机算法代替默认的轮询
           * @return
           */
          @Bean
          public IRule myRule(){
              return new RandomRule();
          }
      
      }
  • consul中添加了Netflix 的 Ribbon等相关模块依赖,因此添加了consul的spring-cloud-starter-consul-discovery依赖后相关模块都会加载到应用中

  • RestTemplate设计是为了Spring更好的请求并解析Restful风格的接口返回值而设计的,通过这个类可以在请求接口时直接解析对应的类(来源于网络)

  • 想要通过客户端RestTemplate去访问我们的微服务时候自带负载均衡,我们需要通过注解@LoadBalanced开启负载均衡

  • 创建RestTemplate Bean时我们添加了注解@LoadBalanced只会,可以通过微服务名字从Consul上找到并访问相关服务,默认使用轮询算法

  • 自定义负载均衡算法需要我们添加IRule Bean,这里我目前只测试了随机算法,见上面的代码

  • RestTemplate使用示例:

    @RestController
    public class CallHelloController {
        @Autowired
        RestTemplate restTemplate;
    
        //我在配置文件中定义了服务提供者的名称,即:http://dobqop-consul-service-yml
        @Value("${rest.url.prefix.url}")
        private String url;
    
        @RequestMapping("users/all")
        public String call(HttpServletRequest request) {
            String callServiceResult = restTemplate.getForObject(url + request.getRequestURI(), String.class);
            System.out.println(callServiceResult);
            return callServiceResult;
        }
    
    }
  • 通过上面的代码,我们可以看到在调用服务提供者时,只需要定义URL:http://dobqop-consul-service-yml,RestTemplate组合注解@LoadBalanced实现了负载均衡

  • 以下为本次应用截图:

Consul 初步实现服务注册发现,配置中心,负载均衡

Consul 初步实现服务注册发现,配置中心,负载均衡


以上是关于Consul 初步实现服务注册发现,配置中心,负载均衡的主要内容,如果未能解决你的问题,请参考以下文章

微服务SpringCloud之注册中心Consul

(031)Spring Boot之服务的注册与发现,使用zookeeper演示负载均衡

(031)Spring Boot之服务的注册与发现,使用zookeeper演示负载均衡

springcloud(十三):注册中心 Consul 使用详解

服务注册发现配置中心集一体的 Spring Cloud Consul

服务注册发现配置中心集一体的 Spring Cloud Consul