Ribbon的负载均衡现实Nacos的协同开发

1,055 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情

背景问题

对于目前一些主流的框架,可能大部分都会选择Spring Cloud微服务的架构,把不同的模块抽取成一个个独立的微服务

例如:ruoyi这一个开源的Ruoyi-Cloud版本,就分了很多微服务

image.png

例如上图,就有7个微服务

那就会存在这样的一个问题,如果每个开发人员,本地要跑起整个项目,那至少得开7个jvm。那这样的话,对程序员的电脑要求就很高了,同时跑7个jvm

这确实是个大问题!!!T_T

image.png

别慌,我们来想办法处理一下!!!^_^

我们有这样的一个想法:

1.我们可以在公司的测试环境部署一套完整的Ruoyi-Cloud服务。

2.每个开发人员,本地就只需跑起自己需要开发负责的微服务

3.当需要调到其他微服务的时候,就可以负载到公司测试环境上的那套Ruoyi-Cloud微服务

这个想法,是不是很叼!!!

image.png

想法是这么回事,那究竟要如何实现这个功能呢?

这里要实现这个功能,就得对Spring Cloud微服务这套体系,有比较深刻的理解才行!!!

微服务架构,有一个显著的作用:就是我们可以动态的添加删除服务节点,这些改动,不需要我们业务代码去处理这些逻辑,而是交给了Spring Cloud微服务体系去管理。

那这样的话,就不得不提及一个概念:负载均衡

引用百度百科解析如下:

负载均衡,英文名称为Load Balance,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。

那同样的话,我们的服务节点,就是这里说到的操作单元!!!

那我们既然有多个操作单元,那我们就得使用到每一个操作单元,不然你部署了,而不去使用,那就是资源的浪费了!!!

那我们使得所有的操作单元,都能被使用到,这里就是负载均衡的作用了!!!^_^

不知道这么解析,大家伙,能不能get到(可能解析得不是很对,别喷!!!)

image.png

既然是负载均衡的作用?那Spring Cloud体系,是怎么实现负载均衡的呢?

底层实现,就是今天的主角Ribbon了。

Ribbon Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。 它提供以下功能

  • 负载均衡
  • 容错
  • 异步和反应模型中的多协议(HTTP、TCP、UDP)支持
  • 缓存和批处理

好了,回归到我们今天的主题:

如何使用Ribbon实现Nacos的协同开发?

image.png

协同开发描述

先看架构图:

image.png

这里,要解决的问题就是:

API网关,如何选择system,job,gen等服务?

system,如何选择job,gen等服务?

解决思路通过重写Ribbon负载均衡策略

Ribbon负载均衡策略

  • RoundRobinRule 轮询(默认)
  • RandomRule 随机
  • WeightedResponseTimeRule 加权轮询
  • 。。。

在微服务开发时,比如像Ruoyi-Cloud开发,我开发一个System的微服务,其他的微服务我可能都部署在公司服务器上。

System服务有多个人参与开发,在网关路由访问时,由于System服务有多个实例,这个时候怎么保证一定路由到当前开发者的实例上来,不然不方便调试。

image.png

这确实是一个很大的问题,那我要如何处理这个问题呢,别慌,且听哥们一一道来!!!^_^

image.png

那我们可以这么玩,重写Ribbon负载均衡策略,负载均衡策略如下:

1.优先请求本地的服务

2.本地没有,可以选择优先公司环境的服务。

3.本地和公司都无,随机轮询存在的服务

最终的架构如下:

image.png

这样,就不怕存在这个问题了。

协同开发实现

  • 自定义负载均衡策略
@Slf4j
public class CustomNacosRule extends AbstractLoadBalancerRule {
    /**
     * 本地ip地址
     */
    public String SERVER_HOST_IP;

    public CustomNacosRule() {
        this.SERVER_HOST_IP = IpUtils.getIpAddress();
        log.info("本地服务ip {}", SERVER_HOST_IP);
    }

    @Autowired
    private NacosDiscoveryProperties discoveryProperties;

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

    /**
     * 这个方法是实现负载均衡策略的方法
     *
     * @param key
     * @return
     */
    @Override
    public Server choose(Object key) {
        try {
            //优先负载均衡ip
            String priorIp = Global.getPriorIp();

            // 获取当前负载均衡器
            BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
            // 获取当前服务的实例名称
            String serviceName = loadBalancer.getName();
            // 获取nacos client服务注册发现api
            NamingService namingService = discoveryProperties.namingServiceInstance();
            // 通过namingService获取当前注册的所有服务实例
            List<Instance> allInstances = namingService.getAllInstances(serviceName);
            if (CollectionUtils.isEmpty(allInstances)) {
                log.warn("服务中没有实例 {}", serviceName);
                return null;
            }
            List<Instance> instanceList = new ArrayList<>();
            // (1)、优先本地ip的实例
            for (Instance instance : allInstances) {
                if (StringUtils.endsWithIgnoreCase(instance.getIp(), SERVER_HOST_IP)) {
                    log.debug("优先本地服务实例--{}", instance.getInstanceId());
                    instanceList.add(instance);
                }
            }
            Instance chooseInstance = null;
            if (instanceList.size() > 0) {
                chooseInstance = ExtendBalancer.getHostByRandomWeight2(instanceList);
                return new NacosServer(chooseInstance);
            }

            // (2)、优先的ip服务
            for (Instance instance : allInstances) {
                if (StringUtils.endsWithIgnoreCase(instance.getIp(), priorIp)) {
                    log.debug("优先ip服务实例--{}", instance.getInstanceId());
                    instanceList.add(instance);
                }
            }
            if (instanceList.size() > 0) {
                chooseInstance = ExtendBalancer.getHostByRandomWeight2(instanceList);
                return new NacosServer(chooseInstance);
            }

            // (3)、随机的ip服务
            if (instanceList.size() == 0) {
                chooseInstance = ExtendBalancer.getHostByRandomWeight2(allInstances);
                log.debug("随机服务实例--{}", chooseInstance.getInstanceId());
            }
            return new NacosServer(chooseInstance);
        } catch (NacosException e) {
            e.printStackTrace();
            return null;
        }
    }
}
  • 配置负载均衡策略生效

@Configuration
@RibbonClients(defaultConfiguration = GlobalRibbonConfig.class)
public class CustomRibbonConfig {
}

@Configuration
public class GlobalRibbonConfig {
    @Bean
    public IRule getRule() {
        // 实现带有权重本地ip优先的负载均衡策略
        return new CustomNacosRule();
    }
}

好了,大概的实现,就是这样了!!!^_^

那我们就可以愉快的编写代码了!!!^_^

image.png