前面我们已经利用RestTemplate实现了order服务和User服务之间的通信。
还记得之前User我搭建了两个服务,那么order服务访问user的时候是走的哪个服务去拿的数据呢,我们可以在user服务的controller类里面稍微改动一下:
@RestController
public class UserController {
@Value("${server.port}")
private int port; //这里读取的是当前服务器端端口
@GetMapping("/user/{id}")
public User getUserById(@PathVariable("id") Long id){
return new User(1L,"java","123456","端口号"+port);
}
}
这样就可以在浏览器看到端口号了,重启User和Order服务测试访问:
peer1:1030/order/1
不知道有没有注意到,这里我们是直接访问的user,我们没有走注册中心去获取ip和端口,eureka的作用就是注册与发现,当服务调用的时候应该先去注册中心拿到目标的ip和端口,然后发起调用,我们这里是把地址写和端口写死了。 所以我们需要使用组件ribbon和feign分发请求。我们这里先使用ribbon,先在order服务导入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
我们先回顾一下ribbon是什么?:
Ribbon和Feign都是客户端负载均衡器,它的作用是在服务发生调用的时候帮我们将请求按照某种规则分发到多个目标服务器上,简单理解就是用来解决微服务之间的通信问题。
Ribbon内置7种负载均衡算法,如下图:
ribbon默认使用的是轮询的算法。我这里使用bean的方式配置随机算法策略,当然还有很多配置方式,有兴趣可以去了解一下
首先在主配置了配置一下代码,这里还有一个非常重要容易被忽略的地方,需要在主配置类RestTemplate类上加一个 @LoadBalanced 注解:
@SpringBootApplication
@EnableEurekaClient
public class OrderServerApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServerApplication.class);
}
@Bean
@LoadBalanced //开启负载均衡
public RestTemplate template(){
return new RestTemplate();
}
@Bean
public RandomRule randomRule(){
return new RandomRule();
}
}
需要注意的是,orderController的类的url地址之前是写死了的,这里我们不能写死,需要指定访问的服务名,user的服务名为user-server:
当服务调用的使用ribbon就会去注册中心找对应的服务名,然后发现有多个ip,然后就会根据负载均衡算法使用RestTemplate来发起调用,所以ribbon要配置RestTemplate使用:
重启order服务,访问peer1:1030/order/1 多刷新几次观察
两次的地址不一样,说明我们集成ribbon成功。
这里扩展一点ribbon的调优配置:
超时配置
使用Ribbon进行服务通信时为了防止网络波动造成服务调用超时,我们可以针对Ribbon配置超时时间以及重试机制
ribbon:
ReadTimeout: 3000 #读取超时时间
ConnectTimeout: 3000 #链接超时时间
MaxAutoRetries: 1 #重试机制:同一台实例最大重试次数
MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数
OkToRetryOnAllOperations: false #是否所有操作都重试,因为针对post请求如果没做幂等处理可能会造成数据多次添加/修改
饥饿加载
我们在启动服务使用Ribbon发起服务调用的时候往往会出现找不到目标服务的情况,这是因为Ribbon在进行客户端负载均衡的时候并不是启动时就创建好的,而是在实际请求的时候才会去创建,所以往往我们在发起第一次调用的时候会出现超时导致服务调用失败,我们可以通过设置Ribbon的饥饿加载来改善此情况,即在服务启动时就把Ribbon相关内容创建好。
ribbon:
ReadTimeout: 3000 #读取超时时间
ConnectTimeout: 3000 #链接超时时间
MaxAutoRetries: 1 #重试机制:同一台实例最大重试次数
MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数
OkToRetryOnAllOperations: false #是否所有操作都重试,因为针对post请求如果没做幂等处理可能会造成数据多次添加/修改
eager-load:
enabled: true #开启饥饿加载
clients: user-server #针对于哪些服务需要饥饿加载,这里可以配置多个服务