一、背景

在我们开发微服务架构系统时,虽然说每个微服务都是孤立的可以单独开发,但实际上并非如此,要调试和测试你的服务不仅需要您的微服务启动和运行,还需要它的上下文服务、依赖的基础服务等都要运行;但如果你的系统服务数和依赖比较多呢,那就是一个比较棘手的问题!有没有办法能提高开发效率呢?

如上图所示,我们能不能用服务器把所有的服务都部署起来,然后开发只在本地运行自己所负责开发的服务,因为需要依赖其他服务所以本地启动的服务也需要注册到公共的注册中心里;

例子中业务服务B有3台实例注册到注册中心里

分别是:服务器的、开发A与开发B自己本机启动的

但是这样做又会出现新的问题:服务会冲突乱窜,意思就是开发A在debug自己的业务服务B服务的时候可能请求会跳转到其他人的实例上(服务器、开发B)

 

二、解决思路

解决这个服务乱窜问题有一个比较优雅的方式就是自定义负载均衡规则,主要实现以下目标:

  1. 普通用户访问服务器上的页面时,请求的所有路由只调用服务器上的实例
  2. 开发A访问时,请求的所有路由优先调用开发A本机启动的实例,如果没有则调用服务器上的实例
  3. 开发B访问时同上,请求的所有路由优先调用开发B本机启动的实例,如果没有则调用服务器上的实例

 

三、具体实现

要实现上面的目标有两个比较关键的问题需要解决

  1. 区分不同用户的服务实例
  2. 实现自定义负载均衡规则

3.1. 区分不同用户的服务实例

直接使用注册中心的元数据(metadata)来区分就可以了

主流的注册中心都带有元数据管理

Nacos为例,只需要在配置文件下添加

spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
metadata:
version: zlt

metadata下的version 就是我添加的元数据key为version,value为zlt

启动服务后元数据就会注册上去,如下图

经过元数据区分后,目前是下面这个情况

  • 服务器的实例version为空
  • 开发人员自己本地启动的实例version为唯一标识(自己的名字)

 

3.2. 自定义负载均衡规则

首先在Spring Cloud微服务框架里实例的负载均衡是由Ribbon负责。

CustomIsolationRule详细类信息可查看:CustomIsolationRule.java

public class CustomIsolationRule extends RoundRobinRule {
/**
* 优先根据版本号取实例
*/
@Override
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
String version = LbIsolationContextHolder.getVersion();
List<Server> targetList = null;
List<Server> upList = lb.getReachableServers();
if (StrUtil.isNotEmpty(version)) {
//取指定版本号的实例
targetList = upList.stream().filter(
server -> version.equals(
((NacosServer) server).getMetadata().get(CommonConstant.METADATA_VERSION)
)
).collect(Collectors.toList());
} if (CollUtil.isEmpty(targetList)) {
//只取无版本号的实例
targetList = upList.stream().filter(
server -> {
String metadataVersion = ((NacosServer) server).getMetadata().get(CommonConstant.METADATA_VERSION);
return StrUtil.isEmpty(metadataVersion);
}
).collect(Collectors.toList());
} if (CollUtil.isNotEmpty(targetList)) {
return getServer(targetList);
}
return super.choose(lb, key);
} /**
* 随机取一个实例
*/
private Server getServer(List<Server> upList) {
int nextInt = RandomUtil.randomInt(upList.size());
return upList.get(nextInt);
}
}

继承轮询规则RoundRobinRule来实现,主要的逻辑为

  1. 根据上游输入的版本号version,有值的话则取服务元信息version值一样的实例
  2. 上游的版本号version没值或者该版本号匹配不到任何服务,则只取服务元信息version值为空的实例

 

并通过配置开关控制是否开启自定义负载规则

@Configuration
@ConditionalOnProperty(value = "zlt.ribbon.isolation.enabled", havingValue = "true")
@RibbonClients(defaultConfiguration = {RuleConfigure.class})
public class LbIsolationConfig { }

 

四、总结

上面提到的区分服务实例自定义负载规则为整个解决思路的核心点,基本实现了服务实例的隔离,剩下要做的就是上游的version怎样传递呢?,下面我提供两个思路

  • 开发人员自己启动前端工程,通过配置参数,统一在前端工程传递version
  • 通过postman调用接口的时候在header参数中添加

 

参考

https://github.com/Nepxion/Discovery

 

推荐阅读

 

Spring Cloud开发人员如何解决服务冲突和实例乱窜?的更多相关文章

  1. Spring Cloud开发人员如何解决服务冲突和实例乱窜?(IP实现方案)

    一.背景 在我上一篇文章<Spring Cloud开发人员如何解决服务冲突和实例乱窜?>中提到使用服务的元数据来实现隔离和路由,有朋友问到能不能直接通过IP来实现?本文就和大家一起来讨论一 ...

  2. Spring Cloud开发实践 - 02 - Eureka服务和接口定义

    服务注册 EurekaServer Eureka服务模块只有三个文件, 分别是pom.xml, application.yml 和 EurekaServerApplication.java, 内容如下 ...

  3. 【译文】用Spring Cloud和Docker搭建微服务平台

    by Kenny Bastani Sunday, July 12, 2015 转自:http://www.kennybastani.com/2015/07/spring-cloud-docker-mi ...

  4. Spring Cloud和Docker搭建微服务平台

    用Spring Cloud和Docker搭建微服务平台 This blog series will introduce you to some of the foundational concepts ...

  5. Spring Cloud官方文档中文版-Spring Cloud Config(上)-服务端(配置中心)

    官方文档地址为:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#spring-cloud-feign 文中例子我做了一些测试在:http ...

  6. Spring Cloud(一):服务治理技术概览【Finchley 版】

    Spring Cloud(一):服务治理技术概览[Finchley 版]  发表于 2018-04-14 |  更新于 2018-05-07 |  Spring Cloud Netflix 是 Spr ...

  7. 从 Spring Cloud 开始,聊聊微服务架构实践之路

    [编者的话]随着公司业务量的飞速发展,平台面临的挑战已经远远大于业务,需求量不断增加,技术人员数量增加,面临的复杂度也大大增加.在这个背景下,平台的技术架构也完成了从传统的单体应用到微服务化的演进. ...

  8. 【Spring Cloud学习之一】微服务架构

    一.网站架构模式发展 单体应用-->SOA-->微服务 1.分布式项目与项目集群分布式项目:根据业务需求进行拆分成N个子系统,多个子系统相互协作才能完成业务流程子系统之间通讯使用RPC远程 ...

  9. 9.Spring Cloud Config统一管理微服务配置

    Spring Cloud Config统一管理微服务配置 9.1. 为什么要统一管理微服务配置 9.2. Spring Cloud Config简介 Spring Cloud Config为分布式系统 ...

随机推荐

  1. 3. 源码分析---SOFARPC客户端服务调用

    我们首先看看BoltClientProxyInvoker的关系图 所以当我们用BoltClientProxyInvoker#invoke的时候实际上是调用了父类的invoke方法 ClientProx ...

  2. dubbo文档笔记

    配置覆盖关系 以 timeout 为例,显示了配置的查找顺序,其它 retries, loadbalance, actives 等类似: 方法级优先,接口级次之,全局配置再次之. 如果级别一样,则消费 ...

  3. c#小灶——注释和代码规范

    为什么要写注释? 早上我写完了代码,我和我的朋友们都能看懂,到了晚上,我还能看懂,一周后,就只有上帝能看懂了…… 将来我们写的代码量是很大的,代码又不像我们自然语言这么好理解,可能过段时间我们就不认识 ...

  4. MySQL操作命令梳理(2)

    一.表操作 在mysql运维操作中会经常使用到alter这个修改表的命令,alter tables允许修改一个现有表的结构,比如增加或删除列.创造或消去索引.改变现有列的类型.或重新命名列或表本身,也 ...

  5. 自定义 Button 选择器

    极力推荐文章:欢迎收藏 Android 干货分享 阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以 ...

  6. 面向对象---prototype、__proto__、实例化对象三者之间的关系

    1.构造函数 a.什么是构造函数? 解释:通过关键字new 创建的函数叫做构造函数 作用:用来创建一个对象 废话少说直接上代码,首先我们还是创建一个构造函数人类 然后我们在创建两个实例,一个凡尘 一个 ...

  7. 本地NTP服务器与客户端配置

    1. NTP 简介 NTP是网络时间协议(Network Time Protocol),它是用来同步网络中各个计算机的时间的协议. 在集群中,为了保证各节点之间的时间一致,我们通常需要配置本地的 NT ...

  8. leetcode 29 两数相除

    问题描述 给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 示例 ...

  9. ethtool工具使用实例

    使用ethtool工具可以查看和修改网卡(NIC卡)设备配置,下面我们来看ethtool的具体用法. 1.显示网卡属性 ethtool命令后直接跟网卡名称,可以显示关于该网卡的属性值: # ethto ...

  10. Spring 核心技术(6)

    接上篇:Spring 核心技术(5) version 5.1.8.RELEASE 1.5 Bean 作用域 创建 bean 定义时,你创建了一种用于创建 bean 定义中定义的类实例的方法.bean定 ...