阿里巴巴是如何打通 CMDB,实现就近访问的?

CMDB在企业中,一般用于存放与机器设备、应用、服务等相关的元数据。当企业的机器及应用达到一定规模后就需要这样一个系统来存储和管理它们的元数据。有一些广泛使用的属性,例如机器的IP、主机名、机房、应用、region等,这些数据一般会在机器部署时录入到CMDB,运维或者监控平台会使用这些数据进行展示或者相关的运维操作。

在服务进行多机房或者多地域部署时,跨地域的服务访问往往延迟较高,一个城市内的机房间的典型网络延迟在1ms左右,而跨城市的网络延迟,例如上海到北京大概为30ms。此时自然而然的一个想法就是能不能让服务消费者和服务提供者进行同地域访问。

我们在集团内部的实践中,这样的需求是通过和CMDB打通来实现的。Nacos的服务发现组件中,对接CMDB,然后通过配置的访问规则,来实现服务消费者到服务提供者的同地域优先。

1544702277705-0bbfca60-6629-477c-92bb-1a690e68f9cd.png

图1 服务的同地域优先访问

这实际上就是一种负载均衡策略,在Nacos的规划中,丰富的服务端的可配置负载均衡策略是我们的重要发展方向,这与当前已有的注册中心产品不太一样。在设计如何在开源的场景中,支持就近访问的时候,与企业自带的CMDB集成是我们考虑的一个核心问题。除此之外,我们也在考虑将Nacos自身扩展为一个实现基础功能的CMDB。无论如何,我们都需要能够从某个地方获取IP的环境信息,这些信息要么是从企业的CMDB中查询而来,要么是从自己内置的存储中查询而来。

CMDB插件机制

先不考虑如何将CMDB的数据应用于负载均衡,我们需要首先在Nacos里将CMDB的数据通过某种方法获取。在实际使用中,基本上每个公司都会通过购买或者自研搭建自己的CMDB,那么为了能够解耦各个企业的CMDB具体实现,一个比较好的策略是使用SPI机制,约定CMDB的抽象调用接口,由各个企业添加自己的CMDB插件,无需任何代码上的重新构建,即可在运行状态下对接上企业的CMDB。

1544842539697-cca20e3d-0f78-45b8-92b9-3b7559e838b2.png

图2 Nacos CMDB SPI机制原理

如图2所示,Nacos定义了一个SPI接口,里面包含了与第三方CMDB约定的一些方法。用户依照约定实现了相应的SPI接口后,将实现打成jar包放置到Nacos安装目录下,重启Nacos即可让Nacos与CMDB的数据打通。整个流程并不复杂,但是理解CMDB SPI接口里方法和相应概念的含义不太简单。在这里对CMDB机制的相关概念和接口含义做一个详细说明。

CMDB抽象概念

实体(Entity)

实体是作为CMDB里数据的承载方,在一般的CMDB中,一个实体可以指一个IP、应用或者服务。而这个实体会有很多属性,例如IP的机房信息,服务的版本信息等。

实体类型(Entity Type)

我们并不限定实体一定是IP、应用或者服务,这取决于实际的业务场景。Nacos有计划在未来支持不同的实体类型,不过就目前来说,服务发现需要的实体类型是IP。

标签(Label)

Label是我们抽象出的Entity属性,Label定义为一个描述Entity属性的K-V键值对。Label的key和value的取值范围一般都是预先定义好的,当需要对Label进行变更,如增加新的key或者value时,需要调用单独的接口并触发相应的事件。一个常见的Label的例子是IP的机房信息,我们认为机房(site)是Label的key,而机房的集合(site1, site2, site3)是Label的value,这个Label的定义就是:site: {site1, site2, site3}。

实体事件(Entity Event)

实体的标签的变更事件。当CMDB的实体属性发生变化,需要有一个事件机制来通知所有订阅方。为了保证实体事件携带的变更信息是最新准确的,这个事件里只会包含变更的实体的标识以及变更事件的类型,不会包含变更的标签的值。

CMDB约定接口

在设计与CMDB交互接口的时候,我们参考了内部对CMDB的访问接口,并与若干个外部客户进行了讨论。我们最终确定了以下要求第三方CMDB插件必须实现的接口:

获取标签列表

Set<String> getLabelNames();

这个方法将返回CMDB中需要被Nacos识别的标签名集合,CMDB插件可以按需决定返回什么标签个Nacos。不在这个集合的标签将会被Nacos忽略,即使这个标签出现在实体的属性里。我们允许这个集合会在运行时动态变化,Nacos会定时去调用这个接口刷新标签集合。

获取实体类型

Set<String> getEntityTypes();

获取CMDB里的实体的类型集合,不在这个集合的实体类型会被Nacos忽略。服务发现模块目前需要的实体类似是ip,如果想要通过打通CMDB数据来实现服务的高级负载均衡,请务必在返回集合里包含“ip”。

获取标签详情

Label getLabel(String labelName);

获取标签的详细信息。返回的Label类里包含标签的名字和标签值的集合。如果某个实体的这个标签的值不在标签值集合里,将会被视为无效。

查询实体的标签值

String getLabelValue(String entityName, String entityType, String labelName);
Map<String, String> getLabelValues(String entityName, String entityType);

这里包含两个方法,一个是获取实体某一个标签名对应的值,一个是获取实体所有标签的键值对。参数里包含实体的值和实体的类型。注意,这个方法并不会在每次在Nacos内部触发查询时去调用,Nacos内部有一个CMDB数据的缓存,只有当这个缓存失效或者不存在时,才会去访问CMDB插件查询数据。为了让CMDB插件的实现尽量简单,我们在Nacos内部实现了相应的缓存和刷新逻辑。

查询实体

Map<String, Map<String, Entity>> getAllEntities();
Entity getEntity(String entityName, String entityType);

查询实体包含两个方法:查询所有实体和查询单个实体。查询单个实体目前其实就是查询这个实体的所有标签,不过我们将这个方法与获取所有标签的方法区分开来,因为查询单个实体方法后面可能会进行扩展,比查询所有标签获取的信息要更多。

查询所有实体则是一次性将CMDB的所有数据拉取过来,该方法可能会比较消耗性能,无论是对于Nacos还是CMDB。Nacos内部调用该方法的策略是通过可配置的定时任务周期来定时拉取所有数据,在实现该CMDB插件时,也请关注CMDB服务本身的性能,采取合适的策略。

查询实体事件

List<EntityEvent> getEntityEvents(long timestamp);

这个方法意在获取最近一段时间内实体的变更消息,增量的去拉取变更的实体。因为Nacos不会实时去访问CMDB插件查询实体,需要这个拉取事件的方法来获取实体的更新。参数里的timestamp为上一次拉取事件的时间,CMDB插件可以选择使用或者忽略这个参数。

CMDB插件开发流程

参考 https://github.com/nacos-group/nacos-examples,这里已经给出了一个示例plugin实现。
具体步骤如下:

  1. 新建一个maven工程,引入依赖nacos-api:
    plain <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-api</artifactId> <version>0.7.0</version> </dependency>
  2. 引入打包插件:
    plain <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin>
  3. 定义实现类,继承com.alibaba.nacos.api.cmdb.CmdbService,并实现相关方法。

1543916500193-213df77a-096d-4fd9-a283-85241a856fbf.png

  1. 在src/main/resource/目录下新建目录:META-INF/services

1543916595978-fd322205-16c1-4a95-9cdc-4a6292ee3b66.png

  1. 在src/main/resources/META-INF/services目录下新建文件com.alibaba.nacos.api.cmdb.CmdbService,并在文件里将第三步中创建的实现类全名写入该文件:

1545036650034-75d11aee-8738-485f-9426-52e560b059cd.png

  1. 代码自测完成后,执行命令进行打包:
    plain mvn package assembly:single -Dmaven.test.skip=true
  2. 将target目录下的包含依赖的jar包上传到nacos CMDB插件目录:
    plain {nacos.home}/plugins/cmdb
  3. 在nacos的application.properties里打开加载插件开关:
    plain nacos.cmdb.loadDataAtStart=true
  4. 重启nacos Server,即可加载到您实现的nacos-cmdb插件获取您的CMDB数据。

使用Selector实现同机房优先访问

在拿到CMDB的数据之后,就可以运用CMDB数据的强大威力来实现多种灵活的负载均衡策略了,下面举例来说明如何使用CMDB数据和Selector来实现就近访问。

假设目前Nacos已经通过CMDB拿到了一些IP的机房信息,且它们对应的标签信息如下:

11.11.11.11site: x1122.22.22.22site: x1233.33.33.33site: x1144.44.44.44site: x1255.55.55.55site: x13

11.11.11.11、22.22.22.22、33.33.33.33、44.44.44.44和55.55.55.55.55都包含了标签site,且它们对应的值分别为x11、x12、x11、x12、x13。我们先注册一个服务,下面挂载IP11.11.11.11和22.22.22.22。

1545035855381-5d9dcfad-75ab-43ad-a084-8ae4a65f914c.png

图3 服务详情

然后我们修改服务的“服务路由类型”,并配置为基于同site优先的服务路由:

1545035973200-497c0649-b652-4c36-bf6c-7cddfc5b75c6.png

图4 编辑服务路由类型

这里我们将服务路由类型选择为标签,然后输入标签的表达式:

CONSUMER.label.site = PROVIDER.label.site

这个表达式的格式和我们抽象的Selector机制有关,具体将会在另外一篇文章中介绍。在这里您需要记住的就是,任何一个如下格式的表达式:

CONSUMER.label.labelName = PROVIDER.label.labelName

将能够实现基于同labelName优先的负载均衡策略。

然后假设服务消费者的IP分别为33.33.33.33、44.44.44.44和55.55.55.55,它们在使用如下接口查询服务实例列表:

naming.selectInstances("nacos.test.1", true)

那么不同的消费者,将获取到不同的实例列表。33.33.33.33获取到11.11.11.11,44.44.44.44将获取到22.22.22.22,而55.55.55.55将同时获取到11.11.11.11和22.22.22.22。

以上,便是我们在Nacos中通过打通CMDB,实现就近访问的实践。Nacos是阿里巴巴开源的服务注册与配置管理产品,参考:《阿里启动新项目:Nacos,比 Eureka 更强!》。

本文原创首发于微信公众号:Java技术栈(id:javastack),关注公众号在后台回复 "架构" 可获取更多,转载请原样保留本信息。

转载于:https://www.cnblogs.com/javastack/p/10256401.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/395481.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我们分析了成千上万的编程访谈。 这就是我们学到的东西。

by Aline Lerner通过艾琳勒纳(Aline Lerner) 我们分析了成千上万的编程访谈。 这就是我们学到的东西。 (We analyzed thousands of coding interviews. Here’s what we learned.) Note: I wrote most of the words in this post, but the legendary Dave Holtz did the heavy…

Java 9 新功能之 HTTP2 和 REPL

对Java 9的炒作将不再局限于模块化&#xff08;modularity&#xff09;&#xff0c;Java 9正在搜罗大量额外的功能模块&#xff0c;这些功能模块正作为Java增强提案&#xff08;JEP&#xff09;提交&#xff0c;并在OpenJDK (Java SE的参考实现项目&#xff09;中实现。 在这篇…

c语言编译程序首要工作,c语言试卷

c语言试卷一、选择题(每小题1分&#xff0c;共40分)。(以下A、B、C、D四个选项中只有一个是正确的。)1&#xff0e;一个C语言程序是由()。A&#xff0e;一个主程序和若干子程序组成B&#xff0e;函数C&#xff0e;若干过程组成D&#xff0e;若干子程序组成2&#xff0e;C语言源…

Mac通过wifi连接 Android设备

公司用的全是mac开发&#xff0c;但是全是type-C接口&#xff0c;每次背电脑回家啊&#xff0c;还得带个数据线转换器…… 想着回来&#xff0c;直接通过Wi-Fi连接手机就好&#xff0c;发现完全忘了之前套路&#xff0c;现在赶紧记下一波&#xff0c;保证包教包会&#xff01; …

贝叶斯统计推断_统计推断对决:频繁主义者与贝叶斯主义者

贝叶斯统计推断by Kirill Dubovikov通过基里尔杜博维科夫(Kirill Dubovikov) 统计推断对决&#xff1a;频繁主义者与贝叶斯主义者 (Statistical Inference Showdown: The Frequentists VS The Bayesians) 推理 (Inference) Statistical Inference is a very important topic t…

iOS之由身份证号返回性别

该博文出自&#xff1a;http://www.cnblogs.com/yang-guang-girl/p/5683454.html - (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.NSString *sex[self sexStrFromIdentityCard:"139876456767892345"];NSLog("--s…

c语言程序设计k.r,【答题】C语言程序设计问题与解释实验

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼#include#define N 13main(){int y,m,D,q,t0,i,day0,a0,Day,n,k,O[N]{0,31,29,31,30,31,30,31,31,30,31,30,31},p[N]{0,31,28,31,30,31,30,31,31,30,31,30,31};//y是年&#xff0c;m是月&#xff0c;D是日&#xff0c;q计算周几&am…

运维命令

1 文件管理2 软件管理3 系统管理4 服务管理5 网络管理6 磁盘管理7 用户管理8 脚本相关9 服务配置----------------------------------1 文件管理----------------------------------创建空白文件touch不提示删除非空目录rm -rf 目录名(-r:递归删除-f 强制)####################…

[原创]K8_C段旁注工具6.0 新增SMB漏洞扫描

工具: K8_C段旁注工具6.0_0510[K.8]编译: 自己查壳组织: K8搞基大队[K8team]作者: K8拉登哥哥博客: http://qqhack8.blog.163.com发布: 2017/5/24 13:25:54简介: 图片: 功能: 更新历史:6.0 20170510[] C段SMB漏洞扫描(探测系统版本)[] 批量操作-文本比较提取新增内容[] 旁注查…

qt creator 快捷键

http://www.cnblogs.com/jingzhishen/p/4067657.html转载于:https://www.cnblogs.com/chencesc/p/5733858.html

栈的C语言案例,堆栈实例代码(C语言)

堆栈实例代码(C语言)如下所示&#xff1a;#include int MAXSIZE 8;int stack[8];int top -1;int isempty() {if(top -1)return 1;elsereturn 0;}int isfull() {if(top MAXSIZE)return 1;elsereturn 0;}int peek() {return stack[top];}int pop() {int data;if(!isempty()) …

从vue迁移到react_从AngularJS迁移到React-您如何衡量性能提升?

从vue迁移到reactby Gupta Garuda通过古普塔歌鲁达(Gupta Garuda) 从AngularJS迁移到React-您如何衡量性能提升&#xff1f; (Migrating from AngularJS to React — how do you measure your performance gains?) Are you looking into migrating a large AngularJS single …

【公告】社区周刊即日起停刊

各位订阅51CTO社区周刊的小伙伴们&#xff0c;大家好&#xff0c;我是51CTO社区的大管家蘑菇&#xff0c;今天来是想跟大家说&#xff0c;本期周刊将是我们最后一期邮件期刊&#xff0c;没错&#xff0c;是最后一期&#xff08;请珍惜它~&#xff09;。或许你会问&#xff0c;停…

springcloud-zuul路由网关

路由网关(zuul) 在微服务架构中&#xff0c;需要多个基础的服务治理组件&#xff0c;包括服务注册与发现、服务消费、负载均衡、断路器、智能 路由、配置管理等&#xff0c;由这个基础组件相互协作&#xff0c;共同组建了一个简单的微服务系统。一个简单的微服务系统如下 图 总…

python DB.fetchall()--获取数据库所有记录列表

查询到的数据格式为列表&#xff1a; 多个元素的列表&#xff1a; 单个元素的列表&#xff1a; 转载于:https://www.cnblogs.com/apple2016/p/5734161.html

c语言中文件读写面试题,在C ++中有效读取非常大的文本文件

我将对其进行重新设计以充当流式传输&#xff0c;而不是在一个块上。一个更简单的方法是&#xff1a;std::ifstream ifs("input.txt");std::vector parsed(std::istream_iterator(ifs), {});如果您大致知道期望多少个值&#xff0c;那么预先使用std::vector::reserve…

每次调试都必须clean_如何使用“ The Clean Architecture”每次编写健壮的应用程序...

每次调试都必须cleanby Daniel Oliveira丹尼尔奥利维拉(Daniel Oliveira) 如何使用“ The Clean Architecture”每次编写健壮的应用程序 (How to write robust apps every time, using “The Clean Architecture”) As developers, we can’t keep from using external librar…

404. Sum of Left Leaves

题目来源&#xff1a; 自我感觉难度/真实难度&#xff1a; 题意&#xff1a; 分析&#xff1a; 自己的代码&#xff1a; class Solution(object):def sumOfLeftLeaves(self, root):""":type root: TreeNode:rtype: int"""left[]if not root:retu…

Laravel Composer 命令大全

2019独角兽企业重金招聘Python工程师标准>>> ​​​​​​​1、安装 Laravel composer create-project --prefer-dist laravel/laravel 5.xx user-project 2、.env 文件操作 生成 APP_KEY&#xff1a;php artisan key:generate 缓存 .env 配置&#xff…

linux中initrd的含义,Linux2.6 内核的 Initrd 机制解析

1&#xff0e;什么是 Initrdinitrd 的英文含义是 boot loaderinitialized RAM disk&#xff0c;就是由 boot loader 初始化的内存盘。在 linux内核启动前&#xff0c; boot loader 会将存储介质中的 initrd 文件加载到内存&#xff0c;内核启动时会在访问真正的根文件系统前先访…