文章目录
- 1.Ribbon(负载均衡,服务调用)
- 1.1问题引出
- 1.2 Ribbon负载均衡
- 1.3 RestTemplate整合Ribbon
- 1.4 指定Ribbon负载均衡策略
- 1.4.1 配置文件
- 1.4.2 配置类
- 1.4.3 定义Ribbon客户端配置
- 1.4.4 自定义负载均衡策略
- 2.OpenFeign面向接口的服务调用(服务发现,远程调用)
- 2.1 OpenFeign的使用
- 2.1 .1创建一个fegin的api Module
- 2.1 .2勇敢feginclient调用提供者的方法
- 2.2 FeignClient日志输出
- 2.3 服务调用的超时设置
1.Ribbon(负载均衡,服务调用)
1.1问题引出
学习完了注册中心相关知识,在微服务架构中,我们已经可以实现服务的注册与自动发现了。但是再来看看我们的代码
@Autowired
DiscoveryClient discoveryClient;
// 服务发现
List<ServiceInstance> instances = discoveryClient.getInstances("服务名");
// 选择一个服务提供者
URI uri = instances.get(0).getUri();
// 向选择的服务提供者发起请求
ResponseEntity<String> response = template.getForEntity(uri.toString() + "/nacos/registry/hello?name={1}", String.class, name);
服务是可以有集群的,在发现了一个服务所有的实例之后,在一次服务调用过程中,我们还需要选择其中一个服务实例,发起调用请求,所以发起调用之前还存在着一个选择过程,这就涉及到了选择的策略问题,该按照何种策略选择出集群中的一个实例呢?在SpringCloud中有一个由Ribbon帮我们完成这一选择过程。
1.2 Ribbon负载均衡
Ribbon是一个客户端负载均衡器,能够给HTTP客户端带来灵活的控制。其实现的核心功能,就是一组选择策略,帮助我们在一个服务集群中,选择一个服务实例,并向该实例发起调用请求。它所支持的负载均衡策略如下:
1.3 RestTemplate整合Ribbon
我们希望,在使用RestTemplate发起请求的时候,能“自动选择”其所请求的服务实例,因此我们需要将RestTemplate与Ribbon进行整合。
首页,我们先在消费者服务工程中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
在消费者中,因为nacos-discovery已经自己整合了ribbon依赖,所以实际上我们并不需要去添加该依赖
然后我们修改一下RestTemplate的配置类,添加@LoadBalance注解
@RestController
@RequestMapping("/call")
public class RegistryConsumerController {
@Autowired
RestTemplate template;
@GetMapping("/nacos")
public String consumeNacos(String name) {
// 注意这里调用的ip地址,使用的是服务名称,而不是真实的ip
ResponseEntity<String> response = template.getForEntity( "http://nacos-provider-8002/nacos/registry/hello?name={1}", String.class, name);
String result = response.getBody();
return result;
}
}
1.4 指定Ribbon负载均衡策略
Ribbon中包含多种负载均衡策略,我们在使用Ribbon的时候,可以指定其负载均衡策略,指定的方式有两种,即配置文件和配置类。
1.4.1 配置文件
# 这里的users是我们的服务名称
users:
ribbon:
# 这一行配置的就是实现具体负载均衡策略实现类的全类名
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
1.4.2 配置类
@Configuration
public class RandomRuleConfiguration {
// 这里的xxxRule对应的就是RandomRule()
@Bean
public IRule ribbonRule() {
return new RandomRule();
}
}
1.4.3 定义Ribbon客户端配置
但是切记有一个地方需要注意,我们自己定义的配置类(比如上面的FooConfiguration配置类),不能被@ComponentScan扫描到,所以我们可以将其放在一个独立的,与扫描路径无重叠的包里,或者指明不被@ComponentScan注解扫描到,因为这样一来导致的结果就是,对所有服务调用的负载均衡都用的是同一个我们指定的,被扫描到的这个负载均衡策略
1.4.4 自定义负载均衡策略
我们可根据自己的需要,去定义自己的负载均衡策略,我们只需要自己实现IRule接口的实现类,在接口实现中,实现我们自己的负载均衡策略,并用类似于前面代码的配置方式,使我们自定义负载均衡策略生效。
public class MyBalanceRule extends AbstractLoadBalancerRule {
public MyBalanceRule() {
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
/*
在该方法里实现负载均衡
*/
@Override
public Server choose(Object key) {
List<Server> allServers = getLoadBalancer().getAllServers();
// 简单粗暴的负载均衡策略
return allServers.get(0);
}
}
2.OpenFeign面向接口的服务调用(服务发现,远程调用)
现在我们的服务调用过程,又变得简单了一些,因为Ribbon帮助我们解决了,服务调用过程中的选择问题。再来看一下我们的服务调用代码
我们会发现,因为我们是使用RestTemplate这个Http客户端发起的Http协议的服务调用请求,因此在发起请求的时候,我们得自己构建请求url,请求参数,获取响应体数据等等,导致我们的代码和Restful风格的Http请求紧密耦合。
那么有没有办法,让我们在服务调用的时候与Restful的请求“解耦”,直接以Java代码中接口调用的方式,来完成服务的调用呢?
2.1 OpenFeign的使用
OpenFeign就可以帮助我们实现,让服务调用代码与Restful风格的Http请求解耦的功能。虽然,OpenFeign本身仅仅只是在客户端使用,但是因为使用了OpenFeign意味着服务的调用是面向Java接口的,而非HTTP API的,调用方式发生了改变,所以我们服务提供者工程的代码结构也要发生改变
直接拿一下商城项目使用到的openFeign实例在讲解
我们已经把单体架构拆分成了微服务,现在我们怎么
trade服务里面怎么快速高效率调用item服务呢?
2.1 .1创建一个fegin的api Module
@FeignClient("item-service") //里面的提供者的服务名称
注意路径一致
2.1 .2勇敢feginclient调用提供者的方法
两处调用都是直接调用 itemclient
2.2 FeignClient日志输出
当我们调用FeignClient发出请求的时候,如果我们希望能看到其发出的具体Http请求,我们可以通过配置来实现。
- 配置文件
# 这里的xxx表示我们自己的定义的FeignClient所在包的包名(比如: com.code.feign.consumer.api)
logging:
level:
xxx: debug
- 配置类
@Configuration
public class DefaultFeignConfig {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.FULL;
}
}
这样当我们,通过在对应的FeignClient对象上,调动方法,发起http请求的时候,对应的请求就会打印在控制体。
2.3 服务调用的超时设置
通常,一次远程调用过程中,服务消费者不可能无限制的等待服务提供者返回的结果,正常情况下,服务提供者的一次调用执行过程也不会执行很长时间(除非出现网络故障,或者服务提供者宕机等问题),所以为防止,在非正常情况下服务消费者在调用过程中的长时间阻塞等待,对于一次服务调用过程,我们会设置其超时时间。一次服务调用,超时未返回即认为调用失败。在使用Feign的时候,我们可以配置其超时时间。
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000