1、什么是Ribbon
目前主流的负载均衡大致有以下两种
- 服务端的负载均衡,比如
nginx
- 客户端的负载均衡,
Ribbon
就属于客户端自己做负载均衡
Spring Cloud Ribbon是基于Netflix实现的一套客户端的负载均衡工具
,Ribbon客户端组件提供一系列的完善的配置,如超时、重试等,通过Load Balancer
获取到服务提供的所有机器实例,Ribbon会自动基于某种规则(轮询、随机)去调用这些服务。Ribbon也可以实现我们自己的负载均衡算法。
1.1、客户端的负载均衡
例如spring cloud中的ribbon,客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法选择一个服务器,然后进行访问,这是客户端负载均衡,即在客户端就进行负载均衡算法分配
1.2、服务端的负载均衡
例如Nginx,通过nginx进行负载均衡,先发送请求,然后通过负载均衡算法,在多个服务器之间选择一个进行访问,即在服务器端进行负载均衡算法分配
1.3、常见的负载均衡算法
- 随机,通过随机选择服务进行执行,一般这种方式使用较少
- 轮询,负载均衡默认实现方式,请求来之后排队处理
- 加权轮训,通过对服务器性能的分析,给高配置,低负载的服务器分配更高的权重,均衡各个服务器的压力
- 地址Hash,通过客户端请求的地址的hash值取模进行服务器调度,ip hash
- 最小连接数,即使请求均衡了,压力不一定均衡,最小连接数法就是根据服务器的情况,比如请求积压等参数,将请求分配到当前压力最小的服务器上,最小活跃数
2、Nocos中使用Ribbon
1、依赖
nacos-discovery依赖了ribbon,可以不用再引入ribbon依赖
2、添加@LoadBanlanced
注解
@Configuration public class RestConfig{ @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } }
3、编写controller层即可调用
@RestController @RequestMapping("/order") public class OrderController { @Autowired RestTemplate restTemplate; @GetMapping("/orderList") public String getOrder() { String message = restTemplate.getForObject("http://stock-server/stock/stockList", String.class); return "order" + message; } }
4、Ribbon的负载均衡策略
RandomRule
:随机选择一个服务实例
RoundRobinRule
:轮询复杂均衡策略
RetryRule
:在轮询的基础上进行重试(没有超时的情况下)
WeightedResponseTimeRule
:自动计算权重(如果一个服务的平均响应时间越短权重越大,被选中执行任务的概率就越大)
BestAvailableRule
:过滤掉失效的服务实例的功能,然后顺便找出并发请求最小的服务器实例来使用
ZoneAvoidanceRule
:默认规则,根据服务所在区域的性能和服务的可用性选择服务器
5、修改默认负载均衡策略
- 方式一
配置类的方式:
@Configuration public class RibbonConfig { /** * 指定负载均衡策略 */ @Bean public IRule iRule(){ // Nacos提供的负载均衡策略(优先调用同一集群下的实例,基于随机权重) return new NacosRule(); } }
注意:配置类不能写在@SpringbootApplication注解的@CompentScan扫描的到的地方,否则自定义的配置类就会被所有的RibbonClients共享,所以可放在其他目录下
策略配置好了,最后利用@RibbonClient
指定微服务及其负载均衡策略
测试效果:(l两个提供者(9002,9003),一个消费者9001)
nacos注册中心可以看到,我们的实例都成功注册了进来
浏览器进行访问:
随着不断刷新,根据随机权重选择不同的服务。
- 方式二:(配置文件的方式)
修改application.yml
启动即可。
6、自定义负载均衡
继承AbstractLoadBalancerRule
即可,比如挨个每个访问5次
public class MyRibbonConfig extends AbstractLoadBalancerRule { /** * 默认等于0,如果等于5,指向下一个服务 */ private int total = 0; /** * 默认=0,如果total=5,currentIndex++ */ private int currentIndex = 0; public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } else { Server server = null; while (server == null) { if (Thread.interrupted()) { return null; } //获得所有的服务 List<Server> upList = lb.getReachableServers(); //获得活着的服务 List<Server> allList = lb.getAllServers(); int serverCount = allList.size(); if (serverCount == 0) { return null; } if (total < 5) { server = upList.get(currentIndex); total++; } else { total = 0; currentIndex++; if (currentIndex > upList.size()) { currentIndex = 0; } server = upList.get(currentIndex); } if (server == null) { Thread.yield(); } else { if (server.isAlive()) { return server; } server = null; Thread.yield(); } } return server; } } protected int chooseRandomInt(int serverCount) { return ThreadLocalRandom.current().nextInt(serverCount); } @Override public Server choose(Object key) { return choose(getLoadBalancer(), key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { // TODO Auto-generated method stub } }
注入我们自己写的负载均衡策略
@Configuration public class RibbonConfig { /** * 指定负载均衡策略 */ @Bean public IRule iRule(){ // Nacos提供的负载均衡策略(优先调用同一集群下的实例,基于随机权重) return new MyRibbonConfig(); } }
扩展
开启饥饿加载,解决第一次调用慢的问题
# 开启饥饿加载,解决第一次调用慢的问题 ribbon: eager-load: enabled: true # 配置stock-server使用饥饿加载,多个的话用逗号分隔 clients: stock-server
7、使用LoadBalancer替代Ribbon
1、剔除依赖,既然不用ribbon自然要把依赖去除掉
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <exclusions> <exclusion> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </exclusion> </exclusions> </dependency> <!--添加loadbalancer依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
2、如果不剔除,也可以在yml进行配置
spring: application: name: order-server cloud: nacos: loadbalancer: ribbon: enable: false
3、配置完成后直接启动即可,将以轮询的策略进行访问。