SpringCloud(三)LoadBalancer负载均衡

news2024/10/5 14:38:12

一、负载均衡

实际上,在添加@LoadBalanced注解之后,会启用拦截器对我们发起的服务调用请求进行拦截(注意这里是针对我们发起的请求进行拦截),叫做LoadBalancerInterceptor,它实现ClientHttpRequestInterceptor接口:

@FunctionalInterface
public interface ClientHttpRequestInterceptor {
    ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException;
}

主要是对intercept方法的实现:

public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
    URI originalUri = request.getURI();
    String serviceName = originalUri.getHost();
    Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
    return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}

 

 

服务端会在发起请求时执行这些拦截器。

那么这个拦截器做了什么事情呢,首先我们要明确,我们给过来的请求地址,并不是一个有效的主机名称,而是服务名称,那么怎么才能得到真正需要访问的主机名称呢,肯定是得找Eureka获取的。

我们来看看loadBalancer.execute()做了什么,它的具体实现为BlockingLoadBalancerClient:

//从上面给进来了服务的名称和具体的请求实体
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
    String hint = this.getHint(serviceId);
    LoadBalancerRequestAdapter<T, DefaultRequestContext> lbRequest = new LoadBalancerRequestAdapter(request, new DefaultRequestContext(request, hint));
    Set<LoadBalancerLifecycle> supportedLifecycleProcessors = this.getSupportedLifecycleProcessors(serviceId);
    supportedLifecycleProcessors.forEach((lifecycle) -> {
        lifecycle.onStart(lbRequest);
    });
  	//可以看到在这里会调用choose方法自动获取对应的服务实例信息
    ServiceInstance serviceInstance = this.choose(serviceId, lbRequest);
    if (serviceInstance == null) {
        supportedLifecycleProcessors.forEach((lifecycle) -> {
            lifecycle.onComplete(new CompletionContext(Status.DISCARD, lbRequest, new EmptyResponse()));
        });
      	//没有发现任何此服务的实例就抛异常(之前的测试中可能已经遇到了)
        throw new IllegalStateException("No instances available for " + serviceId);
    } else {
      	//成功获取到对应服务的实例,这时就可以发起HTTP请求获取信息了
        return this.execute(serviceId, serviceInstance, lbRequest);
    }
}

所以,实际上在进行负载均衡的时候,会向Eureka发起请求,选择一个可用的对应服务,然后会返回此服务的主机地址等信息:

二、自定义负载均衡

LoadBalancer默认提供了两种负载均衡策略:

RandomLoadBalancer - 随机分配策略
(默认) RoundRobinLoadBalancer - 轮询分配策略
现在我们希望修改默认的负载均衡策略,可以进行指定,比如我们现在希望用户服务采用随机分配策略,我们需要先创建随机分配策略的配置类(不用加@Configuration):
 

package com.example.config;


import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

public class LoadBalancerConfig {
    //将官方提供的 RandomLoadBalancer 注册为Bean
    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory){
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

接着我们需要为对应的服务指定负载均衡策略,直接使用注解即可:

@Configuration
@LoadBalancerClient(value = "userservice",      //指定为 userservice 服务,只要是调用此服务都会使用我们指定的策略
        configuration = LoadBalancerConfig.class)   //指定我们刚刚定义好的配置类
public class BeanConfiguration {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

三、OpenFeign实现负载均衡

官方文档:https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/

Feign和RestTemplate一样,也是HTTP客户端请求工具,但是它的使用方式更加便捷。首先是依赖:

borrow-service(pom.xml)

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

接着在启动类添加@EnableFeignClients注解:

@SpringBootApplication
@EnableFeignClients
public class BorrowApplication {
    public static void main(String[] args) {
        SpringApplication.run(BorrowApplication.class, args);
    }
}

现在我们需要调用其他微服务提供的接口,我们直接创建一个对应服务的接口类即可:

@FeignClient("userservice")   //声明为userservice服务的HTTP请求客户端
public interface UserClient {
}

接着我们直接创建所需类型的方法,比如我们之前的:

RestTemplate template = new RestTemplate();
User user = template.getForObject("http://userservice/user/"+uid, User.class);

现在可以直接写成这样:

UserClient

package com.example.service.client;

import com.example.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

//声明为userservice服务的HTTP请求客户端
@FeignClient("userservice")
public interface UserClient {

    //路径保证和其他微服务提供的一致即可
    @RequestMapping("/user/getUserById/{uid}")
    User getUserById(@PathVariable("uid") Integer uid);
}

BookClient

package com.example.service.client;

import com.example.entity.Book;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("bookservice")
public interface BookClient {

    @GetMapping("/book/getBookById/{bid}")
    Book getBookById(@PathVariable("bid") Integer bid);
}

接着我们直接注入使用(有Mybatis那味了):

BorrowServiceImpl


@Service
public class BorrowServiceImpl implements BorrowService {

    @Resource
    private BorrowMapper borrowMapper;

    @Resource
    private UserClient userClient;

    @Resource
    private BookClient bookClient;

    @Override
    public UserBorrowDto getUserBorrowDtoByUid(Integer uid) {
        List<Borrow> borrow = borrowMapper.getBorrowByUid(uid);
        //这里通过调用getForObject来请求其他服务,并将结果自动进行封装
        //获取User信息
        User user = userClient.getUserById(uid);
        //获取每一本书的详情信息
        List<Book> bookList = borrow
                .stream()
                .map(b ->bookClient.getBookById(b.getBid()))
                .collect(Collectors.toList());
        return new UserBorrowDto(user,bookList);
    }
}

访问,可以看到结果依然是正确的:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/768398.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JAVA的swing技术到底实用不实用?

文章目录 先说结论JAVA的知识范围那为什么还要学&#xff1f; 总结 先说结论 不实用 1 尚硅谷Java入门视频教程&#xff0c;宋红康java基础视频 必须要排在第一位。1600万的播放量呀。 717集 我的天啦&#xff01; 目录&#xff1a; Java视频及配套资料下载指南 尚硅谷Java基…

有效的括号(C)

bool isValid(char* s) {ST st;StackInit(&st);while (*s) //遍历 -- 与\0终止{//是左括号 压栈if (*s ( || *s [ *s {){StackPush(&st, *s);s;}else{//应对样例&#xff1a; ’]if (StackEmpty(&st)){StackDestroy(&st);return false;}//不是左括号 应该就…

【Flink】详解Flink任务提交流程

启动一个任务 通常我们会使用 bin/flink run -t yarn-per-job -c com.xxx.xxx.WordCount/WordCount.jar 方式启动任务&#xff1b;我们看一下 flink文件中到底做了什么&#xff0c;以下是其部分源码 # Convert relative path to absolute path bindirname "$target"…

快速搭建机器学习demo: gradio教程

1. Intro gradio是一个能够快速建立机器学习demo web应用的工具&#xff0c;仅需简单的几行代码就能构建机器学习模型的可视化交互demo&#xff0c;并分享给你的朋友使用。 与gradio相同功能的竞品有Streamlit&#xff0c;相比Gradio&#xff0c;Streamlit相对复杂&#xff0…

热门二叉树面试题

606. 根据二叉树创建字符串 - 力扣&#xff08;LeetCode&#xff09; 给你二叉树的根节点 root &#xff0c;请你采用前序遍历的方式&#xff0c;将二叉树转化为一个由括号和整数组成的字符串&#xff0c;返回构造出的字符串。 空节点使用一对空括号对 "()" 表示&a…

Baichuan-13B:130亿参数的开源语言模型,引领中文和英文benchmark

Baichuan-13B: 一个强大的开源大规模语言模型 标题&#xff1a;Baichuan-13B&#xff1a;130亿参数的开源语言模型&#xff0c;引领中文和英文benchmark Baichuan-13B是由百川智能开发的一个开源大规模语言模型项目&#xff0c;包含了130亿参数。该模型在中文和英文的权威ben…

基于Nginx深入浅出亿级流量架构设计(更新至2023.7.18)

基于Nginx深入浅出亿级流量架构设计 环境准备/安装部署Nginx四个发行版本简单介绍Nginx的安装 Nginx的目录结构与基本运行原理及其最小配置解析Nginx虚拟主机与域名配置ServerName匹配规则反向代理在系统结构中的应用场景Nginx的反向代理配置基于反向代理的负载均衡器 环境准备…

自洽性改善语言模型中的思维链推理

自洽性改善语言模型中的思维链推理 摘要介绍对多样化路径的自洽实验实验设置主要结果当CoT影响效率时候&#xff0c;SC会有所帮助与现有方法进行比较附加研究 相关工作总结 原文&#xff1a; 摘要 本篇论文提出了一种新的编码策略——自洽性&#xff0c;来替换思维链中使用的…

【STM32】SPI屏幕刷图总结:GPIO模拟,硬件SPI,DMA+硬件SPI

文章目录 GPIO模拟SPI硬件SPI外设DMA硬件SPI外设总结 代码工程&#xff1a;https://github.com/liefyuan/stm32-spi-st7789-tft.git 前言 我的屏幕的分辨率是&#xff1a;240*320 驱动是&#xff1a;ST7789V 线驱动方式&#xff1a;四线SPI&#xff08;CS&#xff0c;DC&#…

206. 反转链表

给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例 3&#xff1a; 输入&am…

PageObject+Python+Appium

目录 前言&#xff1a; 简介 功能 常用目录 配置 实例 - 第一次启动 app 实例 - 登录 代码入口实例 结果展示 前言&#xff1a; Page Object模式是一种常用的设计模式&#xff0c;用于组织和管理自动化测试脚本中的页面对象。它将页面的元素和操作封装在一个独立的类…

数据质量相关问题系列

数据质量问题是什么&#xff1f; 数据质量&#xff0c;是指在业务环境下&#xff0c;数据符合数据消费者的使用目的&#xff0c;能满足业务场景具体需求的程度。而数据质量问题是指数据集中存在无法容忍的缺陷&#xff0c;从而降低该数据的可靠性和可信度。简单理解就是数据很脏…

【JAVA】云HIS系统功能菜单知识(一)

一、云HIS特色 云HIS滚动消息栏&#xff1a;质控消息、住院时长、药库结转、患者入院、医嘱停止、新开医嘱、门诊用药不良、出院审核、药品调拨、排班提醒、药品库存、药品过期、药品临期等帮助医生、护士和相关管理人员实时接收院内消息并作出处理。 二、云HIS功能菜单 【预约…

【MySQL】MySQL事务保姆级教程(适合MySQL初学者学习)

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;啥技术都喜欢捣鼓捣鼓&#xff0c;喜欢分享技术、经验、生活。 &#x1f60e;人生感悟&#xff1a;尝尽人生百味&#xff0c;方知世间冷暖。 &#x1f4d6;所属专栏&#xff1a;重…

桥接模式——连接抽象维度和实现维度

桥接模式 bridge pattern 一 定义 桥接模式&#xff0c;是将抽象部分与它的具体实现部分分离&#xff0c;使它们都可以独立地变化。它是将两个不同的维度建立联系。这两个维度通常是指&#xff1a;抽象维度和实现维度。 使用场景 在抽象和具体实现之间需要增加更多的灵活性…

找不到dll的问题解决,loadlibrary 126错误

症状&#xff1a;loadlibrary时&#xff0c;getlasterror返回126&#xff0c;表示是找不到模块错误。来到目录下看到依赖所需的dll均存在 解决办法&#xff1a; 1.下载ProcmonProcmom-监视进程所有的动作资源-CSDN文库https://download.csdn.net/download/gergul/880597622.运…

RocketMQ第四节(部署模式、监控面板等)

1&#xff1a;mq的部署模式 部署方式 | RocketMQ 参考官网。 单机模式&#xff1a;抗风险能力差&#xff0c;单机挂机没服务&#xff0c;单机硬盘损坏&#xff0c;丢失数据 多机&#xff08;多master没有Slave副本&#xff09;: 多个master采用RAID10磁盘&#xff0c;不会丢…

[java安全]类加载器CommonsCollections3

文章目录 【java安全】类加载器&CommonsCollections3前言java类加载器URLClassLoader利用ClassLoader#defineClass()直接加载字节码 使用TemplatesImpl加载字节码TemplatesImpl中字节码实现AbstractTranslet类 构造未完成POCTrAXFilter类调用newTransformer()InstantiateTr…

【AI绘画Stable Diffusion】高清图像放大+面部修复+一键抠图,谈谈你可能不知道的优化技巧!

一提起后期处理&#xff0c;我猜你可能立马想到的就是图像放大。 今天&#xff0c;我要向你展示的后期处理手法&#xff0c;以及优化技巧。 图片放大算法 如果你常用的是秋叶大佬的整合包&#xff0c;那么你对"R-ESRGAN 4x"和"R-ESRGAN 4x Anime6B"应该…

FPGA单端口RAM——IP核

文章目录 前言一、RAM简介1、随机存储器IP核分类1、RAM IP核2、ROM IP核 2、RAM IP核 二、IP核配置步骤三、源码1、ram_rw驱动文件2、ip_1port_ram顶层文件3、仿真文件4、仿真波形 四、SignalTap II在线调试五、总结六、参考资料 前言 环境&#xff1a; 1、Quartus18.1 2、vsco…