服务消费者(RestTemplate+Ribbon+feign)
负载均衡
spring cloud 体系中,我们知道服务之间的调用是通过http协议进行调用的。注册中心就是维护这些调用的服务的各个服务列表。在Spring中提供了RestTemplate,用于访问Rest服务的客户端,Spring Cloud体系中也是使用RestTemplate进行服务之间的调用。
负载均衡(Load Balance),通常指将请求分摊到各个操作单元上进行处理,精髓在于均衡,也就是平均。负载均衡在我们日常开发中也是经常听到的,下面介绍几种常见的负载均衡技术实现。
Nginx
Nginx是我们平时使用的较多的负载均衡技术实现,性能也是很不错。一个http请求请求至Nginx服务器,Nginx服务器根据请求和一定的算法将请求转发至真正的服务器,以达到负载均衡的目的。至于Nginx里面具体的负载均衡算法,了解过Nginx的人应该会比较熟悉,没了解过的请自己去看吧。
DNS解析
在DNS服务器上配置多个域名对应ip的记录,一个域名可以对应多组的ip地址。DNS服务器在解析域名时根据相应的算法,把通过域名的请求分配到合适的真实服务器上去。这样也可以达到一定的负载均衡,不至于一个服务器的压力过大。
RestTemplate
我们先看下官方是怎么定义的:
Synchronous client to perform HTTP requests, exposing a simple, template method API over underlying HTTP client libraries such as the JDK HttpURLConnection, Apache HttpComponents, and others. The RestTemplate offers templates for common scenarios by HTTP method, in addition to the generalized exchange and execute methods that support of less frequent cases.
我们可以看到,RestTemplate采用的是同步方式执行Http请求的类,底层使用的是JDK的HttpURLConnection或者Apache的HttpComponents的类库,或者其他的类库。RestTemplate还提供了模版使得开发人员能够更简单发送Http请求。
RestTemplate中定义了很多和Rest资源交互的API,下面就介绍2个我们平时常用的GET和POST请求,在RestTemplate中是怎么请求的。
GET请求:
RequestEntity requestEntity = RequestEntity.get(new URI(uri)).build();
ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);
exchage是一个通用的请求方法,接受一个RequestEntity对象,可以设置路径,请求头,请求信息等。最后返回一个ResponeseEntity实体。
当然GET请求也可以是getForEntity()和getForObject()2中类型:
//getForEntity()
ResponseEntity<User> responseEntity = this.restTemplate.getForEntity(uri, User.class);
User user = responseEntity.getBody();
//getForObject()
User user = this.restTemplate.getForObject(uri, User.class);
POST请求:
HttpEntity<MultiValueMap> request = new HttpEntity<>(map, header); ResponseEntity<String> exchangeResult = restTemplate.exchange(url, HttpMethod.POST, request, String.class);
map中存放post的数据,header里存放请求头相关的信息,最后返回一个ResponeseEntity实体类。
同样的,POST请求也是有着对应的getForObject()和getForEntity()类型:
//postForObject()
User user = this.restTemplate.postForObject(uri, user, User.class);
//postForEntity()
ResponseEntity<User> responseEntity = this.restTemplate.postForEntity(uri, user, User.class);
请他的请求,也是类似,这里就不在此列举了,感兴趣的可以查看RestTesmplate的api
Ribbon
Spring Cloud Ribbon是基于Netflix Ribbon实现的客户端负载均衡组件。区别于Nginx的服务端负载均衡的实现。在结合Spring Cloud Eureka组件使用时,ribbonServerList会被重写,改为通过Eureka的注册中心来获取服务列表,可以通过简单的几行配置来实现客户端的负载均衡。
接下来我们来使用Spring Cloud Ribbon来实现客户端的负载均衡
提前项目准备:
1.Eureka:首先我们先启动一个Eureka 服务端作为注册中心
2.然后开启2个服务,注册到Eureka服务中去,我这里开启了2个oauth服务注册到Eureka服务端中
3.开始构建具有负载均衡功能的服务消费方apiGateWay
这里使用apiGateWay作为服务消费方的原因是我们应用一般都是需要权限管理,验证登录用户的,这里apiGateWay通过调用oauth应用服务来验证用户的合法性。
首先添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
启用服务发现客户端
这里apiGateWay作为服务消费方,就相当于http请求过程充当了客户端的角色,被调用的服务就是服务端。先在客户端的启动类中声明要使用的RestTemplate
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
@Slf4j
public class ApiGatewayApplication {
public static void main(String[] args){
SpringApplication.run(ApiGatewayApplication.class);
log.info("ApiGatewayApplication启动");
} @Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
编写测试类
@RestController
@Slf4j
public class RibbonClient {
@Autowired
RestTemplate restTemplate; @GetMapping("/demo")
public String ribbonClientDemo(String paramName){
log.info("请求参数paramName:{}",paramName);
return restTemplate.getForObject("http://oauth/demo?paramName="+paramName,String.class);
}
}
启动应用,访问http://localhost:38763/demo?paramName=demo
请求的端口是:38765
或者是
请求的端口是:38764
然后我们多次发起请求,看被调用的服务的日志,可以发现请求确实被均匀的分配到开启的2个服务的。
oauth(端口:38764)
请求的参数是:demo
serverPort:38764
oauth(端口:38765)
请求的参数是:demo
serverPort:38765
可以看到,2个服务被轮询调用。Ribbon默认的均衡策略是以轮询的方式去选择服务器。
1.RandomRule:随机选取负载均衡策略,随机Random对象,在所有服务实例中随机找一个服务的索引号,然后从上线的服务中获取对应的服务。
2.RoundRobinRule:线性轮询负载均衡策略。
3.WeightedResponseTimeRule:响应时间作为选取权重的负载均衡策略,根据平均响应时间计算所有服务的权重,响应时间越短的服务权重越大,被选中的概率越高。刚启动时,如果统计信息不足,则使用线性轮询策略,等信息足够时,再切换到WeightedResponseTimeRule。
4.RetryRule:使用线性轮询策略获取服务,如果获取失败则在指定时间内重试,重新获取可用服务。
5.ClientConfigEnabledRoundRobinRule:默认通过线性轮询策略选取服务。通过继承该类,并且对choose方法进行重写,可以实现更多的策略,继承后保底使用RoundRobinRule策略。
6.BestAvailableRule:继承自ClientConfigEnabledRoundRobinRule。从所有没有断开的服务中,选取到目前为止请求数量最小的服务。
7.PredicateBasedRule:抽象类,提供一个choose方法的模板,通过调用AbstractServerPredicate实现类的过滤方法来过滤出目标的服务,再通过轮询方法选出一个服务。
8.AvailabilityFilteringRule:按可用性进行过滤服务的负载均衡策略,会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数超过阈值的服务,然后对剩余的服务列表进行线性轮询。
9.ZoneAvoidanceRule:本身没有重写choose方法,用的还是抽象父类PredicateBasedRule的choose。
如果没有符合我们业务需求的,那么我们也可以根据业务需求自己实现一个IRule。可以通过继承
AbstractLoadBalancerRule来实现我们自己的负载均衡算法:@Slf4j
public class MyRule extends AbstractLoadBalancerRule { @Override
public void initWithNiwsConfig(IClientConfig iClientConfig){ } /**
* 自定义均衡策略
* 这里简单实现返回列表的第一个服务
*/
@Override
public Server choose(Object o) {
log.info("key:" + o);
//获取服务列表
List<Server> allServers = getLoadBalancer().getAllServers();
log.info(allServers.toString());
return allServers.get(0);
}
}
我们通过实现choose方法来实现我们自己的负载均衡算法。
getLoadBalancer().getAllServers()可以获取到所有的服务信息,然后我们可以根据自己的策略来确定选择哪一个服务器。自定义策略之后呢,我们需要在服务调用方添加一个注解配置
@FeignClient+配置类来修改spring cloud的默认配置。首先启动类上添加注解:
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
@Slf4j
@FeignClient(value = "oauth",configuration = RuleConfig.class)
public class ApiGatewayApplication {
public static void main(String[] args){
SpringApplication.run(ApiGatewayApplication.class);
log.info("ApiGatewayApplication启动");
} @Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
然后创建RuleConfig类来把策略修改为我们刚刚实现的策略:
@Configuration
public class RuleConfig {
@Bean
public IRule ribbonRule() {
return new MyRule();
}
}
重新启动应用,然后我们在发起请求,就会发现这次请求就只会转发给同一个服务,也就是server列表里的第一个服务,而不在是轮询的进行请求。
然后可以看到
MyRule类打印的日志:请求参数paramName:demo
key:default
[192.168.3.2:38764, 192.168.3.2:38765]
服务列表中依旧是2个服务在运行,但请求通过我们自定义的策略,永远只会发送给第一个服务,而不会转发给第二个服务。
当然我们也可以通过配置文件配置,这就自己去研究吧。。。
feign
我们先来看下官网是怎么定义的:
Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.
Feign是一个声明示的Http客户端,它是的写Http客户端更加简单。它只需要通过注解相应的接口就可以实现,虽然通过上面的Ribbon里介绍的也可以创建Http客户端发起请求,但不是那么的优雅,Feign是NetFlix开发的声明式、模块式的HTTP客户端,可以帮助我们更好的、更快的开发调用HTTP API。
Feign应用
首先在工程中加入相应的依赖:
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
然后添加配置文件:
server.port=38763
spring.application.name=api-gateway
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.service-id=config-server
spring.cloud.config.profile=@package.environment@
eureka.client.service-url.defaultZone=http://localhost:38761/eureka/
创建启动类,添加注解
@EnableFeignClients,开启Feign支持:@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
@Slf4j
@EnableFeignClients
public class ApiGatewayApplication {
public static void main(String[] args){
SpringApplication.run(ApiGatewayApplication.class);
log.info("ApiGatewayApplication启动");
}
}
创建一个接口类IOauthClient,加入注解@FeignClient来指定这个接口要调用的服务的名称
//使用@FeignClient注解来指定要调用的服务名称,即注册到eureka里的服务名称
@FeignClient(name = "oauth")
public interface IOauthClient { /**
* value 指定要调用的接口
* method 指定调用的方式是 GET、POST、PUT、DELETE等
* @RequestParam 指定要传入的参数
*/
@RequestMapping(value = "/demo",method = RequestMethod.GET)
public String demo(@RequestParam("paramName") String paramName);
}
然后在业务需要的地方调用该接口
@RestController
@Slf4j
public class DemoController { @Autowired
IOauthClient iOauthClient; @GetMapping("/demo")
public String demo(String paramName){
log.info("请求参数为:{}",paramName);
return iOauthClient.demo(paramName);
}
}
启动应用,然后发起请求
然后我们就可以看到页面上请求的返回值:
请求的端口是:38764
是不是和前面讲Ribbon一样的,不过这种实现方式是不是和前面的方式更加优雅呢?尤其是在调用的接口变多之后,这种实现方式是不是更加简单?
注意
这里使用
Feign的时候,需要注意的问题:1.GET请求多个参数的时候,需要使用@RequestParam
2.POST请求使用@RequestBody注解参数
参考资料
- https://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign
- https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html
欢迎关注我的公众号

本文由博客群发一文多发等运营工具平台 OpenWrite 发布
服务消费者(RestTemplate+Ribbon+feign)的更多相关文章
- 白话SpringCloud | 第四章:服务消费者(RestTemple+Ribbon+Feign)
前言 上两章节,介绍了下关于注册中心-Eureka的使用及高可用的配置示例,本章节开始,来介绍下服务和服务之间如何进行服务调用的,同时会讲解下几种不同方式的服务调用. 一点知识 何为负载均衡 实现的方 ...
- Spring Cloud学习笔记【二】Eureka 服务提供者/服务消费者(ribbon)
Ribbon 是 Netflix 发布的开源项目,主要功能是为 REST 客户端实现负载均衡.它主要包括六个组件: ServerList,负载均衡使用的服务器列表.这个列表会缓存在负载均衡器中,并定期 ...
- springcloud干货之服务消费者(ribbon)
本章介绍springcloud中的服务消费者 springcloud服务调用方式有两种实现方式: 1,restTemplate+ribbon, 2,feign 本来想一篇讲完,发现篇幅有点长,所以本章 ...
- spring cloud(服务消费者(利用feign实现服务消费及负载均衡)——初学三)
Feign是一个声明式的Web Service客户端,我们只需要使用Feign来创建一个接口并用注解来配置它既可完成. 它具备可插拔的注解支持,包括Feign注解和JAX-RS注解.Feign也支持可 ...
- 服务消费者(Ribbon)
上一篇文章,简单概述了服务注册与发现,在微服务架构中,业务都会被拆分成一个独立的服务,服务之间的通讯是基于http restful的,Ribbon可以很好地控制HTTP和TCP客户端的行为,Sprin ...
- 第二篇:服务消费者(rest + ribbon)
一. ribbon简介 ribbon是一个负载均衡客户端,可以很好的控制http和tcp的一些行为,Feign也用到了ribbon,当你使用@ FeignClient,ribbon自动被应用. Rib ...
- 【一起学源码-微服务】Eureka+Ribbon+Feign阶段性总结
前言 想说的话 这里已经梳理完Eureka.Ribbon.Feign三大组件的基本原理了,今天做一个总结,里面会有一个比较详细的调用关系流程图. 说明 原创不易,如若转载 请标明来源! 博客地址:一枝 ...
- 玩转SpringCloud(F版本) 二.服务消费者(2)feign
上一篇博客讲解了服务消费者的ribbon+restTemplate模式的搭建,此篇文章将要讲解服务消费者feign模式的搭建,这里是为了普及知识 平时的项目中两种消费模式选择其一即可 本篇博客基于博客 ...
- springcloud微服务实战:Eureka+Zuul+Feign/Ribbon+Hystrix Turbine+SpringConfig+sleuth+zipkin
相信现在已经有很多小伙伴已经或者准备使用springcloud微服务了,接下来为大家搭建一个微服务框架,后期可以自己进行扩展.会提供一个小案例: 服务提供者和服务消费者 ,消费者会调用提供者的服务,新 ...
随机推荐
- Dot Net Core中间件内部运行机制
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { ...
- day13 函数入门
目录 一.什么是函数 二.为何要有函数 三.如何用函数 1.定义函数的三种形式: 形式一.无参函数(自身能干活) 形式二.有参函数(需要外部的材料来加工) 形式三.空函数(在写框架构思函数的时候) 2 ...
- 记录一次dns引发的线程池故障
# 问题描述 公司做的是一个支付系统,会对接很多第三方公司. 突然有一天,有一家第三方(简称金花平台)反应收不到我们的通知消息. # 排查过程 我们登陆自己的服务器,检查程序日志,是有给金花平台发送通 ...
- Pop!_OS下安装C++编程工具
Pop!_OS下C++编程 #0x0 Visual Studio Code #0x1 C++ 0x11 code::blocks #0x0 Visual Studio Code 下载安装vscode ...
- 一、python 基础之基础语法
一.变量命名规则 1.驼峰命名 大驼峰 MyName = 'leon' 小驼峰 myName = 'Amy' 2.下划线命名 my_name = 'jack' 建议:变量名或者文件名使用下划线命名方式 ...
- 数据可视化基础专题(十二):Matplotlib 基础(四)常用图表(二)气泡图、堆叠图、雷达图、饼图、
1 气泡图 气泡图和上面的散点图非常类似,只是点的大小不一样,而且是通过参数 s 来进行控制的,多的不说,还是看个示例: 例子一: import matplotlib.pyplot as plt im ...
- SQL中的多表联查(SELECT DISTINCT 语句)
前言:(在表中,可能会包含重复值.这并不成问题,不过,有时你也许希望仅仅列出不同(distinct)的值. 关键词 DISTINCT 用于返回唯一不同的值.) 如果不加DISTINCT 的话,主表本来 ...
- MVC + EFCore 项目实战 - 数仓管理系统5 – 菜单配置及里程碑划分
上次课程我们完成了需求的梳理. 我们根据梳理的需求把菜单配好,另外我们把项目里程碑也配置在系统中,开发和管理都在系统中,形成无文档化管理. 一.菜单配置 根据我们的归纳图,我们先将菜单配置好. 我们遵 ...
- Mybatis执行流程浅析(附深度文章推荐&面试题集锦)
首先推荐一个简单的Mybatis原理视频教程,可以作为入门教程进行学习:点我 (该教程讲解的是如何手写简易版Mybatis) 执行流程的理解 理解Mybatis的简单流程后自己手写一个,可以解决百分之 ...
- 各种jar包下载地址
standard.jar和jstl.jar的下载地址 http://repo2.maven.org/maven2/javax/servlet/jstl/ http://repo2.maven.org/ ...