Eureka的结构和作用
问题1:order-service如何得知user-service实例地址?
获取地址信息的流程如下:
-
user-service服务实例启动后,将自己的信息注册到eureka-server(Eureka服务端)。这个叫服务注册
-
eureka-server保存服务名称到服务实例地址列表的映射关系
-
order-service根据服务名称,拉取实例地址列表。这个叫服务发现或服务拉取
问题2:order-service如何从多个user-service实例中选择具体的实例?
-
order-service从实例列表中利用负载均衡算法选中一个实例地址
-
向该实例地址发起远程调用
问题3:order-service如何得知某个user-service实例是否依然健康,是不是已经宕机?
-
user-service会每隔一段时间(默认30秒)向eureka-server发起请求,报告自己状态,称为心跳
-
当超过一定时间没有发送心跳时,eureka-server会认为微服务实例故障,将该实例从服务列表中剔除
-
order-service拉取服务时,就能将故障实例排除了
搭建eureka-server
1.创建eureka-server服务
在cloud-demo父工程下,创建一个子模块: eureka-server
2.引入eureka依赖
引入SpringCloud为eureka提供的starter依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
3.编写启动类
给eureka-server服务编写一个启动类,一定要添加一个@EnableEurekaServer注解,开启eureka的注册中心功能:
4.编写配置文件
server:
port: 10086
spring:
application:
name: eureka-server
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
5.启动服务
启动微服务,然后在浏览器访问:http://127.0.0.1:10086
看到下面结果应该是成功了:
服务注册
下面,我们将user-service注册到eureka-server中去。
1.引入依赖
在user-service的pom文件中,引入下面的eureka-client依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.配置文件
spring:
application:
name: userservice
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
3.启动多个user-service实例
为了演示一个服务有多个实例的场景,我们添加一个SpringBoot的启动配置,再启动一个user-service。
现在,SpringBoot窗口会出现两个user-service启动配置:
查看eureka-server管理页面:
服务发现
1.引入依赖
这一步与服务注册时一致。
在order-service的pom文件中,引入下面的eureka-client依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.配置文件
服务发现也需要知道eureka地址,因此第二步与服务注册一致,都是配置eureka信息:
在order-service中,修改application.yml文件,添加服务名称、eureka地址:
spring:
application:
name: orderservice
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
3.服务拉取和负载均衡
最后,我们要去eureka-server中拉取user-service服务的实例列表,并且实现负载均衡。
不过这些动作不用我们去做,只需要添加一些注解即可。
在order-service的OrderApplication中,给RestTemplate这个Bean添加一个@LoadBalanced注解:
修改order-service服务中的cn.itcast.order.service包下的OrderService类中的queryOrderById方法。修改访问的url路径,用服务名代替ip、端口:
spring会自动帮助我们从eureka-server端,根据userservice这个服务名称,获取实例列表,而后完成负载均衡。
Ribbon负载均衡
SpringCloud底层其实是利用了一个名为Ribbon的组件,来实现负载均衡功能的。
那么我们发出的请求明明是http://userservice/user/1,怎么变成了http://localhost:8081的呢?
SpringCloudRibbon的底层采用了一个拦截器,拦截了RestTemplate发出的请求,对地址做了修改。用一幅图来总结一下:
基本流程如下:
-
拦截我们的RestTemplate请求http://userservice/user/1
-
RibbonLoadBalancerClient会从请求url中获取服务名称,也就是user-service
-
DynamicServerListLoadBalancer根据user-service到eureka拉取服务列表
-
eureka返回列表,localhost:8081、localhost:8082
-
IRule利用内置负载均衡规则,从列表中选择一个,例如localhost:8081
-
RibbonLoadBalancerClient修改请求地址,用localhost:8081替代userservice,得到http://localhost:8081/user/1,发起真实请求
负载均衡策略
负载均衡的规则都定义在IRule接口中,而IRule有很多不同的实现类:
默认的实现就是ZoneAvoidanceRule,是一种轮询方案
自定义负载均衡策略
通过定义IRule实现可以修改负载均衡规则,有两种方式:
-
代码方式:在order-service中的OrderApplication类中,定义一个新的IRule:对order-service调用的所有服务都使用这个负载均衡规则。
@Bean public IRule randomRule(){ return new RandomRule(); }
-
配置文件方式:在order-service的application.yml文件中,添加新的配置也可以修改规则:只对user-service服务使用该负载均衡规则。
userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务 ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
注意,一般用默认的负载均衡规则,不做修改。