Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
1.eureka简介
Eureka包含两个组件:Eureka Server和Eureka Client。
调用关系说明:
1.服务提供者在启动时,向注册中心注册自己提供的服务。
2.服务消费者在启动时,向注册中心订阅自己所需的服务。
3.注册中心返回服务提供者地址给消费者。
4.服务消费者从提供者地址中调用消费者。
注意! 下面的服务端指:注册中心,客户端指:服务提供者和消费者
Eureka Server:提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,包括主机与端口号、服务版本号、通讯协议等。这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka服务端支持集群模式部署,首尾相连形成一个闭环即可,集群中的的不同服务注册中心通过异步模式互相复制各自的状态,这也意味着在给定的时间点每个实例关于所有服务的状态可能存在不一致的现象。
eureka客户端,主要处理服务的注册和发现。客户端服务通过注册和参数配置的方式,嵌入在客户端应用程序的代码中。在应用程序启动时,Eureka客户端向服务注册中心注册自身提供的服务,并周期性的发送心跳来更新它的服务租约。同时,他也能从服务端查询当前注册的服务信息并把它们缓存到本地并周期行的刷新服务状态。
服务调用
服务消费者在获取服务清单后,通过服务名可以获取具体提供服务的实例名和该实例的元数据信息。因为有这些服务实例的详细信息,所以客户端可以根据自己的需要决定具体调用哪个实例,在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。
Eureka服务注册与发现
创建父工程并导入pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<junit.version>4.12</junit.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<!--spring boot 父依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<dependencies>
<!--SpringBoot要集成SpringMVC进行Controller的开发,所以项目要导入web的启动依赖
web功能起步-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--如果报错要加以下依赖
java9+版本以后,JAXB默认没有加载-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<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>
</project>
创建注册中心子模块eureka-demo,pom.xml导入坐标eureka-server端坐标
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
创建一个启动类sise.cn.eureka.EurekaServerApp
//@SpringBootApplication = (默认属性)@Configuration + @EnableAutoConfiguration + @ComponentScan。
@SpringBootApplication
//开始注册中心server
@EnableEurekaServer
public class EurekaServerApp {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApp.class,args);
}
}
创建eureka配置文件application.yml
###当前的eureka作为注册中心,此为当前程序名称
spring:
application:
name: eureka-server
###服务端口号
server:
port: 8888
###eureka基本信息配置
###注册到eurekaaip地址
eureka:
instance:
hostname: 127.0.0.1
###客户访问当前注册中心的地址
client:
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
###因为自己是注册中心,不需要为自己注册
register-with-eureka: false
###因为自己是注册中心,不需要检索服务
fetch-registry: false
启动引导类
访问http://127.0.0.1:8888
生产者和消费者注册以及调用
创建用户服务,创建子模块user-demo
在pom.xml中导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--SpringBoot要集成SpringMVC进行Controller的开发,所以项目要导入web的启动依赖
web功能起步-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
创建配置文件application.yml
###服务启动端口号
server:
port: 8810
###服务名称(服务注册到eureka名称)
spring:
application:
name: 6ms-user
###服务注册到eureka地址
eureka:
# instance:
# prefer-ip-address: true
# instance-id:
# hostname:
###客户访问当前注册中心的地址
client:
service-url:
defaultZone: http://127.0.0.1:8888/eureka
###该应用为注册中心
register-with-eureka: true
###是否需要从eureka上获取注册信息
fetch-registry: true
创建启动类UserApp
@SpringBootApplication
//开启eureka的客户端注解
@EnableEurekaClient
public class UserApp {
public static void main(String[] args) {
SpringApplication.run(UserApp.class,args);
}
}
创建controller
//提共restful风格的Controller -
@RestController
public class UserController {
@RequestMapping("/user/{id}")
public String getUser(@PathVariable("id") int id) {
if (id == 1) {
return "库里";
} else if (id == 2) {
return "科比";
} else {
return "姚明";
}
}
}
启动eureka-server和userapp
访问
http://localhost:8810/user/1 返回库里
创建订单服务,创建子模块order-demo
在pom.xml中导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--ribbon用于负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
创建配置文件application.yml
###服务器启动端口号
server:
port: 8811
###服务名称(服务注册到eureka名称)
spring:
application:
name: 6ms-orer
###服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka
###默认的ribbon是求余
###负载均衡的规则,表示加权规则,yml配置优先级第一,java代码第二,默认的最后
###改成随机的访问策略
6ms-user:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
配置启动类app
@SpringBootApplication
@EnableEurekaClient
public class orderApp {
public static void main(String[] args) {
SpringApplication.run(orderApp.class,args);
}
/*
springcloud服务于服务之间的调用走的是restful风格的
RestTemplate是springcloud提供的专门封装HTTP请求的
*/
//@Bean 用在方法上,告诉Spring容器,你可以从下面这个方法中拿到一个Bean
/*在使用springcloud ribbon客户端负载均衡的时候,可以给RestTemplate bean 加一个@LoadBalanced注解,
就能让这个RestTemplate在请求时拥有客户端负载均衡的能力*/
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
创建订单访问控制类,OderController
@RestController
public class OderController {
@Autowired
OrderService orderService;
@RequestMapping("/order")
public String addOrder(String name,int id){
//调用用户,查询用户信息
String result = orderService.getUser(1);
return "商品:"+name +",生成订单:" + result;
}
}
创建订单实现类orderservice
@Service
public class OrderService {
@Autowired
RestTemplate restTemplate;
public String getUser(int id){
//获取用户信息
//6ms-user是user-demo在eureka上注册的服务名+访问路径
String url = "http://6ms-user/user/{id}";
//意义是请求返回一个对象,这个对象是一个String类型的
String info = restTemplate.getForObject(url,String.class,id);
return info;
}
}
测试
访问http://localhost:8811/order?name=iphone&id=2
返回
商品:iphone,生成订单:库里
Ribbon负载均衡
修改user服务器的端口号启动多个
order会随机调用user服务器
客户端负载均衡
负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。
硬件负载均衡的设备或是软件负载均衡的软件模块都会维护一个下挂可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法(比如线性轮询、按权重负载、按流量负载等)从维护的可用服务端清单中取出一台服务端端地址,然后进行转发。
而客户端负载均衡和服务端负载均衡最大的不同点在于上面所提到服务清单所存储的位置。在客户端负载均衡中,所有客户端节点都维护着自己要访问的服务端清单,而这些服务端端清单来自于服务注册中心,比如上一章我们介绍的Eureka服务端。同服务端负载均衡的架构类似,在客户端负载均衡中也需要心跳去维护服务端清单的健康性,默认会创建针对各个服务治理框架的Ribbon自动化整合配置,比如Eureka中的org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,Consul中的org.springframework.cloud.consul.discovery.RibbonConsulAutoConfiguration。在实际使用的时候,我们可以通过查看这两个类的实现,以找到它们的配置详情来帮助我们更好地使用它。
通过Spring Cloud Ribbon的封装,我们在微服务架构中使用客户端负载均衡调用非常简单,只需要如下两步:
▪️服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心。
▪️服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用。
这样,我们就可以将服务提供者的高可用以及服务消费者的负载均衡调用一起实现了。
自动配置类,主要做了下面三件事:
创建了一个LoadBalancerInterceptor的Bean,用于实现对客户端发起请求时进行拦截,以实现客户端负载均衡。
创建了一个RestTemplateCustomizer的Bean,用于给RestTemplate增加LoadbalancerInterceptor
维护了一个被@LoadBalanced注解修饰的RestTemplate对象列表,并在这里进行初始化,通过调用RestTemplateCustomizer的实例来给需要客户端负载均衡的RestTemplate增加LoadBalancerInterceptor拦截器。