Springcloud负载均衡Ribbon

Spring Cloud Ribbon 是一个客户端负载均衡器,且并不是单独进行部署的。Ribbon实现负载均衡有三个要素,服务发现、服务选择规则、服务监听。

一、Ribbon使用

1. 客户端负载均衡

负载均衡主要的功能就是缓解网络压力,实现系统的高可用。
在系统中,一般分为服务端负载均衡和客户端负载均衡。

  • 服务端负载均衡,存在代理对服务端的列表进行选择,并返回一个请求给客户端。
  • 客户端负载均衡时,把列表全部给客户端,代理相当于在客户端,均衡的操作逻辑在客户端完成。

Ribbon实现客户端负载均衡,请求列表维护在客户端,然后通过一定的规则,在列表中选择请求进行访问,最后达到负载均衡的效果。

在这里插入图片描述

2. Ribbon实例

本此实例的代码在上一篇文章中。
Springcloud服务治理EureKa。服务注册中心与客户端

  1. 首先启动一个服务注册中心
    application.yml

    server:
      port: 8080
    spring:
      application:
        name: eurekaApplication1
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8080/eureka/
        register-with-eureka: false	
    

    服务注册中心端口8080

  2. 启动两个服务提供者
    首先启动一个应用
    application.yml

    server:
      port: 8083
    spring:
      application:
        name: providerService
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8080/eureka/
    

    修改端口,重新启动一个
    application.yml

    server:
      port: 8084
    spring:
      application:
        name: providerService
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8080/eureka/
    
    @RestController
    public class MyController {
    
        @Autowired
        private DiscoveryClient client;
    
    
        @Qualifier("eurekaRegistration")
        @Autowired
        private Registration registration; //服务注册
    
        private final Logger logger = LoggerFactory.getLogger(MyController.class);
    
        @GetMapping("/hello")
        public String hello() {
    
            ServiceInstance instance = serviceInstance();
    
            String result = "host:port=" + instance.getUri() + ", service_id" + instance.getServiceId();
            logger.info(result);
    
            return "hello eureka";
        }
    
        private ServiceInstance serviceInstance() {
            List<ServiceInstance> list = client.getInstances(registration.getServiceId());
            if (list != null && list.size() > 0) {
                for (ServiceInstance itm : list) {
                    if (itm.getPort() == 8083) {
                        return itm;
                    }
                }
            }
            return null;
        }
    }
    
  3. 启动一个服务消费者

    @RestController
    public class ConsumerController {
    
        @Autowired
        RestTemplate restTemplate;
    
        /**
         * restTemplate 调用
         * @return
         */
        @GetMapping("/consumer")
        public String consumer(){
            return restTemplate.getForEntity("http://PROVIDERSERVICE/hello",String.class).getBody();
        }
    }
    

    application.yml

    server:
      port: 8090
    spring:
      application:
        name: consumerService
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8080/eureka/
    
  4. 测试
    查看服务注册中心界面
    在这里插入图片描述
    访问链接 http://localhost:8090/consumer
    在这里插入图片描述发现8084的控制台输出
    在这里插入图片描述再访问一次该链接
    发现8083的控制台输出
    在这里插入图片描述本例需要注意使用@LoadBalanced注解过的RestTemplate对象。

    @SpringBootApplication
    @EnableEurekaClient
    public class Eurekaconsumer2Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Eurekaconsumer2Application.class, args);
        }
    
        @Bean
        @LoadBalanced //负载均衡,否则restTemplate无法识别微服务名称
        RestTemplate restTemplate(){
            return new RestTemplate();
        }
    
    }
    

二、RestTemplate使用

RestTemplate 是由 Spring提供的一个客户端,主要用于对Rest服务进行访问。这个类提高了开发效率,使Http服务的通信得到简化,简化了提交表单的难度,还自带Json自动转换功能。

只要加上注解@LoadBalanced,就可以使用Ribbon的客户端负载均衡。

Http方法RestTemplate方法
GETgetForObject, getForEntity
POSTpostForObject, postForLocation
PUTPUT
DELETEDELETE
HEADheadForHeaders
OPTIONSoptionsForAllow
AnyExchange, excute

1. GET请求API

GET的API。
在这里插入图片描述

1.1 getForEntity方法

这个方法会返回ResponseEntity类型,这个类的源码可以知道使HttpEntity的扩展,包含HttpStatus与BodyBuilder的信息,说明可以对response进行处理。这个对象ResponseEntity是Spring对于Http请求响应response的封装。

HttpStatus是一个枚举类,包含了HTTP的请求状态,BodyBuilder封装请求体对象,父类HttpEntity包含了请求头信息对象HttpHeaders。

再来看这三个方法,主要是参数不同。

  1. public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)
    第一个参数为url,表示请求地址;第二个参数为responseType,表示请求响应体的封装类型;第三个为uriVariables,表示不定参数。
    如果返回的是基本类型String

    //消费者代码
    @RestController
    public class RibbonController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @GetMapping("/get1")
        public String getForEntity1(){
            ResponseEntity<String> forEntity = restTemplate.getForEntity("http://PROVIDERSERVICE/get1?id={1}", String.class, "12");
            String body = forEntity.getBody();
            System.out.println(body);
            return body;
        }
    }
    
    //生产者代码
    @GetMapping("/get1")
    public String getForEntity1(@RequestParam("id") Integer id) {
    
        System.out.println("id: "+id);
    
        ServiceInstance instance = serviceInstance();
    
        String result = "host:port=" + instance.getUri() + ", service_id" + instance.getServiceId();
        logger.info(result);
    
        return "hello eureka";
    }
    

    运行结果
    在这里插入图片描述如果返回的响应体是一个User对象,
    则代码应为

    //消费者代码
    @RestController
    public class RibbonController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @GetMapping("/get1")
        public String getForEntity1(){
            ResponseEntity<String> forEntity = restTemplate.getForEntity("http://PROVIDERSERVICE/get1?id={1}", User.class, "12");
            User body = forEntity.getBody();
            System.out.println(body);
            return body;
        }
    }
    

    上面的代码,会把占位符和第三个位置的数据进行替换,如果存在多个参数,按顺序书写就行。

  2. public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)
    第三个参数使用map进行封装,在url中,占位符需要使用map中的key作为参数

    @GetMapping("/get2")
    public String getForEntity2(){
        Map<String, Object> map = new HashMap<>();
        map.put("id","12");
        ResponseEntity<String> forEntity = restTemplate.getForEntity("http://PROVIDERSERVICE/get1?id={id}", String.class, map);
        String body = forEntity.getBody();
        return body;
    }
    
  3. public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType)
    这个方法使用URI对url与 uriVariavles进行封装。

    @GetMapping("/get3")
    public String getForEntity3(){
        UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://PROVIDERSERVICE/get1?id={id}").build().expand("12").encode();
        URI uri = uriComponents.toUri();
        String body = restTemplate.getForEntity(uri, String.class).getBody();
        return body;
    }
    

1.2 getForObject方法

getForObject 方式包含了HTTP转换为pojo的功能,通过HttpMessageConverter进行转换,将响应体Body的内容转换成对象。

User user = restTemplate.getForObject("http://PROVIDERSERVICE/get1?id={1}", User.class, "12");

返回的时候直接获取到pojo,不需要从HttpEntity中的getBody这个代码。

  1. public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)
  2. public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
  3. public <T> T getForObject(URI url, Class<T> responseType)

这三种方法的使用方式与getForEntity一样。

2. POST请求API

POST的API
在这里插入图片描述

2.1 postForLocation方法

	@Override
	@Nullable
	public URI postForLocation(String url, @Nullable Object request, Object... uriVariables)
			throws RestClientException {

		RequestCallback requestCallback = httpEntityCallback(request);
		HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor(), uriVariables);
		return (headers != null ? headers.getLocation() : null);
	}

	@Override
	@Nullable
	public URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables)
			throws RestClientException {

		RequestCallback requestCallback = httpEntityCallback(request);
		HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor(), uriVariables);
		return (headers != null ? headers.getLocation() : null);
	}

	@Override
	@Nullable
	public URI postForLocation(URI url, @Nullable Object request) throws RestClientException {
		RequestCallback requestCallback = httpEntityCallback(request);
		HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor());
		return (headers != null ? headers.getLocation() : null);
	}

这三种方法都是返回资源定位的URI。

三种方法操作基本一样,首先根据request返回一个RequestCallback, 然后执行execute返回headers,最后从headers获取location。

RequestCallback 允许将操作请求头写入请求体中,使用execute方法,对给定的URL执行HTTP方法,模板将总是关闭请求并处理任何错误。

这三种方法都是对给定的数据发送POST创建资源,返回HTTP头。

这三种方法的参数如同前面getForEntity一样。
public URI postForLocation(String url, @Nullable Object request, Object... uriVariables)
需要注意的是request可以是一个HttpEntity,可以当作一个完整的HTTP请求进行处理,里面包含了请求头和请求体。request也可以是一个普通对象,restTemplate 会把请求对象转换成HttpEntity进行处理,request的内容会被当成一个消息体进行处理。

2.2 postForObject方法

	@Override
	@Nullable
	public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
			Object... uriVariables) throws RestClientException {

		RequestCallback requestCallback = httpEntityCallback(request, responseType);
		HttpMessageConverterExtractor<T> responseExtractor =
				new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
		return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
	}

	@Override
	@Nullable
	public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType,
			Map<String, ?> uriVariables) throws RestClientException {

		RequestCallback requestCallback = httpEntityCallback(request, responseType);
		HttpMessageConverterExtractor<T> responseExtractor =
				new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
		return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
	}

	@Override
	@Nullable
	public <T> T postForObject(URI url, @Nullable Object request, Class<T> responseType)
			throws RestClientException {

		RequestCallback requestCallback = httpEntityCallback(request, responseType);
		HttpMessageConverterExtractor<T> responseExtractor =
				new HttpMessageConverterExtractor<>(responseType, getMessageConverters());
		return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
	}

使用同之前方法一样,返回封装对象。返回类型需要自己指定。

2.3 postForEntity方法

返回ResponseEntity。

3. PUT请求API

	@Override
	public void put(String url, @Nullable Object request, Object... uriVariables)
			throws RestClientException {

		RequestCallback requestCallback = httpEntityCallback(request);
		execute(url, HttpMethod.PUT, requestCallback, null, uriVariables);
	}

	@Override
	public void put(String url, @Nullable Object request, Map<String, ?> uriVariables)
			throws RestClientException {

		RequestCallback requestCallback = httpEntityCallback(request);
		execute(url, HttpMethod.PUT, requestCallback, null, uriVariables);
	}

	@Override
	public void put(URI url, @Nullable Object request) throws RestClientException {
		RequestCallback requestCallback = httpEntityCallback(request);
		execute(url, HttpMethod.PUT, requestCallback, null);
	}

通过put的请求方式对资源进行创建或者更新,没有返回值。
使用方式同之前的方法。

4. DELETE请求API

	@Override
	public void delete(String url, Object... uriVariables) throws RestClientException {
		execute(url, HttpMethod.DELETE, null, null, uriVariables);
	}

	@Override
	public void delete(String url, Map<String, ?> uriVariables) throws RestClientException {
		execute(url, HttpMethod.DELETE, null, null, uriVariables);
	}

	@Override
	public void delete(URI url) throws RestClientException {
		execute(url, HttpMethod.DELETE, null, null);
	}

使用delete删除操作,使用的都是唯一标识删除数据,不需要body体和返回值。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: Spring Cloud负载均衡Ribbon是一种客户端负载均衡工具,它可以将请求分发到多个服务提供者实例中,从而提高系统的可用性和性能。Ribbon可以根据不同的负载均衡策略来选择服务提供者,例如轮询、随机、加权轮询等。同时,Ribbon还支持服务发现和服务注册,可以自动地从服务注册中心获取可用的服务实例列表。在Spring Cloud微服务架构中,Ribbon是非常重要的一部分,它可以帮助我们构建高可用、高性能的微服务系统。 ### 回答2: Spring Cloud 负载均衡Ribbon 是一个在客户端上运行的组件,可以在目标服务之间分配传入请求,以降低每个服务的负载。Ribbon 提供了多种负载均衡策略,包括简单轮询、随机、使用可用性统计数据等。 在实践中,Ribbon 可以轻松地集成到 Spring Cloud 应用中,通过配置文件中的特殊前缀“@LoadBalanced”来激活负载均衡服务。Spring Cloud 应用可以使用 Ribbon 来调用其他 REST 服务,而不用担心网络瓶颈和性能问题。 使用 Ribbon 进行负载均衡的最大好处是其透明的实现,使得客户端无需感知分配策略的变化。具体来说,当使用 Ribbon 负载均衡时,客户端可以轮流使用不同的目标服务,而无需编写特定的代码。Ribbon 为开发人员提供了一致的抽象层,以便简化分配策略和请求转发的实现。 Ribbon 作为 Spring Cloud 的核心组件之一,可以与其他重要的云基础设施服务进行集成,例如 Eureka 服务注册、Zookeeper 服务发现和 Consul 网格。通过这种方式,Ribbon 可以很容易地在多个云基础设施服务之间进行切换和部署。此外,Ribbon 还支持快速故障转移和自动重试机制,以确保应用程序可以在单个节点或整个系统故障时保持高可用性。 ### 回答3: Spring Cloud是一个基于Spring Boot实现的云原生应用开发框架,其中Spring Cloud Ribbon是其核心组件之一,提供了负载均衡的功能。 在传统的架构中,为了保证高可用性和可扩展性,常常需要多个相同的应用实例来处理用户请求,这时候就需要使用负载均衡来将请求均匀地分配到各个实例上。Spring Cloud Ribbon就是为了实现这个目的而设计的。 Ribbon可以将所有服务实例看作是一个整体,通过算法(一般为轮询算法)将请求分配给各个实例,从而实现负载均衡Ribbon内部维护了一个可用服务实例列表,当有服务实例启动或宕机时,它会实时更新列表,保证了服务的动态感知和适应。 Ribbon还提供了一些负载均衡策略,比如轮询(Round Robin)、随机(Random)、最少连接(Least Connection)等,可以根据具体业务来选择不同的策略。 在Spring Cloud中,使用Ribbon进行负载均衡非常简单,只需要加上@LoadBalanced注解,就可以实现自动的负载均衡。具体步骤如下: 1. 引入spring-cloud-starter-ribbon依赖 2. 创建RestTemplate实例,并添加@LoadBalanced注解 3. 像普通的RestTemplate一样使用其get、post等方法发起请求即可 最后,需要注意的是,Ribbon只是一种负载均衡的实现方式,而且还有其它的负载均衡框架可以选择,比如Nginx、HAProxy等。选择哪种负载均衡框架,需要根据具体业务需求、系统规模等综合考虑。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zxg45

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值