什么是负载均衡
负载均衡(load balancing)是一种电子计算机技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。 使用带有负载均衡的多个服务器组件,取代单一的组件,可以通过冗余提高可靠性。负载均衡服务通常是由专用软件和硬件来完成。主要作用是将大量作业合理地分摊到多个操作单元上进行执行,用于解决互联网架构中的高并发和高可用的问题。
简单来说,就是将所有请求先集中在一起,然后再根据特定的算法将这些请求分配出去,使各个服务器的效率都能最大化。
常见的负载均衡算法有:
- 随机法(Random)
- 加权随机法(Weight Random)
- 轮询法(Round Robin)
- 加权轮询法(Weight Round Robin)
- 平滑加权轮询法(Smooth Weight Round Robin)
- 地址哈希法(Hash)
- 最小连接数法(Least Connections)
Ribbon 简介
Ribbon 是一个由 Netflix 创建并开源(目前已闭源)的客户端负载均衡器。
使用 Ribbon
导入 Ribbon
由于 Nacos 注册与发现中心已默认集成了 Ribbon,因此我们不必再手动导入。

Ribbon 负载均衡策略
各负载均衡策略的关系继承图如下:

主要提供了如下几种负载均衡策略
名称 |
策略解释 |
RoundRobinRule |
轮询策略 |
WeightedResponseTimeRule |
服务实例的平均响应时间越短则权重越大,那么服务实例被选中执行的概率也就越大 |
RandomRule |
随机策略 |
RetryRule |
在轮询的基础上进行重试(超过重试时间服务实例仍无效则进行轮询) |
NacosRule |
根据Nacos设置的权重进行挑选 |
ClientConfigEnabledRoundRobinRule |
和RoundRobinRule一致,轮询策略 |
BestAvailableRule |
过滤掉失效的服务实例然后找出并发请求最小的服务实例进行使用 |
AvailabilityFilteringRule |
先过滤掉故障实例然后选择并发较小的服务实例 |
ZoneAvoidanceRule |
默认负载均衡策略。根据判断server所在区域的性能和server的可用性来过滤服务实例。过滤成功后,使用轮询策略从过滤结果中选择服务实例 |
使用 Ribbon 默认负载均衡策略
只需要在 RestTemplate Bean类上添加一个 @LoadBalanced 注解即可使用 Ribbon 的默认负载均衡策略。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.pushihao.orderRibbon.config;
import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate;
@Configuration public class RestConfig {
@LoadBalanced @Bean public RestTemplate restTemplate(RestTemplateBuilder builder) { return builder.build(); } }
|
修改 Ribbon 负载均衡策略
- 通过配置类进行修改
注意:配置类不能放在 @SpringBootApplication 注解的 @ComponentScan 能扫描到的地方
RibbonRandomRuleConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.pushihao.ribbon;
import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class RibbonRandomRuleConfig {
@Bean public IRule iRule() { return new RandomRule(); } }
|
RestConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.pushihao.orderRibbon.config;
import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; import com.pushihao.ribbon.RibbonRandomRuleConfig;
@Configuration @RibbonClients(value = { @RibbonClient(name = "stock-service", configuration = RibbonRandomRuleConfig.class) }) public class RestConfig {
@LoadBalanced @Bean public RestTemplate restTemplate(RestTemplateBuilder builder) { return builder.build(); } }
|
- 通过配置文件进行修改
application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13
| server: port: 9002 spring: cloud: nacos: server-addr: 127.0.0.1:8848 application: name: order-service
stock-service: ribbon: NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
|
自定义负载均衡策略
通过实现 IRule 接口或继承 AbstractLoadBalancerRule 抽象类可以自定义负载均衡策略,主要的逻辑代码在 choose 方法中。
比如我要自己实现一个随机策略的负载均衡器
CustomRuleConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.pushihao.ribbon;
import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.Server;
import java.util.List; import java.util.concurrent.ThreadLocalRandom;
public class CustomRuleConfig extends AbstractLoadBalancerRule { @Override public Server choose(Object key) { ILoadBalancer loadBalancer = this.getLoadBalancer(); List<Server> reachableServers = loadBalancer.getReachableServers();
int randomNum = ThreadLocalRandom.current().nextInt(reachableServers.size());
Server server = reachableServers.get(randomNum); if (server.isAlive()) { return server; } else { return null; } }
@Override public void initWithNiwsConfig(IClientConfig iClientConfig) { } }
|
然后通过配置类或配置文件修改使用自己的负载均衡策略,例如
application.yml
1 2 3
| stock-service: ribbon: NFLoadBalancerRuleClassName: com.pushihao.ribbon.CustomRuleConfig
|
配置 Ribbon 负载均衡预加载
Ribbon 的负载均衡器默认是懒加载,也就是当第一次访问时才会加载,那么就会导致第一次访问时间较长甚至出现网络连接超时的情况。我们可以通过开启预加载(启动服务时就加载)来解决这个问题。
application.yml
1 2 3 4 5 6
| ribbon: eager-load: enabled: true clients: stock-service1,stock-service2
|