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 初步实现服务注册发现,配置中心,负载均衡的主要内容,如果未能解决你的问题,请参考以下文章
(031)Spring Boot之服务的注册与发现,使用zookeeper演示负载均衡
(031)Spring Boot之服务的注册与发现,使用zookeeper演示负载均衡
springcloud(十三):注册中心 Consul 使用详解