博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 客户端负载均衡
阅读量:5321 次
发布时间:2019-06-14

本文共 6494 字,大约阅读时间需要 21 分钟。

  • 客户端侧负载均衡

在下图中,负载均衡能力算法是由内容中心提供,内容中心相对于用户中心来说,是用户中心的客户端,所以又被称为客户端侧负载均衡

图片名称

自定义实现Client Random负载均衡

  1. 获取所有的服务list
  2. 随机获取需要访问的服务信息
// 自定义客户端负载均衡能力        // 获取所有用户中心服务的实例列表        List
targetUris = instances.stream().map(i -> i.getUri().toString() + "/users/{id}").collect(Collectors.toList()); //获取随机实例 int i = ThreadLocalRandom.current().nextInt(targetUris.size()); //调用用户微服务 /users/{userId} log.info("请求的目标地址:{}", targetUris.get(i)); ResponseEntity
userEntity = restTemplate.getForEntity( targetUris.get(i), UserDTO.class, userId );

Ribbon

什么是Ribbon

Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法。

Github:

组成接口

image-20190713132523310

内置负载均衡规则

image-20190713133911384

配置方式

  • Java 代码配置
/** * RibbonConfiguration for TODO * * @author Isaac.Zhang | 若初 * @since 2019/7/13 */@Configurationpublic class RibbonConfiguration {    @Bean    public IRule ribbonRule(){        return new RandomRule();    }}/*------------------------------------------------------------*//** * UserCenterRibbonConfiguration for 自定义实现User-center service ribbon client * * @author Isaac.Zhang | 若初 * @since 2019/7/13 */@Configuration@RibbonClient(name = "user-center", configuration = RibbonConfiguration.class)public class UserCenterRibbonConfiguration {    }/*------------------------------------------------------------*/@Configuration//@RibbonClient(name = "user-center", configuration = RibbonConfiguration.class) //作用域为 user-center@RibbonClients(defaultConfiguration = RibbonConfiguration.class) //作用域为全局public class UserCenterRibbonConfiguration {}
  • 使用配置文件
user-center: # service name  ribbon:    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 规则类的全路径名称
图片名称
  • 对比

image-20190713142916635

  • 最佳使用
    • 尽量使用属性配置
    • 在同一个微服务中尽量保持单一配置,不要混合使用,增加定位复杂性

==Tip==

在使用Ribbon的时候,配置class一定不能处于启动类的同级目录及其子目录,否则会导致父子上下文重叠问题,带来的结果就是,Ribbon规则会被配置称全局配置规则,从而被所有微服务应用。

image-20190713141743025

The CustomConfiguration class must be a @Configuration class, but take care that it is not in a @ComponentScan for the main application context. Otherwise, it is shared by all the @RibbonClients. If you use @ComponentScan (or @SpringBootApplication), you need to take steps to avoid it being included (for instance, you can put it in a separate, non-overlapping package or specify the packages to scan explicitly in the @ComponentScan).

Ribbon 饥饿加载

默认情况下,Ribbon是懒加载,在第一次请求的时候才会创建客户端。

ribbon:  eager-load:    enabled: true # 饥饿加载激活    clients: user-center,xxx,xxx # 为哪些clients开启

使用Ribbon 替代自定义实现

  1. 添加依赖(Spring-Cloud-Alibaba-Nacos-Discovery已经依赖了Ribbon,因此不需要额外依赖)

  2. 添加注解(只需要在RestTemplate IOC添加 @LoadBalance)

    /**     * 在Spring 容器中,创建一个对象,类型是{@link RestTemplate}     * 名称/ID 为 restTemplate     * 
    * {@link LoadBalanced} 为RestTemplate整合Ribbon调用 * * @return restTemplate */ @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); }
  3. 添加配置,直接使用

    ResponseEntity
    userEntity = restTemplate.getForEntity( "http://user-center/users/{userId}", UserDTO.class, userId );

扩展Ribbon - 支持Nacos权重

  • 实现接口com.netflix.loadbalancer.IRule
  • 实现抽象类 com.netflix.loadbalancer.AbstractLoadBalancerRule

image-20190713150041397

@Slf4j@RequiredArgsConstructor(onConstructor = @__(@Autowired))public class NacosWeightRule4Ribbon extends AbstractLoadBalancerRule {    private final NacosDiscoveryProperties nacosDiscoveryProperties;    @Override    public void initWithNiwsConfig(IClientConfig clientConfig) {        // 读取配置文件,并初始化 NacosWeightRule4Ribbon    }    @Override    public Server choose(Object key) {        try {            // ILoadBalancer 是Ribbon的入口,基本上我们想要的元素都可以在这个对象中找到            BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();            log.info("NacosWeightRule4Ribbon lb = {}", loadBalancer);            // 想要请求的微服务名称            String name = loadBalancer.getName();            // 实现负载均衡算法            // 可得到服务发现相关的API(nacos内部实现)            NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();            // nacos client 通过基于权重的负载均衡算法,选择一个实例            Instance instance = namingService.selectOneHealthyInstance(name);            log.info("port = {}, weight = {}, instance = {}", instance.getPort(), instance.getWeight(), instance);            return new NacosServer(instance);        } catch (NacosException e) {            log.error("NacosWeightRule4Ribbon {}", e.getMessage());        }        return null;    }}@Configuration@RibbonClients(defaultConfiguration = NacosWeightRule4Ribbon.class) //全局配置public class UserCenterRibbonConfiguration {}

拓展Ribbon - 同集群优先

public Server choose(Object key) {        try {            // 获取到配置文件中的集群名称 BJ            String clusterName = nacosDiscoveryProperties.getClusterName();            BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();            String serviceName = loadBalancer.getName();            //获取服务发现的相关API            NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();            // 1. 找到指定服务的所有实例 A            List
instances = namingService.selectInstances(serviceName, true); // 2. 过滤出相同集群下的所有实例 B List
sameClusterInstances = instances.stream() .filter(instance -> Objects.equals(instance.getClusterName(), clusterName)) .collect(Collectors.toList()); // 3. 如果B为空,则使用 A List
instancesChoosen = new ArrayList<>(); if (CollectionUtils.isEmpty(sameClusterInstances)) { instancesChoosen = instances; log.warn("发生跨集群调用,name = {},clusterName = {}", serviceName, clusterName); } else { instancesChoosen = sameClusterInstances; } // 4. 基于权重的负载均衡算法,返回一个实例 A Instance instance = ExtendBalancer.getHostByRandomWeightOverride(instancesChoosen); log.info("choose instance is : port = {}, instance = {}", instance.getPort(), instance); return new NacosServer(instance); } catch (NacosException e) { e.printStackTrace(); log.error(e.getErrMsg()); } return null; }/*** 调用Nacos内部方法,进行一次包装*/class ExtendBalancer extends Balancer { public static Instance getHostByRandomWeightOverride(List
hosts) { return getHostByRandomWeight(hosts); }}

扩展Ribbon - 基于元数据的版本控制

转载于:https://www.cnblogs.com/zhangpan1244/p/11203754.html

你可能感兴趣的文章
扫描线
查看>>
C#按位操作,直接操作INT数据类型的某一位
查看>>
node
查看>>
初入计算机图形学(二):对bidirectional path tracing的一些困惑
查看>>
关于hive的优化
查看>>
MPLS LDP随堂笔记1
查看>>
[Algorithm] 二分查找之旅
查看>>
[02] mybatis-config.xml 全局配置文件解析
查看>>
centos7安装redis单机版
查看>>
微商竟然靠这样引流?佛山抖音培训老师告诉你其中奥秘
查看>>
function语句和function表达式的随笔
查看>>
ASCII键值查询
查看>>
hdu4393 Throw nails(只用模拟前面500来次,后面根据速度、位置、id值排序即可)
查看>>
生成器函数 推导式
查看>>
Linux下ctrl+c/z/d的区别
查看>>
P3377 【模板】左偏树(可并堆)
查看>>
require和import的区别
查看>>
Final发布文案+美工
查看>>
扩展entityframework.extended使之支持整个实体类更新
查看>>
FFMpeg框架代码阅读
查看>>