Spring Cloud:第三章:Ribbon客服端负载均衡

本文涉及的产品
网络型负载均衡 NLB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
简介: Spring Cloud:第三章:Ribbon客服端负载均衡

负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段。理解Ribbon对于我们使用Spring Cloud来讲非常的重要。它是一个基于Http和TCP的客户端负载均衡工具。它不像服务注册中心、配置中心、API网关那样独立部署,但是它几乎存在于每个微服务的基础设施中。

基于Ribbon+RestTemplate的用法

1、引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

注意:Eureka默认集成了Ribbon,只需引入Eureka JAR即可。

2、在启动类中注入配置

package com.mimaxueyuan.consumer.robbin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
public class RibbonConsumerApplication {
    @Bean
    @LoadBalanced // 需要使用负载均衡,必须与Bean一同使用
    public RestTemplate balanceRestTemplate() {
        return new RestTemplate();
    }
    @Primary //自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常 
    @Bean //需要多个RestTemplate, 有的RestTemplate使用负载均衡,有的不使用,不使用的不增加@LoadBalanced注解
    public RestTemplate noBalanceRestTemplate() {
        return new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(RibbonConsumerApplication.class, args);
    }
}

3、编写 Controller——演示使用负载均衡和不使用负载均衡的用法及区别

package com.mimaxueyuan.consumer.robbin.controller;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.mimaxueyuan.consumer.entity.User;
@RestController
public class RibbonController {
    // 注入restTemplate, 这个类已经在RibbonConsumerApplication中初始化,不使用负载均衡
    @Autowired
    private RestTemplate noBalanceRestTemplate;
    // 注入restTemplate, 这个类已经在RibbonConsumerApplication中初始化,并且使用负载均衡
    @Autowired // 默认按照类型注入,如果需要按照名字注入需要使用@Qualifier注解
    //@LoadBalanced //使用带有负载均衡的RestTemplate
    @Qualifier("balanceRestTemplate")
    private RestTemplate balanceRestTemplate;
    // 以下注入负载均衡客户端LoadBalancerClient是一个接口,下面只有一个RibbonLoadBalancerClient实现类
    @Autowired
    private LoadBalancerClient loadBalancerClient;
    @Autowired
    private RibbonLoadBalancerClient ribbonLoadBalancerClient;
    /**
     * 不使用ribbon的旧调用方式
     *
     * @author Kevin
     * @Title: old
     * @return
     * @return: String
     */
    @GetMapping("/ribbon/old/get/{id}")
    public String old(@PathVariable("id") String id) {
        // 使用noBalanceRestTemplate是非负载均衡的,所以没问题
        String result = noBalanceRestTemplate.getForObject("http://localhost:9907/get/"+id, String.class);
        System.out.println("[hardcode1]" + result);
        // 由于balanceRestTemplate已经使用了Ribbon做负载均衡,所以使用硬编码方式就不允许了,会提示:No instances available for localhost
        result = balanceRestTemplate.getForObject("http://localhost:9907/get/"+id, String.class);
        System.out.println("[hardcode2]" + result);
        return "result";
    }
    /**
     * ribbon使用
     *
     * @author Kevin
     * @Title: ribbon 
     * @param id
     * @return
     * @return: String
     */
    @GetMapping("/ribbon/get/{id}")
    public String ribbon(@PathVariable("id") String id) {
        // -----------------以下代码使用ribbon做客户端负载均衡
        // 使用provider的instanceName替代ip和端口的硬编码
        String result = balanceRestTemplate.getForObject("http://mima-cloud-producer/get/"+id, String.class);
        System.out.println("[ribbon]" + result);
        System.out.println("[loadBalancerClient]choose的结果,代表负载均衡之后要选择的服务实例");
        ServiceInstance instance = loadBalancerClient.choose("mima-cloud-producer");
        System.out.println("host:" + instance.getHost() + ",port:" + instance.getPort() + ",serviceId=" + instance.getServiceId() + ",uri=" + instance.getUri());
        System.out.println("[ribbonLoadBalancerClient]choose的结果,代表负载均衡之后要选择的服务实例");
        instance = ribbonLoadBalancerClient.choose("mima-cloud-producer");
        System.out.println("host:" + instance.getHost() + ",port:" + instance.getPort() + ",serviceId=" + instance.getServiceId() + ",uri=" + instance.getUri());
        System.out.println("[ribbonLoadBalancerClient]choose的结果,代表负载均衡之后要选择的服务实例");
        instance = ribbonLoadBalancerClient.choose("mima-cloud-producer");
        System.out.println("host:" + instance.getHost() + ",port:" + instance.getPort() + ",serviceId=" + instance.getServiceId() + ",uri=" + instance.getUri());
        try {
            // 根据负载均衡后的服务,构建一个访问url
            // 第二个参数不能为null
            System.out.println("根据负载均衡后的服务,构建一个访问url");
            URI reconstructURI = ribbonLoadBalancerClient.reconstructURI(instance, new URI(""));
            System.out.println("reconstructURI1-yes:" + reconstructURI);
            // 拼写在请求地址后边,需要注意是否需要添加/
            reconstructURI = ribbonLoadBalancerClient.reconstructURI(instance, new URI("/ribbon/get"));
            System.out.println("reconstructURI2-yes:" + reconstructURI);
            reconstructURI = ribbonLoadBalancerClient.reconstructURI(instance, new URI("http"));
            System.out.println("reconstructURI3-no:" + reconstructURI);
            reconstructURI = ribbonLoadBalancerClient.reconstructURI(instance, new URI("https"));
            System.out.println("reconstructURI4-no:" + reconstructURI);
            reconstructURI = ribbonLoadBalancerClient.reconstructURI(instance, new URI("test"));
            System.out.println("reconstructURI5-no:" + reconstructURI);
            // 使用http:/xxx、https:/xxx可以用于切换http协议还是https协议
            reconstructURI = ribbonLoadBalancerClient.reconstructURI(instance, new URI("http:/ribbin/get"));
            System.out.println("reconstructURI6-yes:" + reconstructURI);
            reconstructURI = ribbonLoadBalancerClient.reconstructURI(instance, new URI("https:/ribbin/get"));
            System.out.println("reconstructURI7-yes:" + reconstructURI);
        } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return "ribbon's demo,please to see console output";
    }
    @GetMapping("/nobalance/get/{id}")
    public String nobalance(@PathVariable("id") String id) {
        // -----------------以下代码使用硬编码方式调用服务
        // 如果restTemplate已经使用了Ribbon做负载均衡,也就是使用了@LoadBaleced注解,依然使用硬编码方式就不允许了,会提示:No instances available for localhost
        String result = noBalanceRestTemplate.getForObject("http://localhost:9907/get/"+id, String.class);
        System.out.println("[noBalanceRestTemplate-hardcode1]" + result); //正常访问
        result = noBalanceRestTemplate.getForObject("http://localhost:9908/get/"+id, String.class);
        System.out.println("[noBalanceRestTemplate-hardcode2]" + result); //正常访问
        try {
            //异常访问,Ribbon负载均衡只能通过服务名调用
            result = balanceRestTemplate.getForObject("http://localhost:9907/get/"+id, String.class);
            System.out.println("[balanceRestTemplate-hardcode1]" + result); 
            //异常访问,Ribbon负载均衡只能通过服务名调用
            result = balanceRestTemplate.getForObject("http://localhost:9908/get/"+id, String.class);
            System.out.println("[balanceRestTemplate-hardcode2]" + result); 
        } catch (Exception e) {
            System.out.println("使用balanceRestTemplate同时使用地址硬编码错误:" + e.getMessage());
        }
        return "ribbon's demo,please to see console output";
    }
    @SuppressWarnings("unchecked")
    @GetMapping("listAll")
    public List<User> listAll() {
        // restTemplate怎样返回一个List对象
        List<User> list = balanceRestTemplate.getForObject("http://mima-cloud-producer/listAll", List.class);
        return list;
    }
}

其中 mima-cloud-producer 为服务名,启动两个服务节点如下:

http://localhost:9907/

http://localhost:9908/

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
1月前
|
负载均衡 Java Nacos
Ribbon负载均衡
Ribbon负载均衡
33 1
Ribbon负载均衡
|
1月前
|
负载均衡 监控 网络协议
SpringCloud之Ribbon使用
通过以上步骤,就可以在Spring Cloud项目中有效地使用Ribbon来实现服务调用的负载均衡,提高系统的可靠性和性能。在实际应用中,根据具体的业务场景和需求选择合适的负载均衡策略,并进行相应的配置和优化,以确保系统的稳定运行。
74 15
|
1月前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
89 5
|
22天前
|
负载均衡 Java Nacos
常见的Ribbon/Spring LoadBalancer的负载均衡策略
自SpringCloud 2020版起,Ribbon被弃用,转而使用Spring Cloud LoadBalancer。Ribbon支持轮询、随机、加权响应时间和重试等负载均衡策略;而Spring Cloud LoadBalancer则提供轮询、随机及Nacos负载均衡策略,基于Reactor实现,更高效灵活。
54 0
|
3月前
|
负载均衡 Java Nacos
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
微服务介绍、SpringCloud、服务拆分和远程调用、Eureka注册中心、Ribbon负载均衡、Nacos注册中心
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
|
3月前
|
负载均衡 Java 开发者
Ribbon框架实现客户端负载均衡的方法与技巧
Ribbon框架为微服务架构中的客户端负载均衡提供了强大的支持。通过简单的配置和集成,开发者可以轻松地在应用中实现服务的发现、选择和负载均衡。适当地使用Ribbon,配合其他Spring Cloud组件,可以有效提升微服务架构的可用性和性能。
48 0
|
13天前
|
机器学习/深度学习 自然语言处理 搜索推荐
深度分析 | 2024主流的智能客服系统有哪些?他们是怎么实现的?
本文深入探讨了智能客服系统的使用方法和相关技术实现逻辑,涵盖前端交互、服务接入、逻辑处理、数据存储四大层面,以及自然语言处理、机器学习、语音识别与合成、数据分析与挖掘、知识库管理和智能推荐系统等核心技术,帮助企业更好地理解和应用智能客服系统,提升服务效率和客户满意度。
77 1
|
2月前
|
存储 自然语言处理 机器人
实战揭秘:当RAG遇上企业客服系统——从案例出发剖析Retrieval-Augmented Generation技术的真实表现与应用局限,带你深入了解背后的技术细节与解决方案
【10月更文挑战第3天】随着自然语言处理技术的进步,结合检索与生成能力的RAG技术被广泛应用于多个领域,通过访问外部知识源提升生成内容的准确性和上下文一致性。本文通过具体案例探讨RAG技术的优势与局限,并提供实用建议。例如,一家初创公司利用LangChain框架搭建基于RAG的聊天机器人,以自动化FAQ系统减轻客服团队工作负担。尽管该系统在处理简单问题时表现出色,但在面对复杂或多步骤问题时存在局限。此外,RAG系统的性能高度依赖于训练数据的质量和范围。因此,企业在采用RAG技术时需综合评估需求和技术局限性,合理规划技术栈,并辅以必要的人工干预和监督机制。
165 3
|
23天前
|
存储 人工智能 运维
最新榜单 | 盘点2024年10大主流工单系统
随着互联网的发展,工单系统因其多样化功能和高效管理能力,成为企业运营的重要工具。本文介绍了10大主流工单系统,包括合力亿捷、阿里云服务中台、华为云ROMA ServiceCore等,它们各具特色,帮助企业提升服务质量和运营效率,实现数字化转型。
44 7
|
2月前
|
人工智能 自然语言处理 搜索推荐
AI技术在智能客服系统中的应用与挑战
【9月更文挑战第32天】本文将探讨AI技术在智能客服系统中的应用及其面临的挑战。我们将分析AI技术如何改变传统客服模式,提高服务质量和效率,并讨论在实际应用中可能遇到的问题和解决方案。
327 65