一、简介
在微服务架构中服务发现是一个非常核心的功能。在spring cloud中可以很方便集成Netflix Service Discovery组件eureka。Eureka包含server和client,其中server端能够以群集的形式提供,各个sever又可以通过同步其他server中注册的service状态来实现高可用性。
当一个Eureka client向server注册时,会提供自身的元数据信息,包括host、port、health check URI等信息,Eureka server通过侦听同一个service的不同实例的心跳信息来确定当前实例是否正常,如果心跳信息失败,就会自动将该实例移除。
调用注册到Eureka中的服务,可以不直接采用EurekaClient,利用声明式的rest client :feign,或者Spring RestTemplate可以更加方便的调用注册在Eureka总的服务。
二、例子
[*]1. Eureka server
核心是在正常的Spring boot程序中加入spring-cloud-starter-eureka-server依赖,在启动类中加入@EnableEurekaServer 注解
[*]代码结构:
[img]http://dl2.iteye.com/upload/attachment/0123/0090/d33819d0-9bee-3128-a9cd-b7c86bef3f7b.png[/img]
[*]启动类
[*]pom文件
[*]应用配置信息
[*]2.Eureka client(即user server端)
核心是在正常的Spring boot程序中加入spring-cloud-starter-eureka依赖,在启动类中加入@EnableDiscoveryClient注解
[*]代码结构:
[img]http://dl2.iteye.com/upload/attachment/0123/0092/0b9ac7c6-3a4c-307c-be04-e8b06504f2fc.png[/img]
[*]启动类
[*]pom文件
[*]应用配置信息
[*]3.User client(调用注册到Eureka server中的Eureka client)
核心是在正常的Spring boot程序中加入spring-cloud-starter-eureka、spring-cloud-starter-feign依赖,在启动类中加入@EnableFeignClients注解
[*]代码结构:
[img]http://dl2.iteye.com/upload/attachment/0123/0094/9e7b038d-07ed-3ff9-8405-e84afe0f8fdf.png[/img]
[*]启动类
FeignClient中的service id要和User server配置信息中的spring.application.name的值保持一致
[*]pom文件
[*]应用配置信息
三、启动
按下面的顺序启动
Eureka server ->user server -> user client
等所有应用都启动后通过界面访问http://localhost:7211/greeting,可以正常访问user-server中的方法返回值,整个流程是 界面访问 user client 工程中的hello方法,user client通过@FeignClient中指定的service id从Eureka server中获取到注册的 HelloServer instance,即 user server,然后调用user server中的hello方法,返回调用结果给 user client,最终返回界面
[img]http://dl2.iteye.com/upload/attachment/0123/0098/bc281f95-0a9c-3f39-8926-b2abf9130f29.png[/img]
四、Eureka 集群
[img]http://dl2.iteye.com/upload/attachment/0123/0233/fe987d94-721a-3e5a-9b19-6e57b07de678.png[/img]
1.修改Eureka-server对应的配置文件
2.修改user-server对应的配置文件
注意:application.name 修改过,feignclient对应的serviceid也需要修改
3.修改user-client对应的配置文件
3.如果在同一台机器上,修改hosts
依次启动 Eureka-server user-server user-client,其中启动Eureka-server时用
启动三次,此时Eureka-server以集群形式提供服务,可以关闭任意一个或两个来测试Eureka的高可用性
[*]primary
[img]http://dl2.iteye.com/upload/attachment/0123/0121/d8552ef0-7506-39b5-ac2c-2de9de2b8d36.png[/img]
[*]secondary
[img]http://dl2.iteye.com/upload/attachment/0123/0123/3b5ed66e-2e74-32dd-86ac-23a023abf719.png[/img]
[*]tertiary
[img]http://dl2.iteye.com/upload/attachment/0123/0125/bf175a05-7594-3e86-a7fc-6bd0aef505e1.png[/img]
在微服务架构中服务发现是一个非常核心的功能。在spring cloud中可以很方便集成Netflix Service Discovery组件eureka。Eureka包含server和client,其中server端能够以群集的形式提供,各个sever又可以通过同步其他server中注册的service状态来实现高可用性。
当一个Eureka client向server注册时,会提供自身的元数据信息,包括host、port、health check URI等信息,Eureka server通过侦听同一个service的不同实例的心跳信息来确定当前实例是否正常,如果心跳信息失败,就会自动将该实例移除。
调用注册到Eureka中的服务,可以不直接采用EurekaClient,利用声明式的rest client :feign,或者Spring RestTemplate可以更加方便的调用注册在Eureka总的服务。
二、例子
[*]1. Eureka server
核心是在正常的Spring boot程序中加入spring-cloud-starter-eureka-server依赖,在启动类中加入@EnableEurekaServer 注解
[*]代码结构:
[img]http://dl2.iteye.com/upload/attachment/0123/0090/d33819d0-9bee-3128-a9cd-b7c86bef3f7b.png[/img]
[*]启动类
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServiceApplication.class, args);
}
}
[*]pom文件
<?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>com.example</groupId>
<artifactId>eureka-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</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>Camden.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>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/libs-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>
[*]应用配置信息
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
logging.level.com.netflix.eureka=OFF
logging.level.com.netflix.discovery=OFF
[*]2.Eureka client(即user server端)
核心是在正常的Spring boot程序中加入spring-cloud-starter-eureka依赖,在启动类中加入@EnableDiscoveryClient注解
[*]代码结构:
[img]http://dl2.iteye.com/upload/attachment/0123/0092/0b9ac7c6-3a4c-307c-be04-e8b06504f2fc.png[/img]
[*]启动类
package demo;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Spencer Gibb
*/
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class HelloServerApplication {
@RequestMapping("/greeting")
public String hello() {
List<String> greeting = Arrays.asList("Hi there","Greetings","Salutations");
Random rand = new Random();
int randomNum = rand.nextInt(greeting.size());
return greeting.get(randomNum);
}
public static void main(String[] args) {
SpringApplication.run(HelloServerApplication.class, args);
}
}
[*]pom文件
<?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>org.test</groupId>
<artifactId>feign-eureka-hello-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>feign-eureka-hello-server</name>
<description>Demo project for Spring Cloud</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
[*]应用配置信息
spring:
application:
name: HelloServer
server:
port: 7111
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
leaseRenewalIntervalInSeconds: 10
metadataMap:
instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${server.port}}}
[*]3.User client(调用注册到Eureka server中的Eureka client)
核心是在正常的Spring boot程序中加入spring-cloud-starter-eureka、spring-cloud-starter-feign依赖,在启动类中加入@EnableFeignClients注解
[*]代码结构:
[img]http://dl2.iteye.com/upload/attachment/0123/0094/9e7b038d-07ed-3ff9-8405-e84afe0f8fdf.png[/img]
[*]启动类
package demo;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Spencer Gibb
*/
@SpringBootApplication
@RestController
@EnableFeignClients
public class HelloClientApplication {
@Autowired
HelloClient client;
@RequestMapping("/greeting")
public String hello() {
return client.hello();
}
public static void main(String[] args) {
SpringApplication.run(HelloClientApplication.class, args);
}
@FeignClient("HelloServer")
interface HelloClient {
@RequestMapping(value = "/greeting", method = GET)
String hello();
}
}
FeignClient中的service id要和User server配置信息中的spring.application.name的值保持一致
[*]pom文件
<?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>org.test</groupId>
<artifactId>feign-eureka-hello-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>feign-eureka-hello-client</name>
<description>Demo project for Spring Cloud</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
[*]应用配置信息
spring:
application:
name: HelloClient
server:
port: 7211
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
instance:
leaseRenewalIntervalInSeconds: 10
metadataMap:
instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${server.port}}}
endpoints:
restart:
enabled: true
shutdown:
enabled: true
health:
sensitive: false
三、启动
按下面的顺序启动
Eureka server ->user server -> user client
等所有应用都启动后通过界面访问http://localhost:7211/greeting,可以正常访问user-server中的方法返回值,整个流程是 界面访问 user client 工程中的hello方法,user client通过@FeignClient中指定的service id从Eureka server中获取到注册的 HelloServer instance,即 user server,然后调用user server中的hello方法,返回调用结果给 user client,最终返回界面
[img]http://dl2.iteye.com/upload/attachment/0123/0098/bc281f95-0a9c-3f39-8926-b2abf9130f29.png[/img]
四、Eureka 集群
[img]http://dl2.iteye.com/upload/attachment/0123/0233/fe987d94-721a-3e5a-9b19-6e57b07de678.png[/img]
1.修改Eureka-server对应的配置文件
spring:
application:
name: eureka-server-clustered
profiles: primary
server:
port: 8011
eureka:
instance:
hostname: eureka-primary
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://eureka-secondary:8012/eureka/,http://eureka-tertiary:8013/eureka/
---
spring:
application:
name: eureka-server-clustered
profiles: secondary
server:
port: 8012
eureka:
instance:
hostname: eureka-secondary
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://eureka-tertiary:8013/eureka/,http://eureka-primary:8011/eureka/
---
spring:
application:
name: eureka-server-clustered
profiles: tertiary
server:
port: 8013
eureka:
instance:
hostname: eureka-tertiary
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://eureka-primary:8011/eureka/,http://eureka-secondary:8012/eureka/
2.修改user-server对应的配置文件
spring:
application:
name: UserServer
server:
port: 7111
eureka:
client:
serviceUrl:
defaultZone: http://eureka-secondary:8012/eureka/
instance:
leaseRenewalIntervalInSeconds: 10
metadataMap:
instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${server.port}}}
注意:application.name 修改过,feignclient对应的serviceid也需要修改
3.修改user-client对应的配置文件
spring:
application:
name: UserClient
server:
port: 7211
eureka:
client:
serviceUrl:
defaultZone: http://eureka-primary:8011/eureka/,http://eureka-secondary:8012/eureka/,http://eureka-tertiary:8013/eureka/
instance:
leaseRenewalIntervalInSeconds: 10
metadataMap:
instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${server.port}}}
endpoints:
restart:
enabled: true
shutdown:
enabled: true
health:
sensitive: false
3.如果在同一台机器上,修改hosts
# 127.0.0.1 localhost
# ::1 localhost
127.0.0.1 localhost
127.0.0.1 eureka-primary
127.0.0.1 eureka-secondary
127.0.0.1 eureka-tertiary
依次启动 Eureka-server user-server user-client,其中启动Eureka-server时用
java -jar eureka-server-clustered-0.0.1-SNAPSHOT.jar --spring.profiles.active=primary
java -jar eureka-server-clustered-0.0.1-SNAPSHOT.jar --spring.profiles.active=secondary
java -jar eureka-server-clustered-0.0.1-SNAPSHOT.jar --spring.profiles.active=tertiary
启动三次,此时Eureka-server以集群形式提供服务,可以关闭任意一个或两个来测试Eureka的高可用性
[*]primary
[img]http://dl2.iteye.com/upload/attachment/0123/0121/d8552ef0-7506-39b5-ac2c-2de9de2b8d36.png[/img]
[*]secondary
[img]http://dl2.iteye.com/upload/attachment/0123/0123/3b5ed66e-2e74-32dd-86ac-23a023abf719.png[/img]
[*]tertiary
[img]http://dl2.iteye.com/upload/attachment/0123/0125/bf175a05-7594-3e86-a7fc-6bd0aef505e1.png[/img]