作用

负载均衡
用于客户端负载均衡

集中式负载均衡:消费者与服务提供方中间使用独立方式负载,如F5, NGINX

客户端负载均衡

又客户端,也就是调用方决定调用哪个服务提供者
image.png

服务端负责均衡、

客户端,也就是调用方调用负载中心插件,负载中心决定调用哪个服务提供者
image.png

常见负载均衡算法

  1. 轮询
  2. 随机
  3. 加权轮询
  4. 地址hash
  5. 最小连接数

    ribbon模块

    | 名 称 | 说 明 | | —- | —- | | ribbon-loadbalancer | 负载均衡模块,可独立使用,也可以和别的模块一起使用。 | | Ribbon | 内置的负载均衡算法都实现在其中。 | | ribbon-eureka | 基于 Eureka 封装的模块,能够快速、方便地集成 Eureka。 | | ribbon-transport | 基于 Netty 实现多协议的支持,比如 HTTP、Tcp、Udp 等。 | | ribbon-httpclient | 基于 Apache HttpClient 封装的 REST 客户端,集成了负载均衡模块,可以直接在项目中使用来调用接口。 | | ribbon-example | Ribbon 使用代码示例,通过这些示例能够让你的学习事半功倍。 | | ribbon-core | 一些比较核心且具有通用性的代码,客户端 API 的一些配置和其他 API 的定义。 |

spring cloud 整合ribbon

依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
  4. </dependency>

nacos-discovery依赖ribbon
image.png

配置使用

  1. @Configuration
  2. public class RestConfig {
  3. @Bean
  4. @LoadBalanced
  5. public RestTemplate restTemplate() {
  6. return new RestTemplate();
  7. }

调用

  1. @Autowired
  2. private RestTemplate restTemplate;
  3. @RequestMapping(value = "/findOrderByUserId/{id}")
  4. public R findOrderByUserId(@PathVariable("id") Integer id) {
  5. // RestTemplate调用
  6. //String url = "http://localhost:8020/order/findOrderByUserId/"+id;
  7. //模拟ribbon实现
  8. //String url = getUri("mall-order")+"/order/findOrderByUserId/"+id;
  9. // 添加@LoadBalanced
  10. String url = "http://mall-order/order/findOrderByUserId/"+id;
  11. R result = restTemplate.getForObject(url,R.class);
  12. return result;
  13. }

内核原理

拦截器 LoadBalancerInterceptor

原理就是 拦截调用,把对应服务名替换成对应ip ,端口

@LoadBanlanced注解原理

LoadBalancerAutoConfiguration

Ribbin 相关接口

RibbonClientConfiguration
IClientConfig:ribbon客户端,默认DefaultClientConfigImpl实现
IRule:负责均衡策略默认采用ZoneAvoidanceRule实现
IPing :实例检查策略 DummyPing实现
ServerList 服务实例列表,ConfigurationBasedServerList实现
ServerListFilter:服务实例过滤机制,优先过滤出于请求方同一区域的服务实例
ILoadBalancer :负载均衡ZoneAwareLoadBalancer 实现
1657033278909.png

负载均衡策略

1657033293859.png

  1. RandomRule
  2. RetryRule
  3. RoundRobinRule
  4. AvailabilityFilteringRule
  5. BestAvailableRule: 。
  6. WeightedResponseTimeRule
  7. ZoneAvoidanceRule:默认的负载均衡策略,
  8. NacosRule:


自定义负载均衡策略

实现 IRule接口可以自定义负载均衡策略,重新choose方法

  1. @Slf4j
  2. public class NacosRandomWithWeightRule extends AbstractLoadBalancerRule {
  3. @Autowired
  4. private NacosDiscoveryProperties nacosDiscoveryProperties;
  5. @Override
  6. public Server choose(Object key) {
  7. DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
  8. String serviceName = loadBalancer.getName();
  9. NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
  10. try {
  11. //nacos基于权重的算法
  12. Instance instance = namingService.selectOneHealthyInstance(serviceName);
  13. return new NacosServer(instance);
  14. } catch (NacosException e) {
  15. log.error("获取服务实例异常:{}", e.getMessage());
  16. e.printStackTrace();
  17. }
  18. return null;
  19. }
  20. @Override
  21. public void initWithNiwsConfig(IClientConfig clientConfig) {
  22. }

配置application.yml

  1. # 被调用的微服务名
  2. mall-order:
  3. ribbon:
  4. # 自定义的负载均衡策略(基于随机&权重) 对应方法全路径名
  5. NFLoadBalancerRuleClassName: com.NacosRandomWithWeightRule

利用@RibbonClient指定微服务的放回寺配置负载均衡

  1. @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
  2. DruidDataSourceAutoConfigure.class})
  3. //@RibbonClient(name = "mall-order",configuration = RibbonConfig.class)
  4. //配置多个 RibbonConfig不能被@SpringbootApplication的@CompentScan扫描到,否则就是全局配置的效果
  5. @RibbonClients(value = {
  6. // 在SpringBoot主程序扫描的包外定义配置类
  7. @RibbonClient(name = "mall-order",configuration = RibbonConfig.class),
  8. @RibbonClient(name = "mall-account",configuration = RibbonConfig.class)
  9. })
  10. public class MallUserRibbonDemoApplication {
  11. public static void main(String[] args) {
  12. SpringApplication.run(MallUserRibbonDemoApplication.class, args);
  13. }
  14. }

注意
不能写在compentScan扫描到的地方,不让会被所有的ribbonClients共享,最好还是yml配置

饥饿加载

只有在调起的时候才会创建客户端
需要在配置文件中配置

  1. ribbon:
  2. eager-load:
  3. # 开启ribbon饥饿加载
  4. enabled: true
  5. # 配置mall-order使用ribbon饥饿加载,多个使用逗号分隔
  6. clients: mall-order

源码类: RibbonEagerLoadProperties

LoanBalancer

spring cloud LoadBalancer spring cloud 提供的客户端负载均衡,用来替代Ribbon的

Spring官方两种客户端

  1. RestTemplate
    访问rest 服务的客户端,访问http的,依赖jdk的http工具
  2. WebClient
    Spring webFlux 5.0提供,非阻塞的基于响应式变成的http,j
    基于Reactor,

引入依赖

  1. <!-- LoadBalancer -->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  5. </dependency>
  6. <!-- 提供了RestTemplate支持 -->
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-web</artifactId>
  10. </dependency>
  11. <!-- nacos服务注册与发现 移除ribbon支持-->
  12. <dependency>
  13. <groupId>com.alibaba.cloud</groupId>
  14. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  15. <exclusions>
  16. <exclusion>
  17. <groupId>org.springframework.cloud</groupId>
  18. <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
  19. </exclusion>
  20. </exclusions>
  21. </dependency>

注意点: nacos-discory 引入了ribbon,需要排除
原因是:RibbonLoadBalancerClient和BlockingLoadBalancerClient会倾向使用前者
所以需要排除RibbonLoadBalancerClient
也可以在yml配置中排除

  1. #yml中排除ribbon
  2. spring:
  3. application:
  4. name: mall-user-loadbalancer-demo
  5. cloud:
  6. nacos:
  7. discovery:
  8. server-addr: 127.0.0.1:8848
  9. # 不使用ribbon
  10. loadbalancer:
  11. ribbon:
  12. enabled: false

client的继承关系
image.png

使用@LoadBalanced 配置RestTemplate

  1. @Configuration
  2. public class RestConfig {
  3. @Bean
  4. @LoadBalanced
  5. public RestTemplate restTemplate() {
  6. return new RestTemplate();
  7. }
  8. }

客户端使用

  1. @RestController
  2. @RequestMapping("/user")
  3. public class UserController {
  4. @Autowired
  5. private RestTemplate restTemplate;
  6. @RequestMapping(value = "/findOrderByUserId/{id}")
  7. public R findOrderByUserId(@PathVariable("id") Integer id) {
  8. String url = "http://mall-order/order/findOrderByUserId/"+id;
  9. R result = restTemplate.getForObject(url,R.class);
  10. return result;
  11. }
  12. }