一、前言 Ribbon
是基于 Netflix Ribbon
实现的一套客户端负载均衡器,它本身不属于 Spring Cloud Alibaba
提供的组件,而是 Spring Cloud
将其封装成 starter 供微服务使用。另外,笔者在之前的 文章 中也做过 Ribbon
相关的知识介绍,故本篇章只作为对 Ribbon
内容的补充。
二、介绍 2.1 RestTemplete 请求模板 Spring Cloud
底层对 Ribbon
做了二次封装,可以让我们使用 RestTemplate
的服务请求,同时搭配 @LoadBalanced
注解使用,从而实现客户端负载均衡的服务调用。
RestTemplate
提供两种方法 getForObject 和 getForEntity 去请求调用服务端的数据,接下来笔者将介绍 RestTemplate
基于 REST 的常用的 2 种请求方式。
2.1.1 GET 请求 无参情况:
1 2 3 4 5 6 7 ## 第一个参数:微服务接口地址,第二个参数:返回值类型 ResponseEntity<User> responseEntity = restTemplate.getForEntity("xxx", User.class); User user = responseEntity.getBody(); HttpStatus statusCode = responseEntity.getStatusCode(); int statusCodeValue = responseEntity.getStatusCodeValue(); HttpHeaders headers = responseEntity.getHeaders();
有参情况:
1 2 3 4 5 6 7 8 9 10 11 12 String[] paramArr = {"1000", "张三"}; ## 第一个参数:服务接口地址,第二个参数:返回值类型,第三个参数:入参数组 ResponseEntity<User> responseEntity = restTemplate.getForEntity("xxx?id={0}&name={1}", User.class, paramArr); Map<String, Object> paramMap = new HashMap<>(); paramMap.put("id", 1000); paramMap.put("name", "张三"); ## 第一个参数:服务接口地址,第二个参数:返回值类型,第三个参数:入参 Map ResponseEntity<User> responseEntity = restTemplate.getForEntity("xxx?id={id}&name={name}", User.class, paramMap);
2.1.2 POST 请求 方式一:使用 Map 传参
1 2 3 4 5 6 7 # 注意,使用的是 MultiValueMap 类型 MultiValueMap<String, Object> dataMap = new LinkedMultiValueMap<>(); dataMap.add("id", "1000"); dataMap.add("name", "张三"); # 第一个参数:服务接口地址,第二个参数:入参,第三个参数:返回值类型 ResponseEntity<User> responseEntity = restTemplate.postForEntity("xxx", dataMap, User.class);
注意:如果使用上边的方式传参,接口提供方使用 @RequestParam("id") Integer id
形式接收参数。
方式二:使用实体传参
1 2 3 4 5 6 User user = new User(); user.setId("1000"); user.setName("张三"); # 第一个参数:服务接口地址,第二个参数:入参,第三个参数:返回值类型 ResponseEntity<User> responseEntity = restTemplate.postForEntity("xxx", user, User.class);
注意:如果使用上边的方式传参,接口提供方使用 @RequestBody User user
形式接收参数。
方式三:使用 JSON 传参
1 2 3 4 5 6 7 String userJson = "{\"id\": 4, \"name\": \"张三\"}"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<String> entity = new HttpEntity<>(userJson, headers); # 第一个参数:服务接口地址,第二个参数:入参,第三个参数:返回值类型 ResponseEntity<User> responseEntity = restTemplate.postForEntity("xxx", entity, User.class);
注意:如果使用上边的方式传参,接口提供方使用 @RequestBody User user
形式接收参数。
方式四:已封装参数,URL 仍需添加额外参数
1 2 3 4 String token = "abc123"; # 第一个参数:服务接口地址,第二个参数:入参,第三个参数:返回值类型,第四个参数:配对 url 后边的参数 ResponseEntity<User> responseEntity = restTemplate.postForEntity("xxx?token={token}", user, User.class, token);
2.2 负载均衡 要使用 Ribbon
的负载均衡,只需要在 RestTemplate
的 Bean 上添加 @LoadBalanced
即可,如下:
使用 Ribbon
需要添加依赖:
1 2 3 4 5 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.2.RELEASE</version> </dependency>
1 2 3 4 5 6 7 8 9 @Configuration public class RestConfiguration { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } }
2.2.1 常规负载均衡策略 Ribbon
的负载均衡策略是由 IRule
接口定义, 该接口有如下实现:
从图中可知,Ribbon
已经默认实现了多种负载均衡策略,我们可以根据自己的实际情况替换这些策略:
负载均衡实现类 策略 RandomRule 随机 RoundRobinRule 轮询 AvailabilityFilteringRule 先过滤掉由于多次访问故障的服务,以及并发连接数超过阈值的服务,然后对剩下的服务按照轮询策略进行访问 WeightedResponseTimeRule 根据平均响应时间计算所有服务的权重,响应时间越快服务权重就越大被选中的概率即 越高,如果服务刚启动时统计信息不足,则使用RoundRobinRule策略,待统计信息足够会切换到该WeightedResponseTimeRule策略 RetryRule 先按照RoundRobinRule策略分发,如果分发到的服务不能访问,则在指定时间内进行重 试,然后分发其他可用的服务 BestAvailableRule 先过滤掉由于多次访问故障的服务,然后选择一个并发量最小的服务 ZoneAvoidanceRule (默认) 综合判断服务节点所在区域的性能和服务节点的可用性,来决定选择哪个服务
如果想替换默认的负载均衡策略,操作非常简单,只需重新创建 IRule
接口的实现即可,我们拿 RoundRobinRule
举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Configuration public class RestConfiguration { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } @Bean public IRule testRule() { return new RoundRobinRule(); } }
这样,启动项目后,Ribbon
就会使用该策略进行接口调用了。
2.2.2 自定义负载均衡策略 如果上述的策略不满足自身要求,我们还可以自定义负载均衡策略,需要操作 2 个步骤:
第一步,实现 AbstractLoadBalancerRule
接口,例如:
1 2 3 4 5 6 7 8 9 10 11 12 public class MyNacosRule extends AbstractLoadBalancerRule { @Override public void initWithNiwsConfig(IClientConfig clientConfig) { //基本上不需要实现 } @Override public Server choose(Object key) { //实现该方法 } }
第二步,配置文件(application.properties 或 application.yml)配置负载均衡策略:
1 xxx.ribbon.NFLoadBalancerRuleClassName=com.light.ribbon.MyNacosRule
其中,xxx表示远程服务的名称。
评论