Spring Cloud负载均衡及远程调用实现详解
负载均衡
使用微服务后,为了能够承担高并发的压力,同一个服务可能会启动多个实例。这时候消费者就需要负载均衡,把请求分散到各个实例。负载均衡主要有两种设计:
服务端负载均衡客户端负载均衡
对于传统的分布式服务来说,大多使用服务端负载均衡。一般会使用Nginx或者ELB等工具作为负载均衡器,如下图:
而在SpringCloud中,使用的是「客户端负载均衡」的方式,使用「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 publicclassHelloController{ @Value("${spring.cloud.consul.discovery.instanceId}") privateStringinstanceId; @GetMapping("hello") publicStringhello(){ returnString.format("hello,thisis%s",instanceId); } }
然后对于消费者「service-order」,可以使用Java声明式注解的方式来使用Ribbon,只需要在消费者给RestTemplate类型的Bean配上一个@LoadBalanced就可以了。然后再配置一下负载均衡策略:
@Configuration publicclassRibbonConfig{ @Bean @LoadBalanced publicRestTemplateribbonRestTemplate(){ returnnewRestTemplate(); } @Bean publicIRuleribbonRule(){ returnnewRandomRule();//随机负载均衡 } }
然后就可以直接使用自动注入的RestTemplate类型的Bean了:
@RestController @RequestMapping publicclassHelloController{ @Autowired RestTemplaterestTemplate; @GetMapping("/ribbon/service-user") publicStringribbonService(){ returnrestTemplate.getForObject("http://service-user/hello",String.class); } }
这个时候访问消费者的/ribbon/service-user,刷新几次,就会看到下面两个随机的响应:
hello,thisisservice-user-2
hello,thisisservice-user-1
负载均衡策略
查看IRule接口的实现类,可以看到Ribbon的所有负载均衡策略,查看各实现类顶部的注释可以看到它的具体策略:
- RandomRule:随机选择;
- RoundRobinRule:轮询;
- WeightedResponseTimeRule:根据每个服务的响应时间设置权重,响应时间越长,所占权重越少;
- AvailabilityFilteringRule:过滤掉那些因为一直连接失败的被标记为circuittripped的后端server,并过滤掉那些高并发的的后端server(activeconnections超过配置的阈值);
- ZoneAvoidanceRule:使用CompositePredicate根据区域和可用性过滤服务器的规则;
- BestAvailableRule:选择一个最小的并发请求的server;
- RetryRule:在现有的策略基础上,添加重试机制,因为IRule支持「级联」。
远程调用
SpringCloud提供了OpenFeign组件(以前叫Feign)来进行远程的HTTP调用。它是对RestTemplate的一个封装。
Feign是一个声明式WebService客户端。使用Feign能让编写WebService客户端更加简单。SpringCloud对Feign进行了封装,使其支持了SpringMVC标准注解和HttpMessageConverters。Feign可以与微服务注册中心和Ribbon组合使用以支持负载均衡。
使用OpenFeign
第一步,引入依赖:
implementation'org.springframework.cloud:spring-cloud-starter-openfeign'
第二步,启动配置,在启动类上添加@EnableFeignClients注解:
@SpringBootApplicationbr/>@EnableFeignClients publicclassServiceOrderApplication{ publicstaticvoidmain(String[]args){ SpringApplication.run(ServiceOrderApplication.class,args); } }
第三步:声明调用接口,我这里案例是service-order调用service-user的/hello接口,这里的注解就跟SpringMVC的注解一致:
注意Feign在做POST请求的时候有一个小坑,详情参考:SpringCloudFeignPost表单请求。
@FeignClient("service-user") publicinterfaceUserClient{ @GetMapping("hello") StringgetUserHello(); }
第四步:使用,注解使用@Autowired注解注入就可以了:
@RestController @RequestMapping publicclassHelloController{ @Autowired UserClientuserClient; @GetMapping("hello") publicStringhello(){ return"hello,thisisorderservice"; } @GetMapping("userHello") publicStringuser(){ returnuserClient.getUserHello()+",thisisorder-service"; } }
是不是看起来非常简单?
OpenFeign集成Ribbon
前面我们提到,OpenFeign底层是对RestTemplate的一个封装,而Ribbon是通过给RestTemplate添加过滤器来实现的,所以OpenFeign天生就自动集成了Ribbon,我们不需要任何额外的配置。
在上述代码中,启动后,可以访问service-order的/userHello端口,不断刷新,发现已经实现了负载均衡。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。