spring-cloud的eureka服务注册与发现的搭建
通常我们会遇到这样的问题!如:a服务如何调用b服务,就是我如何找到你?或者我如何让别人知道我?之前我们解决的办法通常是a服务持有b服务的链接,c服务想调用b服务的时候,也是c通过持有b服务的链接,等等到其他的服务,而这样的显然不够弹性,虽然b服务可以对外暴露一个通用的域名接口,但是对其的配置信息也是过于的僵硬,不能随意的修改,怎么办呢?计算机中大多数问题都可以通过加一层来解决!没错,eureka就是中间的那一层,eureka注册中心就是一个服务介绍所,你想要什么服务就来我这里,你能提供什么服务也注册到我这里,其就是用来使微服务相互知晓的桥梁。
ok,开始我们的工程搭建吧。最简单的模式,我们至少需要两个工程对吧,一个提供eureka注册中心的eureka-server工程,一个提供hello服务的hello-service工程。
eureka-server工程
关于spring-cloud与spring-boot之间有版本的对应匹配关系如下:【spring-cloud可能又有最新版了】
Finchley——>兼容Spring Boot 2.0.x,不兼容Spring Boot 1.5.x
Dalston和Edgware——>兼容Spring Boot 1.5.x,不兼容Spring Boot 2.0.x
Camden——>兼容Spring Boot 1.4.x,也兼容Spring Boot 1.5.x
Brixton——>兼容Spring Boot 1.3.x,也兼容Spring Boot 1.4.x
Angel——>兼容Spring Boot 1.2.x
我们配置的是spring-cloud-Brixton.SR5,spring-boot-1.3.7.RELEASE【具体见之后的pom.xml】
1.eurekaserver项目构建图如下:
请忽略application-peer2.properties配置文件,这是我们
构建两个节点的eureka的配置,增加了容错性,但是本文暂时不做介绍。往下继续我们的pom.xml配置。
image.png
eureka-server:pom.xml 如下:
<?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>
<groupId>cong</groupId>
<artifactId>eureka-server</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.7.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>
eureka-server:Application.java
package com.con;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String args[]){
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
eureka-server:application-peer1.properties 如下:
spring.application.name=eureka-server
server.port=1111
#实例的名字,映射ip,ip可能会变化,但是实例不变
eureka.instance.hostname=peer1
#是否注册服务
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
#关闭自身保护机制:防止关闭的实例无法被注册中心剔除的问题,如果开启:实例一段时间是受到保护,不被剔除。
eureka.server.enable-self-preservation=false
#如果不配置会报错:Network level connection to peer localhost; retrying after delay
eureka.client.service-url.defaultZone=http://peer1:1111/eureka
#java -jar target/eureka-server-1.0.jar --spring.profiles.active=peer1
# 关于:配置界面的参数
# Renew: 服务续约
# Eureka Client 会每隔 30 秒发送一次心跳来续约。
# 通过续约来告知 Eureka Server 该 Eureka Client 运行正常,没有出现问题。
# 默认情况下,如果 Eureka Server 在 90 秒内没有收到 Eureka Client 的续约,Server 端会将实例从其注册表中删除,此时间可配置,一般情况不建议更改。
#RENEWALS ARE LESSER THAN THE THRESHOLD. THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.
#RENEWALS小于阀值。自身保护模式关闭。在有网络或其他问题的时候可能不会保护到期的实例。
#Uptime 运行的时间
peer1是指映射peer1到本地ip,如果线上的话我们可能需要映射到我们的域名或者ip,能够使其他的微服务器访问到即可。
host文件添加如下:
127.0.0.1 peer1
application-peer1.properties参数说明:
1.只有一个主的注册中心服务eureka-server启动,所以eureka.client.register-with-eureka=false不需要进行注册服务。
- eureka.client.service-url.defaultZone=http://peer1:1111/eureka
是必须配置的,由于eureka也是一个注册服务,既然是一个注册的服务就需要给我发送心跳,告诉我你还活着。
以上,工程配置完成,打出jar包运行如下命令,启动工程:spring.profiles.active=peer1代表加载的是:application-peer1.properties配置文件,
$ java -jar target/eureka-server-1.0.jar --spring.profiles.active=peer1
这时我们浏览eureka注册中心界面:
http://localhost:1111/
提示:No instances available,没有任何可用的实例。正常因为我们还没有注册任何微服务呢,ok,有个红色的错误:
RENEWALS ARE LESSER THAN THE THRESHOLD. THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.
#RENEWALS小于阀值。自身保护模式关闭。在有网络或其他问题的时候可能不会保护到期的实例
啥意思?就是说你的服务没有在保护内,如果出现网络问题啦,或者其他的情况啦,你的服务会被移除掉,如果是true,就会保护其一段时间不被移除。【具体什么样的条件移除和保护,我暂时还没有检测,配置文件中是一个默认的说明】ok,开始我们的eureka-client工程。
2.eureka-client项目目录结构图: image.png
eureka-client:pom.xml文件和eureka-server的很像,添加了一个:spring-cloud-starter-eureka依赖。
<?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>
<groupId>cong</groupId>
<artifactId>eureka-client</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.7.RELEASE</version>
</parent>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependencies>
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>
eureka-client:Application.java,留意EnableEurekaClient注解配置
package com.con;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class Application {
public static void main(String args[]){
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
eureka-client:HelloController文件,提供hello接口
package com.con;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Random;
@RestController
public class HelloController {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private org.springframework.cloud.client.discovery.DiscoveryClient client;
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String index()throws Exception {
ServiceInstance instance = client.getLocalServiceInstance();
int sleepTime = new Random().nextInt(3000);
logger.info("sleepTime:"+sleepTime);
Thread.sleep(sleepTime);
logger.info("hello host:" + instance.getHost() + " service_id:" + instance.getServiceId());
return "hello world";
}
}
eureka-client:application.properties 如下:
#server.port=1111
eureka.instance.hostname=localhost
#eureka.client.register-with-eureka=false
#eureka.client.fetch-registry=false
#注册的服务名
spring.application.name=hello-service
#eureka.client.service-url.defaultZone=http://peer1:1111/eureka/,http://peer2:1112/eureka/
eureka.client.service-url.defaultZone=http://peer1:1111/eureka/
#java -jar target/eureka-client-1.0.jar --server.port=8081
#java -jar target/eureka-client-1.0.jar --server.port=8082
#服务注册与提供者
#用来模块化,形成微服务的
以上,eukera-client配置完成,启动eukera-client工程,我们以8081端口启动,也可以在配置文件中配置。
$ java -jar target/eureka-client-1.0.jar --server.port=8081
注册中心界面:http://localhost:1111/ 显示了我们的hello-service,这说明我们的hello服务注册成功了!
我们接着请求:http://localhost:8081/hello
image.png
有结果了,但这还不够,我们直接访问了hello接口,其他服务如何调用呢?不能直接访问吧,那又回到了原始社会了。ok,我们来配置消费者服务调用hello服务。
3.消费者服务:ribbon-consumer项目目录结构图:
image.pngribbon-consumer:pom.xml
<?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>
<groupId>ribbon-consumer</groupId>
<artifactId>ribbon-consumer</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.7.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</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-ribbon</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<!--短容器><groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
</dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>
ribbon-consumer:application.properties
spring.application.name=ribbon-consumer
server.port=9000
eureka.client.service-url.defaultZone=http://peer1:1111/eureka/
#hello-service.ribbon.NFLoadBalancerPingClassName=com.netflix.loadbalancer.PingUrl
#java -jar target/ribbon-consumer-1.0.jar
ribbon-consumer:ConsumerApplication.java如下:
Ribbon是一个负载均衡方式的调用服务,通过其调用者可以通过负载均衡的方式来调用注册的微服务。
package com.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate(){//LoadBalanced负载均衡
return new RestTemplate();
}
public static void main(String args[]){
SpringApplication.run(ConsumerApplication.class,args);
}
}
ribbon-consumer:ConsumerController.java如下:
package com.consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConsumerController {
@Autowired
HelloService helloService;
@RequestMapping(value = "/ribbon-consumer",method = RequestMethod.GET)
public String helloConsumer(){
return helloService.helloService();
}
}
ribbon-consumer:HelloService.java如下:
hello服务的调用封装在了service层,RestTemplate已经在Application中配置启动加载。HystrixCommand是断路器,这个是spring-cloud另一个服务功能,这里不做介绍了。
package com.consumer;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
/**
* 断容器默认时间好像是1秒,如果服务在1s没有返回,那么就会走fallbackMethod方法。并不是书中说的2s。
* 注意:被gate-way调用的时候,如大于1s并没有执行短容器,gate-way似乎有1s超时的异常打印。
* @return
*/
@HystrixCommand(fallbackMethod = "helloFallback")
public String helloService(){
long start = System.currentTimeMillis();
String r = restTemplate.getForEntity("http://HELLO-SERVICE/hello",String.class).getBody();
long end = System.currentTimeMillis();
System.out.println("spend time:"+(end-start));
return r;
}
}
配置文件已经配置了端口,直接启动工程:
java -jar target/ribbon-consumer-1.0.jar
我们发现注册中心的界面又多了:10.88.35.92:ribbon-consumer:9000
服务
调用hello服务接口,返回了我们想要的结果:
http://localhost:9000/ribbon-consumer
image.png
以上,是eureka注册中心的微服务注册和微服务的调用的整个搭建过程,还是比较简单的基本就是工程的配置,本文只是一个简单工程搭建,并不是
深入的理解注册中心,更多深入的参数配置请查看官方网站吧。