一、介绍

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 {/*** Ribbon提供的负载均衡器*/@Autowiredprivate LoadBalancerClient loadBalancerClient;@Overridepublic 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-serviceSystem.out.println(si.getServiceId());// URI http://Application Service IP:端口System.out.println(si.getUri().toString());return null;}
}

三、Spring Web 之 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 {@Beanpublic 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;}/*** 任意请求方式, 返回值类型是集合。相对复杂的Java类型。* @return*/@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;}/*** 任意请求,传递路径地址参数* @param name* @param age* @return*/@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;}/*** post请求,请求体传递参数。参数使用@RequestBody处理。*/@PostMapping("/postBodyParams")public String postBodyParams(@RequestBody Map<String, String> params){System.out.println("端口号: " + port + " , post请求,有请求体参数, params = " +params);return "post请求,请求体参数, params = " + params;}/*** post请求,有参数*/@PostMapping("/postWithParams")public String postWithParams(String name, int age){System.out.println("端口号: " + port + " , post请求,有参数, name = " +name + " ; age = " + age);return "post请求有参数 : name = " +name + " ; age = " + age;}/*** post请求,没有参数*/@PostMapping("/postNoParams")public String postNoParams(){System.out.println("端口号: " + port + " , post请求,没有参数");return "post请求,没有参数";}/*** get请求,包含参数*/@GetMapping("/getWithParams")public String getWithParams(String name, int age){System.out.println("端口号: " + port + " 。 get请求,有参数, name = "+ name + " ; age = " + age);return "get请求,包含参数 : name = " + name + " ; age = " + age;}/*** get请求,没有参数* @return*/@GetMapping("/getNoParams")public String getNoParams(){System.out.println("端口号:" + port + "。 get请求,无参数。");return "get请求,无参数。";}
}

(2)无参数GET请求-getForObject

    /*** 发get请求。* 没有请求参数** <T> T getForObject(String url, Class<T> returnValueType, Object... params)* url - 要访问的具体地址* returnValueType - 服务器返回的响应体数据类型* params - 可选的请求参数* return - 响应体中的具体内容。*/@Testpublic void testGetNoParams(){// 定义要访问的地址是什么String url = baseUrl + "/getNoParams";// 发get请求。没有参数String result = restTemplate.getForObject(url, String.class);System.out.println("服务器返回:" + result);}

(3)有参数GET请求-getForObject

    /*** get请求,有参数* <T> T getForObject(String url, Class<T> returnValueType, Object... params)* <T> T getForObject(String url, Class<T> returnValueType, Map params)* 传递参数,就是处理请求地址url,并传递需要的参数。* 要传递参数,则处理请求地址url。使用{名字}作为占位变量。传递参数的时候,* 可以根据占位变量从左至右的顺序,使用可变长数组依次传递。* 也可以根据占位变量名称,做指定传递,使用map集合传递,map的key就是占位变量名,* map的value,是要传递的请求参数。*/@Testpublic 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

    /*** 在RestTemplate中。除方法getForObject以外,还有getForEntity。*  方法除返回值类型,其他一致。* <T> ResponseEntity<T> getForEntity(String url, Class<T> returnValueType,*       Object... params)* ResponseEntity - 包含响应头和响应体。* 如果需要对响应头做特殊处理,使用getForEntity方法。*/@Testpublic 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请求

    /*** post请求,没有参数* <T> T postForObject(String url, Object body, Class<T> returnBodyType,*            Object... params);* <T> T postForObject(String url, Object body, Class<T> returnBodyType,*            Map params);* body参数 - 使用post请求方式发请求的时候,请求体是什么?*   建议传递的对象类型是HttpEntity。*   如果对请求体没有要求,可以传递null。*/@Testpublic void testPostNoParams(){String url = baseUrl + "/postNoParams";String result =restTemplate.postForObject(url, null, String.class);System.out.println("post请求,无参数,服务器返回:" + result);}

(6)post请求路径地址传递参数

    /*** post请求,有参数* 1. 请求地址传递参数。 请求头传参。 传参方式和get一样。* 2. 请求体表单参数。 请求体传参。 需要提供请求体数据*/@Testpublic 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请求表单传递参数

    /*** spring web在处理请求头和请求体的时候,* 需要HttpMessageConverter提供数据转换处理。* HttpMessageConverter是接口,由Spring WEB定义。* 具体实现,需要依赖不同的具体技术实现。* 一般都使用jackson做实现。请求头和体数据,都是基于JSON转换的。*/@Testpublic void testPostWithParamsForm(){String url = baseUrl + "/postWithParams";// 创建请求体信息。// 请求头, 表单请求。  application/x-www-form-urlencodedHttpHeaders 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请求请求体传递参数

    /*** post请求,有参数* 使用请求体传递参数。@RequestBody处理请求参数。*  1. 请求参数只能在请求体中,以字符串描述,且是一个完整的请求参数。此参数没有名称。如:JSON*  2. 请求头 content-type的设置,和具体的参数值的格式相关,如: JSON对应的content-type是application/json*     如:xml字符串对应的content-type是application/xml*  3. 请求体传递的参数,只能由唯一的一个完整参数。可以同时携带表单参数和地址栏参数。*/@Testpublic 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);}@Testpublic 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-8String result = restTemplate.postForObject(url, params, String.class);System.out.println("返回结果:" + result);}

(9)RestFUL传递参数

    /*** 使用get请求方式,传递restful参数*/@Testpublic void testRestfulParams(){String url = baseUrl + "/restfulParams/{name}/{age}";// 访问String result = restTemplate.getForObject(url, String.class, "restful", "15");System.out.println(result);}

(10)Exchange通用处理方案(处理相对复杂的结果类型例如自定义类型数组)

    /*** RestTemplate类型中的通用方法,exchange。可以提交任意方式的请求。* 且可以定义相对复杂的返回类型。如:带有泛型要求的集合。** <T> ResponseEntity<T> exchange(String url, HttpMethod requestMethod, HttpEntity http,*                                Class<T> returnType, Object... params)* <T> ResponseEntity<T> exchange(String url, HttpMethod requestMethod, HttpEntity http,*                                Class<T> returnType, Map params)* <T> ResponseEntity<T> exchange(String url, HttpMethod requestMethod, HttpEntity http,*                                ParameterizedTypeReference<T> returnType, Object... params)* <T> ResponseEntity<T> exchange(String url, HttpMethod requestMethod, HttpEntity http,*                                ParameterizedTypeReference<T> returnType, Map... params)*/@Testpublic 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);}

四、基于RestTemplate和Ribbon实现Application Client调用Application Service集群

 (1)编写配置类

@Configuration
public class AppClientConfiguration {/*** 创建RestTemplate对象的方法,增加注解* LoadBalanced - 把Spring Cloud封装的LoadBalancerClient于RestTemplate整合。* 让RestTemplate自带负载均衡能力。仅在当前的Ribbon环境中生效。* 逻辑是:*  请求  http://服务名称/具体地址.  RestTemplate解析请求地址。*  把服务名称解析出,作为参数,调用LoadBalancerClient中的choose方法。*  把返回的ServiceInstance.getUri().toASCIIString()作为服务器地址,拼接上*  请求的具体地址。访问远程。* @return*/@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
}

(2)发起远程调用

@Service
public class ApplicationClientServiceImpl implements ApplicationClientService {@Autowiredprivate RestTemplate restTemplate;//http://服务名private final String baseUrl = "http://eureka-client-app-service";@Overridepublic 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对象管理方法

    @Beanpublic IRule iRule(){return new RandomRule();}

Spring Cloud Netfilx Ribbon(负载均衡工具)相关推荐

  1. SpringCloud学习笔记(6)----Spring Cloud Netflix之负载均衡-Ribbon的使用

    1. 什么是负载均衡? 负载均衡,就是分发请求流量到不同的服务器. 负载均衡一般分为两种 1. 服务器端负载均衡(nginx) 2. 客户端负载均衡(Ribbon) 2. 服务提供者(spring-c ...

  2. 微服务(三) 【手摸手带你搭建Spring Cloud】 Ribbon 什么是负载均衡?spring cloud如何实现负载均衡?ribbon负载均衡有几种策略?Ribbon是什么?

    在上一章,我介绍了springcloud的eureka搭建.我们做了服务注册.最后我们还介绍了一些续约,失效剔除等参数配置.已经不需要再通过手动输入ip去访问服务,而是通过中心只需要通过服务名就可以获 ...

  3. Spring Cloud Gateway之负载均衡

    ​ 本人最近在学习Spring Cloud Gateway但是发现网上的相关文章都没有介绍其如何使用负载均衡策略,那么本篇文章就给大家带来如何使用Spring Cloud Gateway负载均衡策略. ...

  4. 【微服务~原始真解】Spring Cloud —— 什么是负载均衡?

  5. 网关 Spring Cloud Gateway 实战负载均衡(Spring Cloud Loadbalancer)

  6. 最新版Spring Cloud Alibaba微服务架构-Ribbon负载均衡篇

    文章目录 前言 一.Ribbon核心概念 二.服务器端负载均衡和Riboon客户端负载均衡 1.服务器端负载均衡: 2.Riboon客户端负载均衡: 三.Ribbon策略 四.Ribbon配置使用 五 ...

  7. Spring Cloud Ribbon 负载均衡客户端调用示例

    承接 Spring Cloud 最简入门示例 这一篇, 本篇演示如何使用负载均衡客户端 Ribbon 调用在Eureka注册的服务. Ribbon 是什么? Ribbon是Netflix 的开源项目, ...

  8. Spring Cloud概念+案例(eureka注册+拉取、ribbon负载均衡+重试)、netfix各组件介绍【上】

    Spring Cloud概念+案例(断路器)[下] https://blog.csdn.net/LawssssCat/article/details/104632719 [⭐️⭐️⭐️] Spring ...

  9. Spring Cloud 系列之 Netflix Ribbon 负载均衡

    什么是 Ribbon Ribbon 是一个基于 HTTP 和 TCP 的 客服端负载均衡工具,它是基于 Netflix Ribbon 实现的. 它不像 Spring Cloud 服务注册中心.配置中心 ...

最新文章

  1. 从键盘输入的十个整数中的最大数和最小数
  2. Java多线程中的Runnable和Thread
  3. c++ primer 5th 笔记:第二章
  4. 你的灯亮着吗阅读笔记之一
  5. php 获取浏览器时区,获取用户时区
  6. Spring MVC 3.0 返回JSON数据的方法
  7. 面向对象--选课系统作业
  8. Mac 更改Apache文件系统目录
  9. C# winform小票打印
  10. Unity3D物理渲染算法研究【PBR】
  11. web前端开发面试题
  12. sqlite stmt
  13. JavaScript数组扁平化
  14. 用python画小狗,用turtle画个单身狗送给自己~
  15. Elasticsearch:从零开始到搜索 - 使用 Elasticsearch 摄取管道玩转你的数据
  16. slxrom+v.21+原生android+4.2,小米MIX2S 魔趣OS 安卓9 MagiskV21版 完美ROOT 纯净完美 原生极简 纯净推荐...
  17. 多媒体计算机的概念是,多媒体计算机的基本概念.doc
  18. 虚拟机服务器校园网访问设置,配置VMware虚拟机用绕过校园网达到无线上网配置方法...
  19. isempty()函数用法
  20. redis连接失败 Connection refused: connect

热门文章

  1. 联盟里这么多企业,哪一家会是我的东家?
  2. java编译字节码转化程序下载_编译Java Application源程序文件将产生相应的字节码文件,这些字节码文件的扩展名为( )...
  3. Pyqt5+PIL在图片上写字
  4. 后台管理系统中的CRUD【以用户维护为例】
  5. 可变气门升程的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  6. echarts 堆叠柱状图label显示总和
  7. 如何删除电脑计算机用户,mininews怎么卸载_电脑上的mininews新闻如何删除-win7之家...
  8. 876链表的中间节点
  9. 微信小程序富文本中图片溢出,使用max-width无效
  10. 【Java】- JDK是什么?