微服务-服务调用

文章目录

  • 微服务-服务调用
    • 地址硬编码
      • 1.服务调用
    • Ribbon
      • 1.服务调用
      • 2.负载均衡
      • 3.请求重试
    • OpenFeign
      • 1.服务调用
      • 2.负载均衡
      • 3.服务降级
      • 4.请求压缩
      • 5.日志配置
      • 6.自定义Feign

微服务-服务调用

服务调用,即一个服务调用另一个服务,此过程可以分为服务调用者、服务提供者。基本上都会使用注册中心来作为中间件。


地址硬编码

地址硬编码即将微服务的IP、端口号、请求url等具体的api地址通过代码的形式写在调用者服务中。

平常的单体应用中,客户端访问应用api即可取得数据;在微服务中,服务调用其它服务的api,就可以获取其数据,这样做的好处在于服务细分化,即将一个服务拆分为很多小服务。
微服务-服务调用_第1张图片

1.服务调用

1.创建两个服务,一个为服务调用者,一个为服务提供者(均可为SpringBoot项目)。
假设服务提供者(即被调用者)的配置如下:

server: 
 port: 9091 #服务端口号

spring:
 application:
   name: img-service #服务名

2.硬编码调用
服务调用者,直接使用http协议进行服务调用,需要用到RestTemplate对象。

@SpringBootApplication
public class MainApplication {

	@Bean//将RestTemplate注册到容器
	public RestTemplate RestTemplate(){
  		return new RestTemplate();
	}

	public static void main(String[] args) {
   	SpringApplication.run(MainApplication.class,args);
	}

}

一般情况下,控制层方法来处理用户请求,因此在这里进行服务调用:

@Autowired//注入RestTemplate
private RestTemplate rt;

@RequestMapping("/img/{id}")
public Img findimg(@PathVariable long id){//地址硬编码,不方便 ,因此需要服务注册中心
   //调用图片服务(需启动图片服务)
   Img img=rt.getForObject("http://localhost:9092/img/findimg/"+id,Img.class);
   return img;
}

可以发现,硬编码的调用方式简单快捷。但这种调用方式将服务的ip、端口都精准地写在代码中,而且ip和端口往往是最容易变动的。当服务越来越多时,写入的ip、端口就会越来越多,这将使得后期维护变得极为困难。


Ribbon

注册中心Eureka、Consul、甚至接下来的OpenFeign均集成了Ribbon,足以证明了Ribbon的强大。
Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。

1.服务调用

Ribbon依赖:Eureka、Consul均集成了,因此这些依赖实际上已经被导入了,不用手动添加,依赖如下。


<dependency>
     <groupId>org.springframework.cloudgroupId>
     <artifactId>spring-cloud-starter-netflix-ribbonartifactId>
     <version>2.2.1.RELEASEversion>
dependency>

调用者启动类将RestTemplate对象注册到容器,并使用注解 @LoadBalanced来实现负载均衡

@LoadBalanced
@Bean//将RestTemplate注册到容器
public RestTemplate RestTemplate(){
   return new RestTemplate();
}

控制层来调用目标服务:

@Autowired//注入RestTemplate
private RestTemplate rt;

//Ribbon获取服务
@RequestMapping("/img3/{id}")
public Img ribbonimg(@PathVariable long id){
   Img img=rt.getForObject("http://img-service/img/findimg/"+id,Img.class);//服务名
   return img;
}

整个调用过程就是这么简单,当然前提是你已经使用了注册中心。

2.负载均衡

不同配置的主机部署相同的服务时,可能会承受的压力是等效的,但由于主机配置不同,导致出现配置低的主机承受不了,配置高的主机绰绰有余,因此可以为配置高的主机多分摊一些压力,达到负载均衡。即对多个相同功能的微服务,实现平衡调用

负载均衡分服务端负载均衡和客户端负载均衡:

  • 服务端:nginx、F5等
  • 客户端:Ribbon

负载均衡的开启:在注册RestTemplate到容器时,添加注解 @LoadBalanced就开启了。

Ribbon提供了负载均衡策略,如果一般情况下不建议修改,除非一样的服务,部署在不同配置的主机上。

修改服务调用者的负载均衡策略:

#修改Ribbon负载均衡策略:服务名.ribbon.NFLoadBalancerRuleClassName.策略
img-service:
 ribbon:
   NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

3.请求重试

当服务调用者调用一个服务时,被调用的服务可能无法响应(宕机),此时调用者无法进行对其调用,那么可以重试请求去调用另一个相同的服务。

为调用者服务配置请求重试:


<dependency>
   <groupId>org.springframework.retrygroupId>
   <artifactId>spring-retryartifactId>
dependency>

添加配置

spring:
	cloud:
		loadbalancer:
			retry:
				enabled: true #开启springCloud的重试功能,默认开启
img-service:
	ribbon:
		ConnectTimeout: 250           #ribbon连接的超时时间
		ReadTimeout: 1000             #ribbon数据读取的超时时间
		OkToRetryOnAllperations: true #是否对所有操作都重试
		MaxAutoRetriesNextServer: 1   #切换实例的重试次数
		MaxAutoRetries: 1             #当前实例的重试次数


OpenFeign

SpringCloud对feign组件进行了增强,使其支持SpringMVC注解、整合了Ribbon和Eureka。

1.服务调用

openfeign的调用写法和前面几种略有不同,但这种方式即简单又高效,是十分值得使用的方式。

引入依赖:


<dependency>
   <groupId>org.springframework.cloudgroupId>
   <artifactId>spring-cloud-starter-openfeignartifactId>
dependency>


<dependency>
   <groupId>org.springframework.cloudgroupId>
   <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>

在调用者的启动类使用注解 @EnableOpenFeign注解激活OpenFeign

@SpringBootApplication
@EnableFeignClients//激活Fegin,注意写在配置类上会启动出错
public class MainApplication {
   
	public static void main(String[] args) {
       SpringApplication.run(MainApplication.class,args);
   }
}

为调用者创建接口,并在接口上通过注解调用服务:

@Component
@FeignClient(name="img-service")	//声明要调用的微服务名,name值为服务名
public interface ImgFeignClient {

   // 配置需要调用的微服务接口
   @RequestMapping(value = "/img/findimg/{id}",method = RequestMethod.GET)	
   public Img findid( @PathVariable long id);
   
}

调用者控制层调用接口,实现对数据的获取:

@Autowired
private ImgFeignClient ifc;	//此处报红线,不用担心,是加载过慢

//feign获取服务
@RequestMapping("/img4/{id}")
public Img fignimg(@PathVariable long id){
   Img img=ifc.findid(id);
   return img;
}

可以看出,这种方式是最舒服的,使得调用和控制层耦合度变低。而且不需要再注册 RestTemplate 对象(就算注册了,也会失效)。

2.负载均衡

Feign 中本身已经集成了Ribbon依赖和自动配置,因此我们不需要额外引入依赖.也不需要额外配置。

3.服务降级

什么是服务降级?即服务请求已经达到上设置的上限(阀值)时,为后面的请求提供一个低级的服务来处理请求,以此来解决高并发问题。

OpenFeign内部集成了Hystrix,通过Hystrix,可以实现服务的降级操作。服务降级的解决方案不止Hystrix一种:https://blog.csdn.net/qq_52681418/article/details/113351447

Feign的调用方式为在调用者添加接口,对接口使用注解来实现服务调用,然后在控制层调用接口。这和一般的调用相比多了一层接口,因此在feign里,可以对调用的服务接口设置降级。

Feign已经集成了Hystrix,因此无需再导入依赖,只需要添加配置:

feign:
	hystrix: #开启对hystrix的支持
		enabled: true

实现要保护的接口,并将实现类注册到容器:假定调用服务创建的接口为ImgFeignClient 。

@Component
public class ImgFeignClientCallBack implements ImgFeignClient {
  
   @Override // 熔断降级的方法
   public Img findid(long id) {
       Img img=new Img();
       img.setName("触发降级方法");
       return img;
   }
}

调用服务的接口上添加注解,指定用来降级的实现类(因为此接口实现不止一个):

//  fallback:指定服务降级方法,即实现类
@FeignClient(name="img-service",fallback= ImgFeignClientCallBack.class)
public interface ImgFeignClient {
   
    // 配置需要调用的微服务接口
   @RequestMapping(value = "/img/findimg/{id}",method = RequestMethod.GET)
   public Img findid( @PathVariable long id);
   
}

为什么说此接口实现类不止一个呢,通过接口加注解来调用服务,不就相当于内置提供了一个实现吗。

4.请求压缩

SpringCloud Feign支持对请求、响应进行GZIP压缩,减少性能损耗。

为调用者添加如下配置:

feign:
	compression:
		request:
			enabled: true #开启请求压缩
		response:
			enabled: true #开启响应压缩

同时,可以对请求的数据类型、触发压缩的大小下限。

feign:
	compression:
		request:
			enabled: true #开启请求压缩
			mime-types: text/html,application/xml,application/json	#设置压缩的数据类型
			min-request-size: 2048 #设置触发压缩的大小下限

上面均为默认配置,无特殊需求,可以不写。

5.日志配置

为调用者添加日志配置:

feign:
client:
 config:
	img-service: #此处为服务名
		loggerLevel: FULL 
				#NONE:不输出日志(性能最好)。
                #BASIC:适用于生产环境追踪问题
				#HEADERS:在BASIC的基础上记录请求和响应头信息
				#FULL:记录所有
logging:
	level:
		com.feign.ImgFeignClient: debug1	#接口全类名

6.自定义Feign

从Spring Cloud Edgware开始,Feign支持使用属性自定义Feign.

feign:
   client:
     config:
       feignName: ##定义FeginClient的名称
         connectTimeout: 5000  # 相当于Request.Options
         readTimeout: 5000   # 相当于Request.Options
         # 配置Feign的日志级别,相当于代码配置方式中的Logger
         loggerLevel: full
         # Feign的错误解码器,相当于代码配置方式中的ErrorDecoder
         errorDecoder: com.example.SimpleErrorDecoder
         # 配置重试,相当于代码配置方式中的Retryer
         retryer: com.example.SimpleRetryer
         # 配置拦截器,相当于代码配置方式中的RequestInterceptor
         requestInterceptors:
           - com.example.FooRequestInterceptor
           - com.example.BarRequestInterceptor
         decode404: false
 

你可能感兴趣的:(001-分布式系列,spring,cloud,分布式,微服务架构)