分布式微服务--万字详解 微服务的各种负载均衡全场景以注意点

前言:

 1. 使用方式分类总览

序号使用形式是否基于服务名调用是否需 @LoadBalanced备注
1RestTemplate + 自定义负载均衡❌ 否(手动拼接URL)❌ 否手动选择服务实例
2RestTemplate + Ribbon(非服务名)❌ 否(手动拼接URL)❌ 否使用 DiscoveryClient+Ribbon手动选节点
3RestTemplate + Spring Cloud LoadBalancer(非服务名)❌ 否(手动拼接URL)❌ 否使用 LoadBalancerClient 手动选实例
4RestTemplate + Ribbon(基于服务名)✅ 是✅ 是自动通过服务名解析
5RestTemplate + Spring Cloud LoadBalancer(基于服务名)✅ 是✅ 是推荐替代 Ribbon
6OpenFeign + Ribbon✅ 是❌ 否Spring Cloud 2020 以前使用
7OpenFeign + Spring Cloud LoadBalancer✅ 是❌ 否Spring Cloud 2020 以后默认方案

2. @LoadBalanced 的作用

  • @LoadBalanced 是加在 RestTemplate@Bean 上的注解。

  • 作用:让这个 RestTemplate 支持通过服务名调用,并自动使用 Ribbon 或 Spring Cloud LoadBalancer 做客户端负载均衡

  • 必须加 @LoadBalanced 才能支持服务名调用,比如 restTemplate.getForObject("http://producer/getMember", String.class)

  • 如果没加,RestTemplate 就是普通的,只能用完整 URL(IP+端口)调用,自己拼 URL。

3. 使用Ribbon

//1.不加也可以,是默认@Beanpublic IRule ribbonRule() {return new RandomRule(); //随机策略return new RoundRule(); // 轮询策略return new RoundRule(); // 自定义负载均衡策略}
//2. 也可以自定义负载均衡的方式
//@Component 建议采用@Bean方式注入
//原因://1. 可读性差:别人一看 @Bean 没配置,可能误以为用的默认 RoundRobinRule。//2. 项目中多个服务时可能出现冲突:比如你给多个服务配置不同的 IRule,使用 @Component 会全局生效,反而不好控制。
public class BoyatopWeightLoadBalance extends AbstractLoadBalancerRule {@Overridepublic void initWithNiwsConfig(IClientConfig iClientConfig) {}private AtomicInteger countAtomicInteger = new AtomicInteger(0);@Overridepublic Server choose(Object key) {ILoadBalancer lb = getLoadBalancer();if (lb == null) {return null;}// 获取该服务接口地址 多个//获取的同时是该服务没有下线的地址  ServerList<Server> upList = lb.getReachableServers();//目的是单纯server没有实现权重,只有选择nacos的server才可以实现权重ArrayList<NacosServer> newNacosServers = new ArrayList<>();upList.forEach((s) -> {NacosServer nacosServer = (NacosServer) s;double weight = nacosServer.getInstance().getWeight();for (int i = 0; i < weight; i++) {newNacosServers.add(nacosServer);}});return newNacosServers.get(countAtomicInteger.incrementAndGet() % newNacosServers.size());}
}

4. 使用Spring Cloud LoadBalancer

        不同于 Ribbon,Spring Cloud LoadBalancer 不支持 IRule,如需更换策略需使用 RandomLoadBalancer

  若要配置随机策略,需自定义 Spring Cloud LoadBalancer 的配置类。(下面不加也是可以的,为默认的)

@Configuration
public class ProducerLoadBalancerConfig {@Beanpublic ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,LoadBalancerClientFactory factory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
}

application.yml:

spring:cloud:loadbalancer:clients:producer:configuration: com.example.ProducerLoadBalancerConfig

1. RestTemplate + 自定义负载均衡(手动选择实例 + 手动拼接 URL)

✅ 是否基于服务名:❌ 否

✅ 是否需要 @LoadBalanced:❌ 否

✅ 特点:

  • 不依赖 Ribbon 或 LoadBalancer。

  • 手动从注册中心获取实例列表,实现负载均衡逻辑(如随机)。

✅ 示例代码:

@RestController
public class OrderController {@Autowiredprivate DiscoveryClient discoveryClient;@Autowiredprivate RestTemplate restTemplate;@GetMapping("/orderToMember")public String orderToMember() {List<ServiceInstance> instances = discoveryClient.getInstances("producer");if (instances == null || instances.isEmpty()) return "No instance";// 随机负载均衡ServiceInstance instance = instances.get(new Random().nextInt(instances.size()));String url = instance.getUri() + "/getMember";return restTemplate.getForObject(url, String.class);}@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

2. RestTemplate + Ribbon + 手动拼接 URL(非服务名调用)

✅ 是否基于服务名:❌ 否

✅ 是否需要 @LoadBalanced:❌ 否

✅ 特点:

  • 实际并未用到 Ribbon 的服务发现,仅使用 Ribbon 提供的负载策略(如 RandomRule)。

  • 使用 LoadBalancerClient.choose() 手动选择服务实例。

✅ 示例代码:

@Configuration
public class RibbonConfig {//不加也可以,是默认@Beanpublic IRule ribbonRule() {return new RandomRule(); //随机策略return new RoundRule(); // 轮询策略}@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}@RestController
public class OrderController {@Autowiredprivate LoadBalancerClient loadBalancerClient;@Autowiredprivate RestTemplate restTemplate;@GetMapping("/orderToMember")public String orderToMember() {ServiceInstance instance = loadBalancerClient.choose("producer");String url = instance.getUri() + "/getMember";return restTemplate.getForObject(url, String.class);}
}

3. RestTemplate + Spring Cloud LoadBalancer + 手动拼接 URL

✅ 是否基于服务名:❌ 否

✅ 是否需要 @LoadBalanced:❌ 否

✅ 示例代码:

@RestController
public class OrderController {@Autowiredprivate LoadBalancerClient loadBalancerClient;@Autowiredprivate RestTemplate restTemplate;@GetMapping("/orderToMember")public String orderToMember() {ServiceInstance instance = loadBalancerClient.choose("producer");String url = instance.getUri() + "/getMember";return restTemplate.getForObject(url, String.class);}@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

⚠️ 不同于 Ribbon,Spring Cloud LoadBalancer 不支持 IRule,如需更换策略需使用 RandomLoadBalancer

 若要配置随机策略,需自定义 Spring Cloud LoadBalancer 的配置类。

@Configuration
public class ProducerLoadBalancerConfig {@Beanpublic ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,LoadBalancerClientFactory factory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
}

application.yml:

spring:cloud:loadbalancer:clients:producer:configuration: com.example.ProducerLoadBalancerConfig

4. RestTemplate + Ribbon(基于服务名)

✅ 是否基于服务名:✅ 是

✅ 是否需要 @LoadBalanced:✅ 是

✅ 示例代码:

@Configuration
public class RibbonConfig {@Beanpublic IRule ribbonRule() {return new RandomRule();}@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}@RestController
public class OrderController {@Autowiredprivate RestTemplate restTemplate;@GetMapping("/orderToMember")public String orderToMember() {return restTemplate.getForObject("http://producer/getMember", String.class);}
}

5. RestTemplate + Spring Cloud LoadBalancer(基于服务名)

✅ 是否基于服务名:✅ 是

✅ 是否需要 @LoadBalanced:✅ 是

✅ 示例代码:

@Configuration
public class LoadBalancerConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}@RestController
public class OrderController {@Autowiredprivate RestTemplate restTemplate;@GetMapping("/orderToMember")public String orderToMember() {return restTemplate.getForObject("http://producer/getMember", String.class);}
}

若要配置随机策略,需自定义 Spring Cloud LoadBalancer 的配置类。

@Configuration
public class ProducerLoadBalancerConfig {@Beanpublic ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,LoadBalancerClientFactory factory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
}

application.yml:

spring:cloud:loadbalancer:clients:producer:configuration: com.example.ProducerLoadBalancerConfig

6. OpenFeign + Ribbon

✅ 是否基于服务名:✅ 是(自动)

✅ 是否需要 @LoadBalanced:❌ 否

✅ 示例代码:

@FeignClient(name = "producer")
public interface MemberFeignClient {@GetMapping("/getMember")String getMember();
}@RestController
public class OrderController {@Autowiredprivate MemberFeignClient memberFeignClient;@GetMapping("/orderToMember")public String orderToMember() {return memberFeignClient.getMember();}
}@Configuration
public class RibbonConfig {@Beanpublic IRule ribbonRule() {return new RandomRule();}
}

7. OpenFeign + Spring Cloud LoadBalancer

✅ 是否基于服务名:✅ 是(自动)

✅ 是否需要 @LoadBalanced:❌ 否

✅ 示例代码:

@FeignClient(name = "producer")
public interface MemberFeignClient {@GetMapping("/getMember")String getMember();
}@RestController
public class OrderController {@Autowiredprivate MemberFeignClient memberFeignClient;@GetMapping("/orderToMember")public String orderToMember() {return memberFeignClient.getMember();}
}// application.yml:
spring:cloud:loadbalancer:clients:producer:configuration: com.example.ProducerLoadBalancerConfig

随机策略方式同上使用 ReactorLoadBalancer


8. 总结对比表格

方式基于服务名需要 @LoadBalanced策略配置方式是否推荐
RestTemplate + 自定义负载均衡手动逻辑(如随机)✅ 灵活
RestTemplate + Ribbon(非服务名)IRule / RandomRule⚠️不常见
RestTemplate + Spring Cloud LB(非服务名)ReactorLoadBalancer⚠️一般用服务名
RestTemplate + Ribbon(服务名)IRule / RandomRule❌ 已弃用
RestTemplate + Spring Cloud LB(服务名)ReactorLoadBalancer✅ 推荐
OpenFeign + RibbonIRule / RandomRule❌ 已弃用
OpenFeign + Spring Cloud LBReactorLoadBalancer✅ 推荐

9. 举例说明:是否基于服务名的区别

        以RestTemplate + Spring Cloud LoadBalancer + 手动拼接 URL和RestTemplate + Spring Cloud LoadBalancer(基于服务名)为例

1. RestTemplate + Spring Cloud LoadBalancer + 手动拼接 URL

  • 通常写法

@Bean
public RestTemplate restTemplate() {return new RestTemplate();  // 普通RestTemplate,没有@LoadBalanced
}@Autowired
private LoadBalancerClient loadBalancerClient;public void call() {ServiceInstance instance = loadBalancerClient.choose("service-name");String url = instance.getUri() + "/api";restTemplate.getForObject(url, String.class);
}
  • 特点

    • RestTemplate 是普通实例,不支持基于服务名自动负载均衡。

    • 你手动通过 LoadBalancerClient 获取具体服务实例,再拼完整 URL。

    • 负载均衡由 LoadBalancerClient 实现,调用时需要自己拼接 URL。


2. RestTemplate + Spring Cloud LoadBalancer(基于服务名)

  • 通常写法

@Bean
@LoadBalanced
public RestTemplate restTemplate() {return new RestTemplate();  // 带@LoadBalanced支持服务名调用
}public void call() {restTemplate.getForObject("http://service-name/api", String.class);
}
  • 特点

    • RestTemplate 通过 @LoadBalanced 注解支持服务名解析和负载均衡。

    • 你直接调用服务名 URL,不用关心具体实例。

    • 负载均衡和服务实例选择完全交给 Spring Cloud LoadBalancer 内部管理。


3. 核心区别总结

特性手动拼 URL(无 @LoadBalanced)基于服务名调用(带 @LoadBalanced)
RestTemplate 是否带 @LoadBalanced
负载均衡策略执行点LoadBalancerClient 手动调用实例选取RestTemplate 内部自动调用负载均衡
请求时是否需手动拼接 URL是,需要拼接具体实例的 URI否,直接写服务名 URL
代码简洁性代码相对复杂,需要手动管理实例和 URL代码简洁,专注业务调用
适用场景需要自定义实例选择或做扩展时使用绝大多数场景推荐使用

4. 结论

是否加了 @LoadBalanced 是两种方式最主要的区别,但真正关键是:

  • @LoadBalancedRestTemplate 支持直接用服务名调用,负载均衡自动执行;

  • 不带 @LoadBalanced 时需要自己用 LoadBalancerClient 选实例,拼 URL 手动调用。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Netty的Http解码器源码分析

一、HTTP协议简介HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一种基于 请求-响应模型 的无状态应用层协议&#xff0c;广泛用于客户端&#xff08;如浏览器&#xff09;和服务器之间的数据通信。其主要特点包括&#xff1a;基于 TCP…

磁盘io查看命令iostat与网络连接查看命令netstat

1. iostat的使用场景首先iostat命令隶属于sysstat软件包。iostat专门用来查看主机上每个磁盘设备的io情况&#xff0c;包括像每秒的读写数据情况&#xff0c;磁盘平均io时间&#xff0c;设备io繁忙情况等等。1.1 iostat的普通输出解释首先是主机的架构&#xff0c;主机名&#…

Linux ps -ef 命令解析

ps 是 Linux 系统中用于查看进程状态的标准命令&#xff0c;-ef 是其参数组合&#xff0c;用于输出系统范围内所有进程的完整信息。以下是对该参数的详细解析&#xff1a; 1. 核心参数含义-e表示显示所有进程&#xff08;包括系统进程和用户进程&#xff09;&#xff0c;相当于…

2025年湖北中级注册安全工程师报考那些事

2025年湖北中级注册安全工程师报考那些事各位从事建筑安全的人员看过来&#xff0c;注册安全工程师是你们行业认可度较为高的证书。关于报考无论是安全相关专业跟不相关的专业都是可以报考的。只是年份要求不同。 本科&#xff1a;相关专业3年&#xff0c;不相关专业4年。 专科…

容器与虚拟机的本质差异:从资源隔离到网络存储机制

目录 专栏介绍 作者与平台 您将学到什么&#xff1f; 学习特色 容器与虚拟机的本质差异&#xff1a;从资源隔离到网络存储机制 一、容器与虚拟机的本质区别 1.1 资源抽象层次差异 1.2 资源消耗与性能对比 1.3 隔离性深度差异 二、容器网络基础架构 2.1 Docker网络模型…

FPGA实现SRIO高速接口与DSP交互,FPGA+DSP异构方案,提供3套工程源码和技术支持

目录1、前言&#xff1a;SRIO在FPGADSP架构中的作用工程概述免责声明2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的FPGADSP异构方案我这里已有的 GT 高速接口解决方案3、工程详细设计方案工程设计原理框图FPGA端工程源码FPGA端SRIO从…

网络安全第15集

前言&#xff1a; 挖不到一点&#xff0c;又来学习了 内容&#xff1a; 1、根据端口扫描可以得到相关的信息 端口扫描&#xff0c;根据扫描的端口&#xff0c; 可以得到目标服务器开启的应用服务器&#xff0c;的具体相关信息&#xff0c;数据库的相关信息 web服务器&…

【Linux】重生之从零开始学习运维之Mysql事务

事务开启事务begin;提交事务commit;select * from stu;事务回滚begin; select * from stu; update stu set age100 where id10; select * from stu; rollback;事务保存点rollback to p2; rollback to p1;因回到p1&#xff0c;无后面记录&#xff0c;所以无法回到p2、p3保存点。…

深入理解Java Map的entrySet()方法

文章目录深入理解Java Map的entrySet()方法一、entrySet()方法概述二、为什么需要entrySet()三、entrySet()的核心特性四、Map.Entry接口详解五、entrySet()的典型使用场景1. 遍历Map2. 批量修改值3. 过滤Map4. 并行处理六、性能考虑七、Java 8的增强八、注意事项九、总结深入理…

webpack 原理及使用

【点赞收藏加关注,前端技术不迷路~】 一、webpack基础 1.核心概念 1)entry:定义入口,webpack构建的第一步 module.exports ={entry:./src/xxx.js } 2)output:出口(输出) 3)loader:模块加载器,用户将模块的原内容按照需求加载成新内容 比如文本加载器raw-loade…

5.1 动⼿实现⼀个 LLaMA2 ⼤模型

Meta&#xff08;原Facebook&#xff09;于2023年2月发布第一款基于Transformer结构的大型语言模型LLaMA&#xff0c;并于同年7月发布同系列模型LLaMA2。5.1.1 定义超参数自定义一个ModelConfig类&#xff0c;来存储和记录超参数&#xff0c;这里继承了PretrainedConfig类&…

【Python】自动化GIT提交

在日常开发中&#xff0c;我们经常需要频繁地向 Git 仓库提交代码。虽然 git add、git commit、git push 这几个命令并不复杂&#xff0c;但重复操作容易出错&#xff0c;也浪费时间。本文将介绍如何使用 Python 脚本自动化完成 Git 提交流程&#xff0c;让开发更高效&#xff…