原文:https://xie.infoq.cn/article/4fe6f02b220fb009844861b56
https://www.cnblogs.com/myitnews/p/13655000.html
一 概述
说完了 Consul 的服务注册,那么就该到服务发现了。大家有过 rpc 框架使用经验的,例如 nacos、eureka、dubbo 等,就会了解服务中的角色,也就是生产者和消费者,也可以理解为服务的提供方和服务使用方。服务注册,是服务提供方把自己的信息(ip、端口、方法、参数 &返回值信息)注册到一个中心;服务发现就是服务使用方,从中心获取到可用的服务提供方信息,并像本地方法调用一样调用其方法(远程方法),这也就是 RPC(远程方法调用)的过程。
二 Consul 宏观架构
这里先说一下 consul 的架构,Consul 的宏观架构如下图所示:
其中"DATACENTER1"和 “DATACENTER2”代表两个数据中心(Consul 对多数据中心天然有比较好的支持)。
在每个数据中心内有 Client 和 Server 的混合。通常我们会部署 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}
sleuth:
sampler:
probability: 1
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();
}
@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,到服务注册和发现,可以简单的使用起来了,但还是非常简单的应用,并未深入到原理和架构,后面的文章中,将会对其原理进行分析,敬请期待。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
2021-05-30 (转)MySQL 主从复制相关参数
2021-05-30 (转)MySQL学习笔记-redo log 和 binlog&两阶段提交
2018-05-30 (转)GlusterFS 01 理论基础,企业实战,故障处理
2018-05-30 (转)CentOS7.4环境下搭建--Gluster分布式集群存储
2018-05-30 (转)DB2性能优化 – 如何通过调整锁参数优化锁升级