一、前言
在微服务领域,服务注册与发现是其中很重要的一个模块,主要用于服务治理问题;在分布式Dubbo
中常用的服务发现与注册中心是Zookeeper
,Cosul
与其类似,在SpringCloud
刚占领市场的时候,SpringCloud
微服务框架默认使用的注册中心组建是Eureka
,总所周知,Eureka
已经开始闭源了,那么可以替代Eureka
的有:Consul
、Zookeeper
,这两种比较常用,同样可以很好的与SpringCloud
集成,用于替代Eureka
,本篇就主要实现SpringCloud
整合Consul
实现服务注册与发现。
二、Consul是什么
Consul
是一个支持多数据中心分布式高可用的服务发现和配置共享的服务软件,采用 Go 语言
开发。Consul
内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value
存储、多数据中心方案。由于出现得晚些,Consul
具有功能完善、部署简单、使用方便等特点。
1. 使用Consul 的优势
- 使用 Raft 算法来保证一致性, 比 ZooKeeper 的 Paxos 算法更简单直接。
- 支持多数据中心,内外网的服务采用不同的端口进行监听。 ZooKeeper 和 etcd 均不提供多数据中心功能的- 支持。
- 支持健康检查,etcd 不提供此功能。
- 支持 http 和 dns 协议接口。ZooKeeper 的集成较为复杂,etcd 只支持 http 协议。
- 官方提供 web 管理界面,etcd 无此功能。
- Consul 1.2 新增 Service Mesh 解决方案。
2. Consul默认支持Ribbon负载均衡
三、Consul的安装
1. 下载安装
Consul
由Go
语言开发,因此也继承了Go
语言跨平台,易安装的特点,支持Windwos
、Linux
、macOS
,解压即可运行使用;以Windwos
为例,去官网下载: https://www.consul.io/downloads.html , 解压后只有一个.exe文件。
2. 运行Consul
a. 启动Consul命令:
consul agent -dev -ui -node=cy
-dev
开发服务器模式启动,-node
结点名为cy
,-ui
可以用界面访问,默认能访问。
b. 起始访问地址:
访问地址: http://localhost:8500
四、实现思路
启动Consul
后,创建两个基于Consul
的客户端服务工程,一个服务提供者和一个服务消费者,使用Feign
进行服务消费,客户端配置连接运行的Consul
服务,这里先贴一下项目完整结构图;
五、搭建服务提供者springcloud-consul-provider
1.引入pom依赖
<!--SpringBoot依赖版本-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/>
</parent>
<!--项目编码、jdk版本、SpringCloud版本定义-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<!--声明管理SpringCloud版本依赖信息-->
<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>
<dependencies>
<!-- SpringBootWeb组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--springcloud整合consul组件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- 引入Feign接口公共层-->
<!--<dependency>-->
<!--<groupId>com.thinkingcao</groupId>-->
<!--<artifactId>springcloud-feign-interface</artifactId>-->
<!--<version>0.0.1-SNAPSHOT</version>-->
<!--</dependency>-->
</dependencies>
<!--maven插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2. 启动类上加@EnableDiscoveryClient
注解
package com.thinkingcao.api;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class AppMemerProvider {
public static void main(String[] args) {
SpringApplication.run(AppMemerProvider.class, args);
}
}
3. @EnableDiscoveryClient 与@EnableEurekaClient区别
@EnableDiscoveryClient
注解是基于spring-cloud-commons
依赖,并且在classpath
中实现; 适合于consul
、zookeeper
注册中心@EnableEurekaClient
注解是基于spring-cloud-netflix
依赖,只能为eureka
作用;
4. 修改application.yml
##=========服务生产者-会员服务配置========
##服务在7777端口暴露出来
server:
port: 8764
##配置Spring相关
spring:
##应用服务名称,切记不能为下划线consul_member_provider,因为Feign不支持
application:
name: consul-member-provider
##consul注册中心地址
cloud:
consul:
##Consul所在主机ip
host: localhost
##Consul监听的端口
port: 8500
discovery:
##配置开启服务注册到Consul上
register: true
##配置注册到Consul的服务实例名称(Consul里Feign是通过此名称调用,而非spring.application.name)
service-name: member-provider
##配置服务健康检查地址,供Consul调用
healthCheckPath: /health
##Consul 健康检查频率
healthCheckInterval: 15s
5. 提供会员接口ApiConsulMemberController
package com.thinkingcao.api.controller;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @desc: 服务生产者(会员服务)
* @author: cao_wencao
* @date: 2020-02-22 23:44
*/
@RestController
public class ApiConsulMemberController {
@Value("${server.port}")
private String serverPort;
@RequestMapping(value="/getMember", method = RequestMethod.GET)
private String getMember(@RequestParam("userName") String userName){
return "我是会员服务,订单服务调用会员服务成功啦, 姓名为: " + userName + ", 端口为: " + serverPort;
}
}
6. Consul健康检查接口HealthCheckController
package com.thinkingcao.api.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @desc: 提供给Consul健康检查的controller
* @auth: cao_wencao
* @date: 2020/2/23 0:08
*/
@RestController
public class HealthCheckController {
//RequestMapping中的url地址需和配置文件中保持一致
@RequestMapping("/health")
public String healthCheck() {
return "ok";
}
}
7. 启动会员服务
启动springcloud-consul-provider项目,会发现项目实例 member-provider 注册到了 consul 中
六、搭建服务消费者springcloud-feign-consumer
1.引入pom依赖
<!--SpringBoot依赖版本-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.thinkingcao</groupId>
<artifactId>springcloud-feign-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springcloud-feign-consumer</name>
<description>SpringCloud整合Feign客户端组件消费服务</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<!--声明管理SpringCloud版本依赖信息-->
<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>
<dependencies>
<!-- SpringBootWeb组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- springcloud整合Feign客户端组件 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 引入Feign接口公共层-->
<!--<dependency>-->
<!--<groupId>com.thinkingcao</groupId>-->
<!--<artifactId>springcloud-feign-interface</artifactId>-->
<!--<version>0.0.1-SNAPSHOT</version>-->
<!--</dependency>-->
<!--springcloud整合consul组件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- 健康检查 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--lombok代码简化工具-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2. 启动类添加注解
在启动类添加
@EnableFeignClients
和@EnableDiscoveryClient
注解,表示启用Feign
客户端调用和Consul
服务注册与发现功能package com.thinkingcao.api;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication @EnableFeignClients @EnableDiscoveryClient public class AppOrderConsumer {
public static void main(String[] args) { SpringApplication.run(AppOrderConsumer.class, args); }
}
3. 编辑application.yml
##=========服务消费者-订单服务配置========
#服务端口号
server:
port: 8787
##配置Spring相关
spring:
##服务名称
application:
name: consul-order_consumer
##consul注册中心地址
cloud:
consul:
##Consul所在主机ip
host: localhost
##Consul监听的端口
port: 8500
discovery:
##配置注册到Consul的服务实例名称(Consul里Feign是通过此名称调用,而非spring.application.name)
service-name: order-consumer
##配置服务健康检查地址,供Consul调用
healthCheckPath: /health
##Consul 健康检查频率
healthCheckInterval: 15s
4. 定义 Feign 接口IFeignClientService
定义
Feign
接口时,其中@FeignClient
的value
是provide
注册在consul
中的服务名。RequestMapping
对应provider
的具体映射。package com.thinkingcao.api.Feign;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam;
/**
- @desc: Feign声明式客户端调用工具
- @author: cao_wencao
- @date: 2020-02-22 12:23
*/ @FeignClient(value = "member-provider") public interface IFeignClientService {
//通过userId查询会员信息数据 @RequestMapping("/getMember") public String getOrderToMemberInfo(@RequestParam("userName") String userName);
}
5. 定义Controller调用Feign接口
package com.thinkingcao.api.controller;
import com.thinkingcao.api.Feign.IFeignClientService;
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.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @desc: 服务消费者(订单服务)
* @author: cao_wencao
* @date: 2020-02-22 12:30
*/
@RestController
public class ApiFeignOrderController {
@Autowired
private LoadBalancerClient loadBalancerClient;
@Autowired
private DiscoveryClient discoveryClient;
// @Autowired
// private OrderService orderService;
@Autowired(required = false)
private IFeignClientService feignClientService;
//基于Feign实现订单调用会员 ,并且实现本地负载均衡
@RequestMapping(value ="/getMemberInfo",method = RequestMethod.GET)
public String getMemberInfo(@RequestParam("userName") String userName) {
String memberInfo = feignClientService.getOrderToMemberInfo(userName);
return memberInfo;
}
/**
* 获取服务实例
*/
@RequestMapping(value = "/discover",method = RequestMethod.GET)
public String discover(){
String instance = loadBalancerClient.choose("member-provider").getUri().toString();
return instance;
}
/**
* 获取所有服务
*/
@RequestMapping("/services")
public Object services() {
return discoveryClient.getInstances("member-provider");
}
}
6. Consul健康检查接口HealthCheckController
package com.thinkingcao.api.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @desc: 提供给Consul健康检查的controller
* @auth: cao_wencao
* @date: 2020/2/23 0:08
*/
@RestController
public class HealthCheckController {
//RequestMapping中的url地址需和配置文件中保持一致
@RequestMapping("/health")
public String healthCheck() {
return "ok";
}
}
7. 启动订单服务
启动springcloud-feign-consumer项目,会发现项目实例 order-consumer注册到了 consul 中,这时候有两个服务都注册其中
七、测试
实现订单调用会员服务接口,为了测试Feign+Ribbon+Cosul
实现负载均衡效果,需要启动两个会员提供者服务实例;启动会员服务两个实例后,稍等片刻。
这是浏览器交替显示结果:
我是会员服务,订单服务调用会员服务成功啦, 姓名为: “Thinkingcao”, 端口为: 8764
我是会员服务,订单服务调用会员服务成功啦, 姓名为: “Thinkingcao”, 端口为: 8765
- 访问接口: http://127.0.0.1:8787/services ,获取服务列表信息
八、项目源码
1. 项目源码: https://github.com/Thinkingcao/SpringCloudLearning/tree/master/springcloud-consul
七、SpringCloud系列教程
1.Spring Cloud系列教程(七): Spring Cloud系列教程(七):服务注册与发现ZooKeeper(Finchley版本)
SpringCloud教程汇总: Spring Cloud系列教程(汇总篇):专栏汇总篇(持续更新中)
本文同步分享在 博客“Thinkingcao”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。