Spring Cloud负载均衡及远程调用实现详解
作者:编了个程 发布时间:2021-10-16 01:11:27
负载均衡
使用微服务后,为了能够承担高并发的压力,同一个服务可能会启动多个实例。这时候消费者就需要负载均衡,把请求分散到各个实例。负载均衡主要有两种设计:
服务端负载均衡客户端负载均衡
对于传统的分布式服务来说,大多使用服务端负载均衡。一般会使用Nginx或者ELB等工具作为负载均衡器,如下图:
传统负载均衡
而在Spring Cloud中,使用的是「客户端负载均衡」的方式,使用「Ribbon」组件来实现客户端的负载均衡。只要引入了微服务注册中心依赖,就会自动引入Ribbon依赖。客户端负载均衡原理如下图:
客户端负载均衡
Ribbon的原理
Ribbon利用了RestTemplate的 * (接口是ClientHttpRequestInterceptor)机制,在 * 中实现的负载均衡。负载均衡的基本实现就是利用从「服务注册中心」获取可用的服务地址列表,然后通过一定算法负载,决定使用哪一个服务地址来进行HTTP调用。
详情可以查看LoadBalancerInterceptor这个类,位于org.springframework.cloud.client.loadbalancer包下。
使用Ribbon
首先定义一下生产者「service-user」,我这里使用容器启动了多个生产者实例,每个实例具有不同的id,我的示例代码里面启动了两个实例:
service-user-1
service-user-2
代码:
@RestController
@RequestMapping
public class HelloController {
@Value("${spring.cloud.consul.discovery.instanceId}")
private String instanceId;
@GetMapping("hello")
public String hello() {
return String.format("hello, this is %s", instanceId);
}
}
然后对于消费者「service-order」,可以使用Java声明式注解的方式来使用Ribbon,只需要在消费者给RestTemplate类型的Bean配上一个@LoadBalanced就可以了。然后再配置一下负载均衡策略:
@Configuration
public class RibbonConfig {
@Bean
@LoadBalanced
public RestTemplate ribbonRestTemplate(){
return new RestTemplate();
}
@Bean
public IRule ribbonRule() {
return new RandomRule(); // 随机负载均衡
}
}
然后就可以直接使用自动注入的RestTemplate类型的Bean了:
@RestController
@RequestMapping
public class HelloController {
@Autowired
RestTemplate restTemplate;
@GetMapping("/ribbon/service-user")
public String ribbonService(){
return restTemplate.getForObject("http://service-user/hello", String.class);
}
}
这个时候访问消费者的/ribbon/service-user,刷新几次,就会看到下面两个随机的响应:
hello, this is service-user-2
hello, this is service-user-1
负载均衡策略
查看IRule接口的实现类,可以看到Ribbon的所有负载均衡策略,查看各实现类顶部的注释可以看到它的具体策略:
负载均衡器
RandomRule:随机选择;
RoundRobinRule:轮询;
WeightedResponseTimeRule:根据每个服务的响应时间设置权重,响应时间越长,所占权重越少;
AvailabilityFilteringRule:过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值);
ZoneAvoidanceRule:使用CompositePredicate根据区域和可用性过滤服务器的规则;
BestAvailableRule:选择一个最小的并发请求的server;
RetryRule:在现有的策略基础上,添加重试机制,因为IRule支持「级联」。
远程调用
Spring Cloud提供了OpenFeign组件(以前叫Feign)来进行远程的HTTP调用。它是对RestTemplate的一个封装。
Feign是一个声明式Web Service客户端。使用Feign能让编写Web Service客户端更加简单。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与微服务注册中心和Ribbon组合使用以支持负载均衡。
使用OpenFeign
第一步,引入依赖:
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
第二步,启动配置,在启动类上添加@EnableFeignClients注解:
@SpringBootApplicationbr/>@EnableFeignClients
public class ServiceOrderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceOrderApplication.class, args);
}
}
第三步:声明调用接口,我这里案例是service-order调用service-user的/hello接口,这里的注解就跟Spring MVC的注解一致:
注意Feign在做POST请求的时候有一个小坑,详情参考:SpringCloud Feign Post表单请求。
@FeignClient("service-user")
public interface UserClient {
@GetMapping("hello")
String getUserHello();
}
第四步:使用,注解使用@Autowired注解注入就可以了:
@RestController
@RequestMapping
public class HelloController {
@Autowired
UserClient userClient;
@GetMapping("hello")
public String hello() {
return "hello, this is order service";
}
@GetMapping("userHello")
public String user() {
return userClient.getUserHello() + ", this is order-service";
}
}
是不是看起来非常简单?
OpenFeign集成Ribbon
前面我们提到,OpenFeign底层是对RestTemplate的一个封装,而Ribbon是通过给RestTemplate添加过滤器来实现的,所以OpenFeign天生就自动集成了Ribbon,我们不需要任何额外的配置。
在上述代码中,启动后,可以访问service-order的/userHello端口,不断刷新,发现已经实现了负载均衡。
来源:https://blog.51cto.com/14890694/2518860


猜你喜欢
- 目的:在使用mybatis框架中mapper文件有自动生成,但有时需要自己添加sql语句进行开发,当遇到需要使用 if进行条件判断的时候该怎
- AlertDialog可以在当前的界面上显示一个对话框,这个对话框是置顶于所有界面元素之上的,能够屏蔽掉其他控件的交互能力,因此AlertD
- 本文实例为大家分享了Java模拟实现斗地主发牌的具体代码,供大家参考,具体内容如下题目:模拟斗地主的发牌实现,54张牌,每张牌不同的花色(红
- 1. 前言SpringBoot在包扫描时,并不会扫描子模块下的内容,这样就使得我们的子模块中的Bean无法注入到Spring容器中。Spri
- 近期在开发中遇到一种需求:根据用户的权限决定是否显示某操作按钮。例如:若用户拥有删除数据的权限,则在界面中显示“删除”按钮;若用户无该权限,
- Android虚拟键盘的弹起会遮挡住部分ui,虽然通过在清单文件中设置,可以随着虚拟键盘的弹出,布局往上推,但是面对登陆界面时,并没有太大的
- 一、Jvm加载对象在说Java * 之前,还是要说一下Jvm加载对象的过程,这个依旧是理解 * 的基础性原理:Java类即源代码程序.j
- 方法1:使用内部APIs该方法和其他所有内部没有向外正式公布的APIs一样存在它自己的风险。原理是通过获得WindowManager的一个实
- 初学线程时,总是将 run 方法和 start 方法搞混,虽然二者是完全不同的两个方法,但刚开始使用时很难分清,原因就是因为初次使用时效果貌
- 动态SQL实现前端指定返回字段问题描述在使用ClickHouse时,遇到需要根据业务需求,动态返回指定字段,从而充分利用ClickHouse
- 最近正好也没什么可忙的,就回过头来鼓捣过去的知识点,到Servlet部分时,以前学习的时候硬是把从上到下的继承关系和接口实现记得乱七八糟。这
- 产生私钥和公钥System.Security.Cryptography.RSACryptoServiceProvider myrsa = n
- 一、总体概述官方文档:https://docs.devexpress.com/WindowsForms/8117/controls-and-
- 前台form 表单:设置method=post,enctype=multipart/form-data。struts2在原有的上传解析器继承
- 定义在类里面的类就叫做内部类。内部类的特点:在内部类中可以直接访问外部类的成员,包括私有的成员在外部类中不能直接访问内部类的成员,必须通过创
- LinearLayout<?xml version="1.0" encoding="utf-8"
- (1). 和反射+泛型有关的接口类型java.lang.reflect.Type:java语言中所有类型的公共父接口java.lang.re
- Eclipse的应用需要众多的插件,但是Eclipse的插件大家又知道多少呢?“Eclipse最牛的30个插件”不知道看官们是否了解,51C
- Starting创建手势密码可以查看 CreateGestureActivity.java 文件.登陆验证手势密码可以看 GestureLo
- 1、简介单例模式使⽤场景:业务系统全局只需要⼀个对象实例,⽐如发号器、 redis 连接对象等。Spring IOC容器中的 Bean 默认