阿里巴巴是如何打通 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.pswp.cn/news/395481.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/395481.shtml
英文地址,請注明出處:http://en.pswp.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;內核啟動時會在訪問真正的根文件系統前先訪…