SpringCloudNetfilxRibbon负载均衡工具使用方法介绍
一、介绍
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个Spring Cloud构建的微服务和基础设施中。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,包括后续我们将要学习的OpenFeign,它也是基于Ribbon实现负载均衡的远程服务调用工具。所以,对Spring Cloud Ribbon的理解和使用,对于我们使用Spring Cloud来构建微服务非常重要.
二、使用
@Service
public class ApplicationClientServiceImpl implements ApplicationClientService {
@Autowired
private LoadBalancerClient loadBalancerClient;
@Override
public String client() {
ServiceInstance si = loadBalancerClient.choose("application-service");
// 获取Application Service IP。
System.out.println(si.getHost());
// 获取Ip及端口。
System.out.println(si.getInstanceId());
// 端口
System.out.println(si.getPort());
// 应用程序名 application-service
System.out.println(si.getServiceId());
// URI http://Application Service IP:端口
System.out.println(si.getUri().toString());
return null;
}
}
三、SpringWeb之RestTemplate基于Http协议的远程访问
要想使用RestRemplate必须自己配置
package com.bjsxt.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class MyConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
(1)控制器
@RestController
public class ServerController {
@Value("${server.port}")
private int port;
@RequestMapping("/returnUsers")
public List<User> returnUsers(int nums){
List<User> result = new ArrayList<>();
for(int i = 0; i < nums; i++){
result.add(new User(100 + i, "姓名-" + i, 20+i));
}
return result;
}
@RequestMapping("/returnList")
public List<String> returnList(int nums){
List<String> result = new ArrayList<>();
for(int i = 0; i < nums; i++){
result.add("返回结果 - " + i);
}
return result;
}
@RequestMapping("/restfulParams/{name}/{age}")
public String restfulParams(@PathVariable("name") String name,
@PathVariable int age){
System.out.println("端口号: " + port + ", 任意请求方式,restful参数, name = " +
name + " ; age = " + age);
return "restful参数, name = " + name + " ; age = " + age;
}
@PostMapping("/postBodyParams")
public String postBodyParams(@RequestBody Map<String, String> params){
System.out.println("端口号: " + port + " , post请求,有请求体参数, params = " +
params);
return "post请求,请求体参数, params = " + params;
}
@PostMapping("/postWithParams")
public String postWithParams(String name, int age){
System.out.println("端口号: " + port + " , post请求,有参数, name = " +
name + " ; age = " + age);
return "post请求有参数 : name = " +
name + " ; age = " + age;
}
@PostMapping("/postNoParams")
public String postNoParams(){
System.out.println("端口号: " + port + " , post请求,没有参数");
return "post请求,没有参数";
}
@GetMapping("/getWithParams")
public String getWithParams(String name, int age){
System.out.println("端口号: " + port + " 。 get请求,有参数, name = "
+ name + " ; age = " + age);
return "get请求,包含参数 : name = " + name + " ; age = " + age;
}
@GetMapping("/getNoParams")
public String getNoParams(){
System.out.println("端口号:" + port + "。 get请求,无参数。");
return "get请求,无参数。";
}
}
(2)无参数GET请求-getForObject
@Test
public void testGetNoParams(){
// 定义要访问的地址是什么
String url = baseUrl + "/getNoParams";
// 发get请求。没有参数
String result = restTemplate.getForObject(url, String.class);
System.out.println("服务器返回:" + result);
}
(3)有参数GET请求-getForObject
@Test
public void testGetWithParams(){
String url = baseUrl + "/getWithParams?name={x}&age={y}";
String result1 =
restTemplate.getForObject(url, String.class,
"张三", "20");
System.out.println("可变长数组传递参数,服务器返回:" + result1);
System.out.println("==========================================");
Map<String, Object> params = new HashMap<>();
params.put("x", "李四");
params.put("y", 25);
String result2 =
restTemplate.getForObject(url, String.class, params);
System.out.println("Map集合传递参数,服务器返回:" + result2);
}
(4)GET请求-getForEntity
@Test
public void testGetForEntity(){
String url = baseUrl + "/getNoParams";
ResponseEntity<String> entity =
restTemplate.getForEntity(url, String.class);
HttpHeaders headers = entity.getHeaders();
for(String headerName : headers.keySet()){
System.out.println("响应头: " + headerName + " = "
+ headers.get(headerName));
}
System.out.println("响应状态码: " + entity.getStatusCodeValue());
System.out.println("响应体数据: " + entity.getBody());
}
(5)无参数POST请求
@Test
public void testPostNoParams(){
String url = baseUrl + "/postNoParams";
String result =
restTemplate.postForObject(url, null, String.class);
System.out.println("post请求,无参数,服务器返回:" + result);
}
(6)post请求路径地址传递参数
@Test
public void testPostWithParamsPath(){
String url = baseUrl + "/postWithParams?name={1}&age={2}";
String result =
restTemplate.postForObject(url, null, String.class,
"王五", 30);
System.out.println(result);
}
(7)post请求表单传递参数
@Test
public void testPostWithParamsForm(){
String url = baseUrl + "/postWithParams";
// 创建请求体信息。
// 请求头, 表单请求。 application/x-www-form-urlencoded
HttpHeaders headers = new HttpHeaders();
headers.add("content-type", "application/x-www-form-urlencoded");
// 表单
MultiValueMap<String, Object> form =
new LinkedMultiValueMap<>();
// add 提供一个 请求参数 名 = 值。
form.add("name", "尼古拉斯.赵四");
form.add("age", 40);
// put 提供 键值对
//form.put("name", Arrays.asList("尼古拉斯.赵四"));
//List<Object> ages = new ArrayList<>();
//ages.add(40);
//form.put("age", ages);
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(form, headers);
String result =
restTemplate.postForObject(url, entity, String.class);
System.out.println(result);
}
(8)post请求请求体传递参数
@Test
public void testPostBodyParams(){
String url = baseUrl + "/postBodyParams";
// 创建请求参数, 使用JSON格式的字符串,描述一个Map集合。
String params = "{\"key1\":\"value1\", \"key2\":\"value2\"}";
// 创建请求时,使用的请求体描述
HttpHeaders headers = new HttpHeaders();
headers.add("content-type", "application/json;charset=utf-8");
HttpEntity<String> entity = new HttpEntity<>(params, headers);
String result = restTemplate.postForObject(url, entity, String.class);
System.out.println("返回结果:" + result);
}
@Test
public void testPostBodyParams2(){
// 可以使用简单的处理方案,实现请求体传递JSON格式的数据
// 使用postForObject(),第二个参数,直接传递一个Java对象,作为请求体中传递的参数。
// 参数没有名字,由RestTemplate做数据转换,默认使用JSON格式字符串做转换结果。
String url = baseUrl + "/postBodyParams";
// 创建Map类型的参数对象
Map<String, String> params = new HashMap<>();
params.put("name", "测试");
params.put("gender", "男");
// 请求服务器。 直接传递java对象,默认请求头content-type=application/json;charset=utf-8
String result = restTemplate.postForObject(url, params, String.class);
System.out.println("返回结果:" + result);
}
(9)RestFUL传递参数
@Test
public void testRestfulParams(){
String url = baseUrl + "/restfulParams/{name}/{age}";
// 访问
String result = restTemplate.getForObject(url, String.class, "restful", "15");
System.out.println(result);
}
(10)Exchange通用处理方案(处理相对复杂的结果类型例如自定义类型数组)
@Test
public void testExchangeMethod(){
String url = baseUrl + "/returnList?nums={1}";
// 相对复杂的返回结果类型描述对象
url = baseUrl + "/returnUsers?nums={1}";
ParameterizedTypeReference<List<User>> type =
new ParameterizedTypeReference<List<User>>() {};
// 访问远程
ResponseEntity<List<User>> entity =
restTemplate.exchange(url, HttpMethod.GET, null, type, 3);
List<User> body = entity.getBody();
System.out.println(body);
}
四、调用Application Service集群
基于RestTemplate和Ribbon实现Application Client调用Application Service集群
(1)编写配置类
@Configuration
public class AppClientConfiguration {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
(2)发起远程调用
@Service
public class ApplicationClientServiceImpl implements ApplicationClientService {
@Autowired
private RestTemplate restTemplate;
//http://服务名
private final String baseUrl = "http://eureka-client-app-service";
@Override
public String getNoParams() {
String url = baseUrl + "/getNoParams";
// 访问
String result = restTemplate.getForObject(url, String.class);
System.out.println(result);
return result;
}
}
五、Ribbon负载均衡算法
Ribbon的负载均衡策略是通过不同的类型来实现的(都是IRule接口的实现),下表详细介绍一些常用负载均衡策略及对应的Ribbon策略类。
编号 | 策略名称 | 策略对应的类名 | 实现原理 |
---|---|---|---|
1 | 轮询策略(默认) | RoundRobinRule | 轮询策略表示每次都按照顺序取下一个application service,比如一共有5个application service,第1次取第1个,第2次取第2个,第3次取第3个,以此类推 |
2 | 权重轮询策略(常用,中小型项目使用) | WeightedResponseTimeRule | 1.根据每个application service的响应时间分配一个权重,响应时间越长,权重越小,被选中的可能性越低。 2.原理:一开始为轮询策略,并开启一个计时器,每30秒收集一次每个application service的平均响应时间,当信息足够时,给每个application service附上一个权重,并按权重随机选择application service,权重越高的application service会被高概率选中。 |
3 | 随机策略(不推荐,测试使用,开发使用) | RandomRule | 从application service列表中随机选择一个 |
4 | 最少并发数策略(应用在硬件软件环境一致的情况下,中小型项目使用) | BestAvailableRule | 选择正在请求中的并发数最小的application service,除非这个application service在熔断中。 |
5 | 重试策略。在“选定的负载均衡策略”基础上进行重试机制 | RetryRule | 1.“选定的负载均衡策略”这个策略是轮询策略RoundRobinRule 2.该重试策略先设定一个阈值时间段,如果在这个阈值时间段内当选择application service不成功,则一直尝试采用“选定的负载均衡策略:轮询策略”最后选择一个可用的application service |
6 | 可用性敏感策略(一般在同区域内服务集群环境中使用) | AvailabilityFilteringRule | 过滤性能差的application service,有2种: 第一种:过滤掉在eureka中处于一直连接失败application service 第二种:过滤掉高并发的application service |
7 | 区域敏感性策略(应用在大型的,物理隔离分布式环境中) | ZoneAvoidanceRule | 1.以一个区域为单位考察可用性,对于不可用的区域整个丢弃,从剩下区域中选可用的application service 2.如果这个ip区域内有一个或多个实例不可达或响应变慢,都会降低该ip区域内其他ip被选中的权重。 |
指定负载均衡策略,新增Bean对象管理方法
@Bean
public IRule iRule(){
return new RandomRule();
}
到此这篇关于SpringCloud Netfilx Ribbon负载均衡工具使用方法介绍的文章就介绍到这了,更多相关SpringCloud Netfilx Ribbon内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341