Ribbon原理
客户端的负载均衡
客户端根据自己的请求情况做负载均衡,Ribbon 就属于客户端自己做负载均衡
服务端的负载均衡
集中式负载均衡,在消费者和服务提供方中间使用独立的代理方式进行负载,有硬件的(比如 F5),也有软件的(比如Nginx)
Ribbon相关接口
- IRule:Ribbon的负载均衡策略,默认采用ZoneAvoidanceRule实现,该策略能够在多区域环境下选出最佳区域的实例进行访问。
- IPing:Ribbon的实例检查策略,默认采用DummyPing实现,该检查策略是一个特殊的实现,实际上它并不会检查实例是否可用,而是始终返回true,默认认为所有服务实例都是可用的。
- ServerList:服务实例清单的维护机制,默认采用ConfigurationBasedServerList实现。
- ServerListFilter:服务实例清单过滤机制,默认采ZonePreferenceServerListFilter,该策略能够优先过滤出与请求方处于同区域的服务实例。
- ILoadBalancer:负载均衡器,默认采用ZoneAwareLoadBalancer实现,它具备了区域感知的能力。
常见负载均衡算法
- 随机,通过随机选择服务进行执行,一般这种方式使用较少;
- 轮训,负载均衡默认实现方式,请求来之后排队处理;
- 加权轮训,通过对服务器性能的分型,给高配置,低负载的服务器分配更高的权重,均衡各个服务器的压力;
- 地址Hash,通过客户端请求的地址的HASH值取模映射进行服务器调度。 ip --->hash
- 最小链接数,即使请求均衡了,压力不一定会均衡,最小连接数法就是根据服务器的情况,比如请求积压数等参数,将请求分配到当前压力最小的服务器上。 最小活跃数
Nacos使用Ribbon
nacos-discovery依赖了ribbon,可以不用再引入ribbon依赖
使用 @LoadBalanced 注解
package com.order; import com.config.rule.RibbonNacosConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; 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.web.client.RestTemplate; /** * @author vans on 2022/2/16 18:32 */ /** * 此配 scanBasePackages={"com.netflix.client.config.IClientConfig"} 解决: * Consider defining a bean of type 'com.netflix.client.config.IClientConfig' in your configuration. */ @SpringBootApplication(scanBasePackages={"com.netflix.client.config.IClientConfig","com.order"})
public class VnOrderApplication { public static void main(String[] args) { SpringApplication.run(VnOrderApplication.class,args); } /** * * @param restTemplateBuilder * @return * * @LoadBalanced 定义负载均衡器 * */ @Bean @LoadBalanced public RestTemplate getRestTemplate(RestTemplateBuilder restTemplateBuilder){ RestTemplate restTemplate = restTemplateBuilder.build(); return restTemplate; } }
package com.order.controller; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; /** * @author vans on 2022/2/16 18:13 */ @RestController @RequestMapping("/vn/order") @Slf4j public class OrderController { @Autowired private RestTemplate restTemplate; @ApiOperation(value = "获取所有用户列表", notes = "不需要任何参数") @ApiImplicitParam(name = "运单号", value = "mailNo", required = false, dataType = "String") @RequestMapping(value="/{mailNo}",method = RequestMethod.GET) public String getOrder(@PathVariable("mailNo") String mailNo) { String message = restTemplate.getForObject("http://stock-service:90/vn/stock", String.class); return message; } }
Ribbon负载均衡策略
IRule:所有负载均衡策略的父接口,里边的核心方法就是choose方法,用来选择一个服务实例。
AbstractLoadBalancerRule是一个抽象类,里边主要定义了一个ILoadBalancer,这里定义它的目的主要是辅助负责均衡策略选取合适的服务端实例。
RandomRule 看名字就知道,这种负载均衡策略就是随机选择一个服务实例
RoundRobinRule这种负载均衡策略叫做线性轮询负载均衡策略。
RetryRule(在轮询的基础上进行重试) 看名字就知道这种负载均衡策略带有重试功能。
WeightedResponseTimeRule是RoundRobinRule的一个子类,在WeightedResponseTimeRule中对RoundRobinRule的功能进行了扩展, WeightedResponseTimeRule中会根据每一个实例的运行情况来给计算出该实例的一个权重,然后在挑选实例的时候则根据权重进行挑选,这样能 够实现更优的实例调用
修改默认负载均衡策略
两种方式修改默认负载均衡策略:1、使用配置类 2、使用配置文件
第一种:
package com.config.rule; /** * @author vans on 2022/2/19 18:31 */ import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 修改默认负载均衡策略 * * 此处有坑。不能写在@SpringbootApplication注解的@CompentScan扫描得到的地方, * 否则自定义的配置类就会被所有的 RibbonClients共享。 不建议这么使用,推荐yml方式 * */ @Configuration public class RibbonRandomConfig { /** * * 指定为 随机策略 * * 此处方法名必须为 iRule */ @Bean public IRule iRule() { return new RandomRule(); } }
package com.order;
import com.config.rule.RibbonNacosConfig;
import com.config.rule.RibbonRandomConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
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.web.client.RestTemplate;
/**
* @author vans on 2022/2/16 18:32
*/
/**
* 此配 scanBasePackages={"com.netflix.client.config.IClientConfig"} 解决:
* Consider defining a bean of type 'com.netflix.client.config.IClientConfig' in your configuration.
*/
@SpringBootApplication(scanBasePackages={"com.netflix.client.config.IClientConfig","com.order"})
@RibbonClients(@RibbonClient(value = "stock-service",configuration = RibbonRandomConfig.class))
public class VnOrderApplication {
public static void main(String[] args) {
SpringApplication.run(VnOrderApplication.class,args);
}
/**
*
* @param restTemplateBuilder
* @return
*
* @LoadBalanced 定义负载均衡器
*
*/
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(RestTemplateBuilder restTemplateBuilder){
RestTemplate restTemplate = restTemplateBuilder.build();
return restTemplate;
}
}
第二种:
server: port: 80 spring: application: name: order-service # 应用名称 nacos 会将名称作为服务名称 cloud: nacos: server-addr: 192.168.43.66:8848 # nacos 服务器地址 discovery: username: nacos password: nacos namespace: public # 被调用的微服务名 stock-service: ribbon: # 指定使用Nacos提供的负载均衡策略(优先调用同一集群的实例,基于随机&权重) NFLoadBalancerRuleClassName: com.config.rule.RibbonNacosConfig ribbon: eager-load: # 开启ribbon饥饿加载 enabled: true # 配置stock-service使用ribbon饥饿加载,多个使用逗号分隔 clients: stock-service
自定义负载均衡策略
package com.config.rule; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.Server; import java.util.List; import java.util.concurrent.ThreadLocalRandom; /** * @author vans on 2022/2/19 19:07 * * 自定义负载均衡策略 * */ public class CustomRuleConfig extends AbstractLoadBalancerRule { @Override public Server choose(Object o) { ILoadBalancer loadBalancer = this.getLoadBalancer(); List<Server> allServers = loadBalancer.getAllServers(); int radom = ThreadLocalRandom.current().nextInt(allServers.size()); Server server = allServers.get(radom); return server; } @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { } }
server: port: 80 spring: application: name: order-service # 应用名称 nacos 会将名称作为服务名称 cloud: nacos: server-addr: 192.168.43.66:8848 # nacos 服务器地址 discovery: username: nacos password: nacos namespace: public # 被调用的微服务名 stock-service: ribbon: # 指定使用提供的负载均衡策略 NFLoadBalancerRuleClassName: com.config.rule.CustomRuleConfig ribbon: eager-load: # 开启ribbon饥饿加载 enabled: true # 配置stock-service使用ribbon饥饿加载,多个使用逗号分隔 clients: stock-service
异构微服务
引入POM依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sidecar</artifactId> </dependency>
配置文件
server: port: 8088 spring: cloud: nacos: discovery: server-addr: 127.0.0.1:8848 application: name: sidecar-simple # 配置异构服务 sidecar: ip: localhost port: 8081 #异构微服务的健康检查URL health-check-url: http://localhost:8081/health