Spring Cloud Eureka
Spring Cloud Eureka是基于 Netflix Eureka 做的二次封装, 主要负责完成微服务架构中的服务治理功能。
服务治理
刚开始构建微服务系统时,由于服务的数量不是很多,我们可以通过静态配置文件的方式来管理服务与实例之间的对应关系。随着业务的发展系统服务越来越多,以及服务的变更等使得手工维护变得越来越困难。为了解决这样的问题,便产生了各种服务治理框架。服务治理主要是用来解决服务实例的自动化注册与发现问题。
服务注册
服务治理框架中通常存在着一个服务注册中心。各个服务实例向注册中心登记自己提供的服务。将主机、端口号、版本、通信协议等告知注册中心。注册中心根据服务名来维护服务对应的实例清单。(服务注册中心还会以心跳的方式去监测清单中的服务是否可用,不可用时从清单中剔除达到排除故障服务的效果)。
服务发现
在服务治理框架下,服务间的调用不再通过具体的实例地址,而是通过服务名请求调用实现。服务调用方向服务注册中心咨询服务并获取所有的服务实例地址,以实现对具体服务实例的访问。比如,现有服务C希望调用服务A, 服务C就需要向注册中心发起咨询服务请求, 服务注册中心就会将服务A的位置清单返回给服务C。当服务C要发起调用的时候, 便从该清单中以某种轮询策略取出 一 个位置来进行服务调用, 这就是客户端负载均衡。
Eureka 服务端
Eureka服务端就是服务注册中心。搭建方式:
1、创建spring boot工程,命名为eureka-server,在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.hxb.springcloud</groupId> <artifactId>eureka-server</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>eureka-server</name> <description>spring cloud eureka-server</description> <parent> <groupId>com.hxb</groupId> <artifactId>SpringCloudLearning</artifactId> <version>1.0-SNAPSHOT</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <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> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> <scope>runtime</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR7</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、通过@EnableEurekaServer标签标注springboot应用
@EnableEurekaServer @SpringBootApplication public class Application { public static void main(String[] args){ new SpringApplicationBuilder(Application.class).web(true).run(args); } }
3、添加相关配置属性。默认情况下(eureka.client.register-with-eureka和eureka.client.fetch-register默认为true)服务注册中心会将自己作为客户端注册到注册中心(自己或者是其他的eureka server实例)。新建application.yml
server: port: 1111 eureka: instance: hostname: eureka1 client: register-with-eureka: false fetch-registry: false service-url: defaultZone: 'http://${eureka.instance.hostname}:${server.port}/eureka/' spring: application: name: 'eureka-server'
启动应用并访问http://localhost:1111:
高可用服务注册中心
在微服务这样的分布式环境中,我们需要考虑发生故障的情况。对生产环境中的各个组件必须进行高可用部署。Eureka的设计中所有的节点既是服务提供方也是服务消费方。构建一个双节点的分布式注册中心:
新建application-peer1.yml
server:
port: 1111
eureka:
instance:
hostname: peer1
client:
service-url:
defaultZone: 'http://peer2:1112/eureka/'
register-with-eureka: true
fetch-registry: true
spring:
application:
name: 'eureka-server'
application-peer2.yml
server:
port: 1112
eureka:
instance:
hostname: peer2
client:
service-url:
defaultZone: 'http://peer1:1111/eureka/'
register-with-eureka: true
fetch-registry: true
spring:
application:
name: 'eureka-server'
修改host文件,添加:
127.0.0.1 peer1
127.0.0.1 peer2
分别启动两个节点:
java -jar eureka-server-1.0-SNAPSHOT.jar --spring.profiles.active=peer1 java -jar eureka-server-1.0-SNAPSHOT.jar --spring.profiles.active=peer2
访问eurekaServer,可以看到如图中所示,两个节点相互注册互为备份,eurekaserver启动了两个实例:
Eureka 客户端
对于Eureka根据服务的注册与被注册可以分为Eureka服务端与客户端。而对于Eureka客户端按功能又分为服务提供者与服务消费者。同时一个服务可以有服务提供者和服务消费者双重身份(服务之间相互调用)。
服务提供者
新建Spring Boot 应用,在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"> <parent> <artifactId>SpringCloudLearning</artifactId> <groupId>com.hxb</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>hello-service</artifactId> <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>Dalston.SR1</spring-cloud.version> </properties> <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> <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>
在应用主类中添加@EnableDiscoveryClient:
package com.hxb; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class HelloServiceApplication { public static void main(String[] args) { new SpringApplicationBuilder(HelloServiceApplication.class).web(true).run(args); } }
添加一个Controller:
package com.hxb.controller; import org.apache.log4j.Logger; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloCtroller { private final Logger logger = Logger.getLogger(getClass()); @RequestMapping("/hello") private String index(){ return "hello world!"; } }
配置属性中添加服务名,端口,eurekaServer等相关信息:
server:
port: 1113
spring:
application:
name: 'helloservice'
eureka:
client:
service-url:
defaultZone: 'http://peer1:1111/eureka/,http://peer2:1112/eureka/'
通过配置两个不同的端口启动两个应用实例:
java -jar hello-service-1.0-SNAPSHOT.jar --server.port=1113
java -jar hello-service-1.0-SNAPSHOT.jar --server.port=1114
配合服务消费者测试负载均衡。启动后服务注册中心如下:
访问http://localhost:1113/hello,页面上打印出 hello world!
服务消费者
创建应用ribbon-consumer,pom.xml文件中添加ribbon依赖:
<?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"> <parent> <artifactId>SpringCloudLearning</artifactId> <groupId>com.hxb</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>ribbonconsumer</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <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>Dalston.SR1</spring-cloud.version> </properties> <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> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </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>
配置文件中配置端口号,服务名,Eureka服务注册中心等:
server:
port: 1115
spring:
application:
name: 'ribbonconsumer'
eureka:
client:
service-url:
defaultZone: 'http://peer1:1111/eureka/,http://peer2:1112/eureka/'
应用主类:
package com.hxb; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; 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; @SpringBootApplication @EnableDiscoveryClient public class ConsumerApplication { @Bean @LoadBalanced RestTemplate restTemplate(){ return new RestTemplate(); } public static void main(String[] args) { new SpringApplicationBuilder(ConsumerApplication.class).web(true).run(args); } }
Controller类调用helloService服务:
package com.hxb.Controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class ConsumerController { @Autowired RestTemplate restTemplate; @RequestMapping("hello-consumer") public String helloConsumer(){ return restTemplate.getForEntity("http://HELLOSERVICE/hello",String.class).getBody(); } }
总结
Eureka服务治理体系的相关调用如下: