由于eureka2.x停止维护了,当前spring cloud eureka使用的eureka 1.9.8,所以对当前一些spring cloud系统影响不大,但是spring cloud发展迅速,更新频率低或停更的组件注定会被淘汰。当然也有其他组件可以作为spring cloud注册中心,比如:Consul,Zookeeper,Kubernetes(k8s)。
Eureka与Consul最大的区别在于CAP:
- Eureka是AP,强调可用性,尽可能的提供服务,不需要等注册信息 replicate 到其它节点,也不保证注册信息是否replicate成功当数据出现不一致时,虽然 A, B 上的注册信息不完全相同,但每个 Eureka节点依然能够正常对外提供服务,这会出现查询服务信息时如果请求 A 查不到,但请求 B 就能查到。如此保证了可用性但牺牲了一致性。
- Consul则是CP,强调一致性,服务注册相比 Eureka 会稍慢一些,Consul的raft协议要求必须过半数的节点都写入成功才认为注册成功 Leader 挂掉时,重新选举期间整个 Consul不可用。保证了强一致性但牺牲了可用性。
一、consul下载、安装、启动
下载地址:https://www.consul.io/downloads.html
单机启动命令:
consul agent -dev
可对端口进行修改:
{
“ports” : {
“dns” : 8600,
“http” : 8500,
“https” : -1,
“grpc” : -1,
“serf_lan” : 8301,
“serf_wan” : 8302,
“server” : 8300
}
}
指定配置文件目录启动:会自动加载配置目录下的json文件
consul agent -dev -config-dir=D:\software\consul\config
常用启动参数:
consul agent -server 表示以服务器模式启动代理。
-bootstrap-expect=3 表示节点个数为3个。
-node=consul-server-1 表示节点名称
-client=0.0.0.0 表示客户端 IP
-bind=10.0.0.1 表示服务端 IP
-datacenter=dc1 数据中心名称
-data-dir=/opt/consul 表示临时数据存储路径
-retry-join “10.0.0.1:8301” 加入集群,端口对用serf_lan
二、服务注册
1. 创建consul_producer工程,pom.xml引入consul,actuator用于心跳健康检查
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.kevin</groupId>
<artifactId>consul_producer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consul_producer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. application.properties
spring.application.name=consulProducer
server.port=9105
# consul地址
spring.cloud.consul.host=localhost
# consul端口
spring.cloud.consul.port=8500
# 服务注册到consul中的服务名,用于消费
spring.cloud.consul.discovery.serviceName=consulProducerName
3. ConsulProducerApplication.java开启服务发现
package com.kevin.consul_producer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsulProducerApplication.class, args);
}
}
4. HelloController.java提供接口服务
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Value("${server.port}")
private Integer serverPort;
@RequestMapping("/sayHello")
public String sayHello(){
return "Hello consul, " + serverPort;
}
}
5. 启动两个服务,端口分别为9106和9106,查看consul ui,发现服务已成功注册
三、服务消费
1. 创建consul_consumer工程,pom.xml引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
2. application.properties
spring.application.name=consulConsumer
server.port=9210
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
# 不注册服务
spring.cloud.consul.discovery.register=false
3. ConsulConsumerApplication.java
package com.kevin.consul_consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class ConsulConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsulConsumerApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
4. 调用服务HelloController.java
package com.kevin.consul_consumer.controller;
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;
import org.springframework.web.client.RestTemplate;
@RestController
public class HelloController {
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private LoadBalancerClient loadBalancer;
@Autowired
private RestTemplate restTemplate;
// 通过服务名查询所有的服务信息
@RequestMapping("/getProducer")
public Object getProducer(){
return discoveryClient.getInstances("consulProducerName");
}
// 通过服务名查询一个服务地址
@RequestMapping("/getProducerUrl")
public String getProducerUrl(){
return loadBalancer.choose("consulProducerName").getUri().toString();
}
// 调用服务
@RequestMapping("/sayHello")
public String sayHello(){
return restTemplate.getForObject("http://consulProducerName/sayHello", String.class);
}
}
5. 启动测试
1)访问 http://127.0.0.1:9210/getProducer
2) 访问http://127.0.0.1:9210/getProducerUrl 会自动负载均衡
3)访问http://127.0.0.1:9210/sayHello 会自动负载均衡
四、使用Feign消费
1. pom.xml引入feign
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. 启动Feign
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ConsulConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsulConsumerApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
3. 使用Feign调用远程服务
package com.kevin.consul_consumer.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(name="consulProducerName")
public interface HelloFeignService {
@RequestMapping(value = "/sayHello")
public String sayHello();
}
4. 对外接口
@RestController
public class HelloController {
@Autowired
private HelloFeignService helloFeignService;
@RequestMapping("/sayHelloFeign")
public String sayHelloFeign(){
return helloFeignService.sayHello() + ", call by feign";
}
}
5. 测试http://127.0.0.1:9210/sayHelloFeign
多次请求返回:
Hello consul, 9105, call by feign
Hello consul, 9106, call by feign
参考:
https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/multi/multi_spring-cloud-consul-discovery.html
http://www.ityouknow.com/springcloud/2018/07/20/spring-cloud-consul.html