一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
背景问题
对于目前一些主流的框架,可能大部分都会选择Spring Cloud
微服务的架构,把不同的模块抽取成一个个独立的微服务
。
例如:ruoyi
这一个开源的Ruoyi-Cloud
版本,就分了很多微服务
。
例如上图,就有7个微服务
。
那就会存在这样的一个问题,如果每个开发人员
,本地要跑起整个项目,那至少得开7个jvm
。那这样的话,对程序员的电脑要求就很高了,同时跑7个jvm
。
这确实是个大问题!!!T_T
别慌,我们来想办法处理一下!!!^_^
我们有这样的一个想法:
1.我们可以在公司的
测试环境
部署一套完整的Ruoyi-Cloud
服务。2.每个开发人员,本地就只需跑起自己需要开发负责的
微服务
。3.当需要调到其他
微服务
的时候,就可以负载到公司测试环境
上的那套Ruoyi-Cloud
微服务
这个想法,是不是很叼!!!
想法是这么回事,那究竟要如何实现这个功能呢?
这里要实现这个功能,就得对Spring Cloud
微服务这套体系,有比较深刻的理解才行!!!
微服务架构
,有一个显著的作用:就是我们可以动态的添加删除服务节点,这些改动,不需要我们业务代码去处理这些逻辑,而是交给了Spring Cloud
微服务体系去管理。
那这样的话,就不得不提及一个概念:负载均衡
,
引用百度百科解析如下:
负载均衡,英文名称为Load Balance,其含义就是指将
负载(工作任务)
进行平衡、分摊
到多个操作单元
上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。
那同样的话,我们的服务节点
,就是这里说到的操作单元
!!!
那我们既然有多个操作单元
,那我们就得使用到每一个操作单元,不然你部署了,而不去使用,那就是资源的浪费了!!!
那我们使得所有的操作单元
,都能被使用到,这里就是负载均衡
的作用了!!!^_^
不知道这么解析,大家伙,能不能get
到(可能解析得不是很对,别喷!!!)
既然是负载均衡
的作用?那Spring Cloud
体系,是怎么实现负载均衡
的呢?
底层实现,就是今天的主角Ribbon
了。
Ribbon
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端
负载均衡的工具。
它提供以下功能
负载均衡
- 容错
- 异步和反应模型中的多协议(HTTP、TCP、UDP)支持
- 缓存和批处理
好了,回归到我们今天的主题:
如何使用Ribbon实现Nacos的协同开发?
协同开发描述
先看架构图:
这里,要解决的问题就是:
API网关,如何选择system,job,gen等服务?
system,如何选择job,gen等服务?
解决思路通过重写Ribbon
的负载均衡策略
。
Ribbon
的负载均衡策略
:
- RoundRobinRule 轮询(默认)
- RandomRule 随机
- WeightedResponseTimeRule 加权轮询
- 。。。
在微服务开发时,比如像Ruoyi-Cloud
开发,我开发一个System
的微服务,其他的微服务我可能都部署在公司服务器上。
System
服务有多个人参与开发,在网关路由访问时,由于System
服务有多个实例,这个时候怎么保证一定路由到当前开发者的实例上来,不然不方便调试。
这确实是一个很大的问题,那我要如何处理这个问题呢,别慌,且听哥们一一道来!!!^_^
那我们可以这么玩,重写Ribbon
的负载均衡策略
,负载均衡策略如下:
1.优先请求本地的服务
2.本地没有,可以选择优先公司环境的服务。
3.本地和公司都无,随机轮询存在的服务
最终的架构如下:
这样,就不怕存在这个问题了。
协同开发实现
- 自定义
负载均衡策略
@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();
}
}
好了,大概的实现,就是这样了!!!^_^
那我们就可以愉快的编写代码了!!!^_^