文章目录
- 负载均衡
- Ribbon简介
- Ribbon的使用(jdk1.8的环境下是可以的)
- [LoadBalancer 负载均衡器](#LoadBalancer 负载均衡器)
- 实现负载均衡
- 自定义负载均衡的算法(LoadBalancer)
- Feign简介
- Feigen的使用
负载均衡
峰值调用,通过网速汇总,调整网络的速率吞吐,其中LVS是典型的应用

Ribbon简介
SpringCloud Ribbon 是基于NetFlix Ribbon实现的一套客户端负载均衡的工具;
Ribbon将负载均衡的位置放在了消费方,和Eureka挂钩,找到合适的节点进行使用;
经调查发现,SpringCloud使用的2024.0.0,对应SpringBoot3.4.5,官方已经完全移除了Ribbon,现在转用loadbalancer,
Ribbon的使用(jdk1.8的环境下是可以的)
三件套:
- 导入依赖启动器
- 编写配置文件
- 启动配置
- 编写配置类(视情况而定)
- 导入依赖:Ribbon、Eureka-Client
xml
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 编写配置文件
- 启动配置
- 测试
LoadBalancer 负载均衡器
Ribbon和LoadBalancer相差不大,大多数内容一致;
LoadBalancer翻译过来的意思是 负载均衡器
正常使用
- 导入依赖
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>4.2.0</version>
</dependency>
- 编写配置文件,localhost换成域名
yaml
server:
port: 8080
eureka:
client:
register-with-eureka: false # 是否注册自己,消费者不需要向注册中心注册自己
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka
- 配置类 ,使用注解
@LoadBalanced
java
@Configuration
public class ConfigBean { // 相当于 application.xml
@Bean
@LoadBalanced // 开启负载均衡功能
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
- 启动配置,检查问题,理论上是正常启用
扩展学习
- 更改服务消费方的访问地址,在最开始是使用RestTemplate的时候使用的
http://localhost:8001/,现在改成服务消费者的名字,之后再在Controller中将对应的url改成服务名http://SPRINGCLOUD-PROVIDER-DEPT;

- 再次开启所有的服务,查看三个集群是否都可以访问 服务供应者;

- 可以之后,访问消费者,使用消费者的Request请求路径访问,测试成功。

实现负载均衡
创建三个服务提供者,使用一样的数据库,数据库Database不一样;
每个服务(8001/8002/8003)都关联多个注册中心(7001/7002/7003);
这样子就会使LoadBalance 进行负载均衡,默认使用轮询调用的方式;
场景:
| serve | port | database | Eureka注册中心 |
|---|---|---|---|
| 8001 | 8001 | DB01 | 7001/7002/7003 |
| 8002 | 8002 | DB02 | 7001/7002/7003 |
| 8003 | 8003 | DB03 | 7001/7002/7003 |
这样子在注册中心调用分配的时候会调用8001,之后再调8002,8003;消费者方发出请求后也会从7001/7002/7003中选择一个合适的节点,进行调用;
默认理解的是:
服务消费者 >> 随机的Eureka注册中心 >> 随机的server服务器 >> 返回调用内容数据;
特别的占内存,测试时启动的微服务 使用 3~5个就可以了
自定义负载均衡的算法(LoadBalancer)
详细流程
- 确保依赖已完全导入
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
- 实现自定义负载均衡器
ReactorServiceInstanceLoadBalancer
java
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.*;
import org.springframework.cloud.loadbalancer.core.*;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Random;
public class CustomRandomLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private final String serviceId;
private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
public CustomRandomLoadBalancer(
ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
String serviceId) {
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
this.serviceId = serviceId;
}
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get(request).next()
.map(serviceInstances -> processInstanceResponse(serviceInstances));
}
private Response<ServiceInstance> processInstanceResponse(List<ServiceInstance> instances) {
if (instances.isEmpty()) {
return new EmptyResponse();
}
// 自定义逻辑:随机选择
int index = new Random().nextInt(instances.size());
ServiceInstance instance = instances.get(index);
System.out.println("【CustomRandomLoadBalancer】选择了实例: " + instance.getHost() + ":" + instance.getPort());
return new DefaultResponse(instance);
}
}
- 注册 Spring Bean(按服务名绑定)
java
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@LoadBalancerClient(
value = "springcloud-provider-dept", // ← 指定服务名
configuration = CustomLoadBalancerConfig.class
)
public class LoadBalancerConfiguration {
// 可留空
}
class CustomLoadBalancerConfig {
@Bean
ReactorServiceInstanceLoadBalancer customLoadBalancer(
Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String serviceId = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new CustomRandomLoadBalancer(
loadBalancerClientFactory.getLazyProvider(serviceId, ServiceInstanceListSupplier.class),
serviceId
);
}
}
这样只有调用 springcloud-provider-dept 时才使用随机算法,其他服务仍用默认轮询算法。
- 使用
@LoadBalanced调用
java
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
// 调用
restTemplate.getForObject("http://springcloud-provider-dept/dept/list", String.class);
Ribbon的方式(Spring新版不支持)
java
// Ribbon 方式(已过时)
public class CustomRandomRule extends AbstractLoadBalancerRule {
@Override
public Server choose(Object key) {
ILoadBalancer lb = getLoadBalancer();
List<Server> servers = lb.getAllServers();
// 随机选择...
return servers.get(new Random().nextInt(servers.size()));
}
}
// 配置类
@RibbonClient(name = "springcloud-provider-dept", configuration = RibbonConfig.class)
public class ConsumerApp { }
class RibbonConfig {
@Bean
public IRule ribbonRule() {
return new CustomRandomRule();
}
}
不要混合使用 Ribbon 和 LoadBalancer
Feign简介
在 Spring Cloud 2024.0.0(基于 Spring Boot 3.4.5) 的现代微服务架构中,Feign 依然是实现 声明式 HTTP 客户端 的核心组件,但其底层已从 Ribbon 切换为 Spring Cloud LoadBalancer,并全面适配 Jakarta EE(jakarta.* 包)。
Feign能做些什么
Feign的目的是在编写Java Http客户端更加容易;
Feign是声明式的web Service客户端,再次简化了微服务之间的调用,类似于Controller调用Service,SpringCloud会同时集成Eureka和LoadBalance,再使用Feign作为负载均衡的HTTP的客户端;只需要创建一个接口,就可以添加注解;
面向接口编程是很多开发时候的规范,调用微服务访问有两种方法:
- 微服务名字(Ribbon/LoadBalance)
- 接口和注解(Feign)
Feign的特点
- 声明式 REST 客户端:用接口 + 注解代替手动写 RestTemplate 或 WebClient
- 自动集成负载均衡:通过 @LoadBalanced 机制,结合服务注册中心(如 Eureka/Nacos)实现服务调用。
- 底层依赖:Spring Cloud OpenFeign(基于 Netflix Feign 封装,但已移除 Ribbon)。
Feigen的使用
前提准备
- 新建一个service在api中

- 新建一个Feign的服务,copy 80消费端的内容
- 删除原来Ribbon/LoadBalance的内容
- 在springcloud-api的com.cloud.springcloud.service创建一个service作为远程调用的service
java
package com.cloud.springcloud.service;
import com.cloud.springcloud.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
/**
*
* 公用接口 Service
* FeignClient: 服务调用方
* name: 服务提供者的服务名
*/
@Service
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {
@RequestMapping("/dept/get/{id}")
public Dept get(@PathVariable("id") Long id);
@RequestMapping("/dept/list")
public List<Dept> list();
@RequestMapping("/dept/add")
public boolean add(Dept dept);
@RequestMapping("/dept/delete/{id}")
public boolean delete(@PathVariable("id") Long id);
@RequestMapping("/dept/update")
public boolean update(Dept dept);
}
- 在该service中调用到Mapping是服务提供者那边的,需要再加一个注解
@Feign,在这个地方的value是在Eureka中设置的服务名
使用流程
组件导入流程:
- 导入依赖
- 编写配置文件
- 启动配置类
- 编写配置类
导入依赖
- Feign的依赖
- Eureka的依赖
- LoadBalancer的依赖(Feign中包含这个,可以不导)
xml
<!-- OpenFeign 核心依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 服务注册发现(以 Eureka 为例) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- LoadBalancer(Feign 默认依赖,但显式声明更安全) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
编写逻辑代码,使用注入的方式将Service导入进去
代码如下,注意要给api路径下的DeptClientService加入Component(@Service注解),确保能被扫描到
java
@RestController
public class DeptConsumerController {
// idea 不建议使用Autowired
// @Autowired
private final DeptClientService deptClientService;
public DeptConsumerController(DeptClientService deptClientService) {
this.deptClientService = deptClientService;
}
// 消费者的请求地址
@RequestMapping("/consumer/dept/findAll")
public List<Dept> findAll(){
return deptClientService.list();
}
@RequestMapping("/consumer/dept/add")
public Object addDept(Dept dept) {
return deptClientService.add(dept);
}
@RequestMapping("/consumer/dept/get/{id}")
public Object findById(@PathVariable("id") Long id) {
return deptClientService.get(id);
}
@RequestMapping("/consumer/dept/update")
public Object updateDept(Dept dept) {
return deptClientService.update(dept);
}
@RequestMapping("/consumer/dept/delete/{id}")
public Object deleteDept(@PathVariable("id") Long id) {
return deptClientService.delete(id);
}
}
编写配置文件
沿用的配置都是之前Eureka所配置完的,不需要改动,注意不要和Ribbon、LoadBalance的内容冲突
PS:Feign就是再对于LoadBalance的再次封装,Feign的底层依旧是沿用的Ribbon/LoadBalance的处理逻辑,使用java思想对其进行了封装。
启动配置,进行测试
- 在SpringBoot服务消费者 的启动类上启用
EnableFeignClients
java
@SpringBootApplication
@EnableFeignClients(basePackages = {"com.cloud.springcloud.service"})
public class SpringCloudDeptConsumerFeign_80 {
public static void main(String[] args) {
SpringApplication.run(SpringCloudDeptConsumerFeign_80.class, args);
}
}
- 服务注册启动成功,Eureka页面正常显示,调用内容正常显示;
- 服务提供者启动正常,直接调用提供者Service的DB查询正常;
- 服务消费者(Feign组件)启动正常,调用URL显示内容查询正常;
