专栏首页架构进阶微服务注册中心:Consul——服务发现
原创

微服务注册中心:Consul——服务发现

系列文章:

微服务注册中心:Consul——概念与基础操作

微服务注册中心:Consul——服务注册

公众号:程序员架构进阶

一 概述

说完了Consul的服务注册,那么就该到服务发现了。大家有过rpc框架使用经验的,例如nacos、eureka、dubbo等,就会了解服务中的角色,也就是生产者和消费者,也可以理解为服务的提供方和服务使用方。服务注册,是服务提供方把自己的信息(ip、端口、方法、参数&返回值信息)注册到一个中心;服务发现就是服务使用方,从中心获取到可用的服务提供方信息,并像本地方法调用一样调用其方法(远程方法),这也就是RPC(远程方法调用)的过程。

二 Consul宏观架构

这里先说一下consul的架构,Consul的宏观架构如下图所示:

其中"DATACENTER1"和 “DATACENTER2”代表两个数据中心(Consul对多数据中心天然有比较好的支持)。

在每个数据中心内有ClientServer的混合。通常我们会部署3~5台Server。具体数量由可用性性能之间取得平衡,因为随着机器的增加,共识的速度会逐渐变慢。不过对Client的数量通常没有限制,可以轻松地扩展到数千或数万的量级。

所有在数据中心的代理都会参与一个Gossip协议,这意味着有一个Gossip池,其中包含了某个数据中心的所有Agent。这有几个目的:

  • 第一,客户端不需要配置Server的地址,发现工作是自动完成的。
  • 第二,检测代理故障的工作不放在Server上,而是分布式的。这使得故障检测的扩展性比原生的心跳方案要强得多。同时,它还为节点提供了故障检测,如果代理无法到达,那么该节点可能已经发生了故障。
  • 第三,它被用作消息层,当发生重要事件(如Leader 选举)时进行通知。

每个数据中心的Server都是单一Raft对等集的一部分。这意味着它们共同选出一个单一的Leader,一个被选中的Server,它有额外的职责。Leader负责处理所有查询和事务。事务也必须复制到所有参与共识协议的分片。由于这一要求,当None-Leader Server收到RPC请求时,它会将其转发给集群Leader。

一般情况下,不同的Consul数据中心之间不会复制数据。当对另一个数据中心的资源进行请求时,本地Consul服务器会将该资源的RPC请求转发给远程Consul服务器,并返回结果。如果远程数据中心不可用,那么这些资源也将不可用,但这不会以其他方式影响本地数据中心。

三 Consul服务发现

3.1 Consul已注册服务查看

大概了解了Consul的架构,接下来回到本篇的主题,我们先搞清楚怎样获取到已注册的服务,来供调用。

如果还不了解服务注册怎样实现,大家先再看一下这篇文章:微服务注册中心:Consul——服务注册,可以直接拉取gitee代码到本地,本地启动Consul服务后,再启动springboot-consul下的SpringBootConsulApplication,即可完成注册。注意一下consul服务端口,默认使用的是8500。

如果上述操作完成且没有问题,那么我们在浏览器中查看http://localhost:8500/,可以看到Consul下的Services信息如下:

会有两个Service,一个是consul——这个是Consul服务启动后就有的,自带的service; 下面的first-consul-client就是我们启动并注册的服务。

3.2 建立消费者工程

3.2.1 创建工程

创建一个名为springboot-consul-consumer的maven工程。

3.2.2 依赖配置

主要是spring-cloud,spring boot,以及spring-cloud-starter-consul-discovery,用于做consul的服务发现。pom.xml内容如下:

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <project.version>1.0.0</project.version>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.RELEASE</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-netflix-hystrix-dashboard</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-openfeign</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>

3.2.3 application属性配置

这里尝试使用application.yml,zipkin不是必须,所以暂时注释掉:

server:
  port: 8521
spring:
  application:
    name: spring-cloud-consul-consumer
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        serviceName: ${spring.application.name}	# 注册到consul的服务名称
  #  zipkin:
  #    base-url: http://localhost:9411/
  sleuth:
    sampler:
      probability: 1 #样本采集量,默认为0.1,为了测试这里修改为1,正式环境一般使用默认值
#ribbon 负载均衡策略配置, service-producer为注册的服务名
service-producer:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
#开启熔断器
feign:
  hystrix:
    enabled: true

3.2.4 核心代码

1)必不可少的启动文件ConsulConsumerApplication:

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class ConsulConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsulConsumerApplication.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    // 此配置是为了服务监控而配置,与服务容错本身无关,
    // ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
    // 只要在自己的项目里配置上下面的servlet就可以了
    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }

}

2)访问服务方法

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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ServiceController {

    @Autowired
    private LoadBalancerClient loadBalancerClient;
    @Autowired
    private DiscoveryClient discoveryClient;

    private String serviceId = "first-consul-client";

   /**
     * 获取所有服务
     */
    @RequestMapping("/services")
    public Object services() {
        return discoveryClient.getInstances(serviceId);
    }

    /**
     * 从所有服务中选择一个服务(轮询)
     */
    @RequestMapping("/discover")
    public Object discover() {
        return loadBalancerClient.choose(serviceId).getUri().toString();
    }
}

至此,工程建立完毕。可见,核心逻辑还是在引入的依赖包spring-cloud-starter-consul-discovery中。consul服务配置在了application.yml中的consul属性,controller中通过设置的serviceId来定位我们要使用的服务。

3.3 启动验证

启动ConsulConsumerApplication,完成后,通过/services来验证是否能够获取到服务列表,浏览器中输入: http://localhost:8521/services,返回信息为:

可见确实得到了预期的结果。

再次查看Consul的ui页面(http://localhost:8500/ui/dc1/services):

标红的就是我们刚刚启动的消费者,也注册到了Consul的services列表中。

上述代码已提交至gitee: https://gitee.com/flamingskyline/spring-boot-integration,可自行拉取并做调整。

四 小结

至此,我们从本地安装启动Consul,到服务注册和发现,可以简单的使用起来了,但还是非常简单的应用,并未深入到原理和架构,后面的文章中,将会对其原理进行分析,敬请期待。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 微服务注册中心:Consul——服务注册

    微服务注册中心:Consul——概念与基础操作介绍了consul的安装和基本操作,本篇开始在consul上进行服务注册与发现,语言使用Java,框架使用Spri...

    程序员架构进阶
  • 服务注册/发现-consul

    当系统的数量越来越多的时候,提供的各种系统接口基本都写在配置文件之中,从而在进行接口升级的时候,关联的系统总是要进行同步升级。。。强耦合了解一下,在程序的世界...

    SRE运维实践
  • .Net Core with 微服务 - Consul 注册中心

    上一次我们介绍了 Ocelot 网关的基本用法。这次我们开始介绍服务注册发现组件 Consul 的简单使用方法。

    kklldog
  • 微服务之Consul服务自动注册

    如果是主动退出服务,会执行取消注册的方法,好处是比心跳响应更快,但是心跳也是必不可少的,因为在微服务中,各种网络原因都有可能导致服务异常中断。

    用户2295386
  • [翻译]微服务设计模式 - 6. 服务发现 - 服务注册中心

    访问一个服务的客户端使用客户端服务发现或者服务端服务发现确定一个服务实例的位置并发送请求给这个实例调用所需服务。

    干货满满张哈希
  • ZooKeeper、Eureka、Consul 、Nacos微服务注册中心对比

    服务注册中心本质上是为了解耦服务提供者和服务消费者。对于任何一个微服务,原则上都应存在或者支持多个提供者,这是由微服务的分布式属性决定的。更进一步,为了支持弹性...

    IT大咖说
  • Consul初探-服务注册和发现

    经过上一篇的学习,现在已经来到了服务注册发现环节;Consul 的核心功能就是服务注册和发现,Consul 客户端通过将自己注册到 Consul 服务器集群,然...

    梁规晓
  • 闲聊微服务之服务注册中心

    服务,提供什么服务,有的叫服务中心,有的叫注册中心,有的叫服务注册中心,表达的都是同一个意思。

    SRE运维实践
  • 微服务注册中心:Consul——概念与基础操作

    好久不见。由于工作的原因停更了一段时间,今天开始继续更新。前面介绍过微服务相关的一些技术方案,注册中心除了 Zookeeper、Nacos 之外,其实 Cons...

    程序员架构进阶

扫码关注云+社区

领取腾讯云代金券