服务提供者:一次业务中,被其它微服务调用的服务。(提供接口给其它微服务)
服务消费者:一次业务中,调用其它微服务的服务。(调用其它微服务提供的接口)
很明显,这是一个相对的概念。
上一篇中,远程调用时,url参数是写死在代码中的,而不同的测试、生产、开发环境IP不同,有集群时,端口也不能固定。
很明显,硬编码肯定行不通。Eureka就是来解决这个问题的。
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
server:
port: 10086 # 服务端口
spring:
application:
name: eurekaserver # eureka的服务名称,eureka自身也是个微服务,也要注册自己的信息到eureka注册中心
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
# eureka自身也是个微服务,也要注册自己的信息到eureka注册中心
# 王思聪住万达酒店也得身份证登记一下,虽然那就是他家的产业
接下来将user和order服务注册到eureka中:
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
server:
port: 8081
spring:
application:
name: userservice
eyreka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
上面完成的注册都是单服务实例的,接下来在IDEA中模拟启动多个服务实例:
接下来实现:在order服务中完成服务信息的拉取,然后通过负载均衡挑选一个user服务,实现远程调用
服务拉取是基于服务名称获取服务列表,然后在对服务列表做负载均衡
String url ="http://userservice/user/" + order.getUserId();
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
分析:
我在浏览器中直接访问http://userservice/user/,访问失败,这是因为userservice既不是可用域名,也不是IP。那order调用到user服务的过程中经历了什么呢?
具体信息,在源码中打断点来调试看看。
@LoadBalanced注解,就标识了调用方当前这个restTemplate这个对象发起的请求,要被Ribbon拦截
LoadBalancerInterceptor实现了ClientHttpRequestInterceptor接口:
在LoadBalancerInterceptor接口重写的intercent方法上打断点,调用order接口(中途会对user服务发起远程调用),断点进入到了这里:
继续往下,看到了Ribbon对象
继续往下:成功从eureka拿到服务列表信息
继续往下调试,看到了IRule这个接口,决定了负载均衡的策略
以上,调用接口http://localhost:8080/order/102后发生的事情如图:
- 接口中途通过restTemple远程调用http://userservice/user/1
- 被负载均衡拦截器拦截
- 获取url中的服务id,即userservice
- 动态服务列表均衡器向eureka拉取userservice的信息
- eureka返回服务列表给DynamicServiceListLoadBalancer
- 通过IRule挑选出某个服务,返回给RibbonLoadBalancerClient
- 请求被转发到了某个一具体的实例上
Ribbon的负载均衡策略是由IRule接口来定义的,它的每一个子接口就是一种策略。
具体的含义为:
以上策略中,Ribbon默认的是ZoneAvoidanceRule。想修改负载均衡策略有这两种方法:
代码方式:在order-service中的OrderApplication类中,定义一个新的IRule:
@Bean
public IRule randomRule(){
return new RandomRule(); //改为随机
}
配置文件方式:在order-service的application.yml文件中,添加新的配置也可以修改规则
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载均衡规则
此时,多次调用order接口(代码中途远程调用user):
http://localhost:8080/order/102
可以看到转发到user实例上的请求不再有明显规律。
重启order服务,然后两次访问order接口,发现耗时相差巨大:
Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,因此请求时间会很长。
饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下配置开启饥饿加载:
ribbon:
eager-load:
enabled: true #开启饥饿加载
clients: userservice # 指定对userservice这个服务饥饿加载
# clients为list,可添加多个