Netflix OSS是一組框架和庫,Netflix為大規(guī)模解決一些有趣的分布式系統(tǒng)問題而編寫的懂版。今天鹃栽,對于Java開發(fā)人員來說,它非常適合云環(huán)境中開發(fā)微服務(wù)躯畴。服務(wù)發(fā)現(xiàn)民鼓、負(fù)載平衡、容錯(cuò)等模式對于可擴(kuò)展的分布式系統(tǒng)來說是非常重要的概念蓬抄,Netflix為此提供了很好的解決方案丰嘉。
無論如何,很多Netflix OSS都是在AWS云上運(yùn)行的時(shí)候編寫的嚷缭,沒有其他選擇饮亏。許多假設(shè)都被移植到了Netflix庫中,這些庫可能不再適用于當(dāng)前運(yùn)行的位置(如Linux容器等)。隨著Linux容器克滴、Docker逼争、容器管理系統(tǒng)等的出現(xiàn),我們開始看到在Linux容器中(在云中劝赔、在私有云中誓焦,兩者中)運(yùn)行我們的微服務(wù)有很多價(jià)值。此外着帽,因?yàn)槲覀儾恢廊萜魃戏?wù)的運(yùn)行方式杂伟,我們往往不太關(guān)心哪種技術(shù)真正的在其中運(yùn)行(它是Java嗎?是node.js嗎仍翰?它是Go赫粥?),Netflix OSS主要面向Java開發(fā)人員予借。它們是需要包含在Java應(yīng)用程序/服務(wù)代碼中的庫/框架/配置集越平。
因此,我們得出第1點(diǎn)灵迫。
微服務(wù)可以在各種框架/語言中實(shí)現(xiàn)秦叛,但服務(wù)發(fā)現(xiàn)、負(fù)載平衡瀑粥、容錯(cuò)等仍然非常重要挣跋。如果我們在容器中運(yùn)行這些服務(wù),我們可以利用功能強(qiáng)大的與語言無關(guān)的基礎(chǔ)架構(gòu)來執(zhí)行如構(gòu)建狞换、打包避咆、部署、運(yùn)行狀況檢查修噪、滾動升級查库、安全性等操作。例如黄琼,openshift是一種Kubernetes的服務(wù)膨报,它考慮到了企業(yè)側(cè)需求,它為您做了所有這些事情:在應(yīng)用層中适荣,您不需要強(qiáng)制任何人來了解或關(guān)心這些事情现柠。讓你的應(yīng)用程序和服務(wù)保持簡單!
那么基礎(chǔ)設(shè)施能否幫助提供服務(wù)發(fā)現(xiàn)弛矛,負(fù)載平衡和容錯(cuò)够吩?為什么這應(yīng)該是應(yīng)用程序級別的東西?
如果您使用kubernetes丈氓,答案是:是周循。
服務(wù)發(fā)現(xiàn)Kubernetes方式
使用Netflix OSS强法,您通常需要設(shè)置一個(gè)服務(wù)發(fā)現(xiàn)服務(wù)器,該服務(wù)器充當(dāng)端點(diǎn)的注冊表湾笛,這些端點(diǎn)可以通過各種客戶端發(fā)現(xiàn)饮怯。例如,您可能使用Netflix功能與其他服務(wù)進(jìn)行通信嚎研,并需要發(fā)現(xiàn)它們運(yùn)行的位置蓖墅。服務(wù)可以被取消,我們可以向集群添加更多的服務(wù)來幫助擴(kuò)展临扮。這個(gè)中央服務(wù)發(fā)現(xiàn)注冊表跟蹤集群中可用的服務(wù)论矾。
其中一個(gè)問題是:作為開發(fā)人員,您需要執(zhí)行以下操作:
- 決定我是否需要AP系統(tǒng)(Consul杆勇、Eureka等)還是一個(gè)CP系統(tǒng)(ZooKeeper贪壳、etcd等)
- 了解如何大規(guī)模上運(yùn)行、管理和監(jiān)控這些系統(tǒng)(這不是一個(gè)簡單的PET項(xiàng)目)
此外蚜退,您需要為所使用的編程語言找到客戶端闰靴,以便了解如何與服務(wù)發(fā)現(xiàn)機(jī)制對話。正如我們已經(jīng)說過的钻注,微服務(wù)可以在許多不同類型的語言中實(shí)現(xiàn)传黄,所以一個(gè)完美的Java客戶端可能是可用的,但是如果GO或NoDEJS客戶端不存在队寇,你必須自己編寫。語言和開發(fā)人員的每一種排列都可能以他們自己對如何實(shí)現(xiàn)這種客戶機(jī)的想法而告終章姓,而現(xiàn)在佳遣,您不得不維護(hù)多個(gè)客戶端,這些客戶端試圖做相同的事情凡伊,但語義上可能不同零渐。或者每種語言都使用自己的服務(wù)發(fā)現(xiàn)服務(wù)器系忙?那么诵盼,現(xiàn)在您是否按語言類型管理和維護(hù)服務(wù)發(fā)現(xiàn)服務(wù)器的基礎(chǔ)結(jié)構(gòu)?不管怎樣……有點(diǎn)小麻煩银还。
只使用DNS怎么辦?
好吧风宁,這就解決了我們的客戶端庫問題,對吧蛹疯?DNS可以融入到任何使用TCP/UDP的系統(tǒng)中戒财,無論您在任何地方部署內(nèi)部部署、云捺弦、容器饮寞、Windows孝扛、Solaris等,都可以隨時(shí)使用DNS幽崩。您的客戶端只指向一個(gè)域名(即http://awsomefooservice/)苦始,基礎(chǔ)設(shè)施知道如何路由到DNS指向的服務(wù)(可以是帶負(fù)載平衡器的)。哎呀慌申!現(xiàn)在我們不需要弄清楚需要使用什么客戶端來發(fā)現(xiàn)服務(wù)陌选,我只需要使用我想要的任何TCP客戶機(jī)。我也不需要弄清楚如何管理一個(gè)DNS集群太示,它已經(jīng)融入到網(wǎng)絡(luò)路由器中柠贤。
Kubernetes服務(wù)
我們就用Kubernetes。無論如何类缤,我們將在docker/linux容器中運(yùn)行臼勉,而kubernetes是運(yùn)行docker容器的最佳方案。
有了kubernetes餐弱,我們只需創(chuàng)建和使用kubernetes服務(wù)宴霸,就完成了!我們不必浪費(fèi)時(shí)間設(shè)置發(fā)現(xiàn)服務(wù)器膏蚓、編寫自定義客戶端瓢谢、使用DNS等。我們將繼續(xù)討論提供業(yè)務(wù)價(jià)值的微服務(wù)的下一個(gè)部分驮瞧。
如何工作的呢
下面是Kubernetes為實(shí)現(xiàn)這一點(diǎn)而帶來的簡單抽象:
- Pods
- 標(biāo)簽/標(biāo)簽選擇器
- 服務(wù)
Pods很簡單氓扛。它們基本上就是您的Linux容器。標(biāo)簽很簡單论笔。它們基本上是鍵值字符串采郎,可以用來標(biāo)記您的pod(例如,pod有標(biāo)簽app=cassandra狂魔、tier=backend蒜埋、version=1.0,language=java)最楷。這些標(biāo)簽可以是你心中想要的任何東西整份。
最后一個(gè)概念是服務(wù)。也很簡單籽孙。服務(wù)是固定的群集IP地址烈评。這個(gè)IP地址是一個(gè)虛擬IP地址,可以用來發(fā)現(xiàn)/調(diào)用pods/容器中的實(shí)際端點(diǎn)犯建。這個(gè)IP地址如何知道哪些pods/容器有資格被發(fā)現(xiàn)础倍?它使用一個(gè)標(biāo)簽選擇器來選擇具有您定義的標(biāo)簽的pods。例如胎挎,假設(shè)我們想要一個(gè)Kubernetes服務(wù)沟启,其選擇器為“app = cassandra AND tier = backend”忆家。這將為我提供一個(gè)帶有虛擬IP的服務(wù),它可以發(fā)現(xiàn)任何與該標(biāo)簽匹配的pods(同時(shí)具有app=cassandra和tier=backend)德迹。此選擇器被主動評估芽卿,以便離開集群的任何pods或加入集群的任何pods(基于它們擁有的標(biāo)簽)都將自動開始參與服務(wù)發(fā)現(xiàn)。
使用Kubernetes服務(wù)選擇與服務(wù)相關(guān)的容器的另一個(gè)好處是胳搞,Kubernetes很聰明哪個(gè)容器屬于哪個(gè)服務(wù)和健康狀況卸例。Kubernetes可以使用內(nèi)置的活躍性和健康檢查來確定是否應(yīng)該根據(jù)特定服務(wù)的活動和/或正常運(yùn)行,將pod包含在pod的集群中肌毅。
注意筷转,kubernetes服務(wù)的一個(gè)實(shí)例不是一個(gè)“東西”,也不是一個(gè)設(shè)備悬而,或者一個(gè)docker容器呜舒,或者任何東西……它是一個(gè)虛擬的“東西”…所以沒有單一的故障點(diǎn)。
對于開發(fā)人員來說笨奠,這是非常強(qiáng)大和簡單的∠龋現(xiàn)在,一個(gè)希望使用Cassandra后端的應(yīng)用程序只使用這個(gè)固定的IP地址與Cassandra數(shù)據(jù)庫通信般婆。但是硬編碼一個(gè)固定的IP通常不是一個(gè)好辦法到腥,因?yàn)槿绻阆氚涯愕膽?yīng)用程序/服務(wù)轉(zhuǎn)移到一個(gè)不同的環(huán)境(如QA、Prod等)∥蹬郏現(xiàn)在您必須更改那個(gè)IP(或注入一些配置)乡范,現(xiàn)在您已經(jīng)增加了配置負(fù)擔(dān)。所以我們只使用dns:)
在Kubernetes中使用集群DNS是正確的答案啤咽。由于IP是為給定環(huán)境(dev晋辆、QA等)固定的,所以我們不關(guān)心緩存它:它永遠(yuǎn)不會改變∪虿希現(xiàn)在,如果我們使用DNS连舍,我們的應(yīng)用程序可以配置為在http://awsomefooseservice/上與服務(wù)通信没陡,即使我們從dev到QA再到prod,到目前為止索赏,我們在每個(gè)環(huán)境中都有這些kubernetes服務(wù)盼玄,我們的應(yīng)用程序不需要更改。
我們不需要額外的配置潜腻,也不需要擔(dān)心DNS緩存/SRV記錄埃儿、自定義庫客戶端和管理其他的服務(wù)發(fā)現(xiàn)基礎(chǔ)結(jié)構(gòu)。pods現(xiàn)在可以添加到集群(或從集群中取出)融涣,kubernetes服務(wù)的標(biāo)簽選擇器將根據(jù)標(biāo)簽主動對集群進(jìn)行分組童番。你的應(yīng)用程序只與http://aWeMESFoService通信精钮,無論你是Java應(yīng)用程序、Python剃斧、NoDE.JS轨香、Perl、Go幼东、.NET臂容、Ruby、C++根蟹、Scala脓杉、Groovy,等等简逮。這個(gè)服務(wù)發(fā)現(xiàn)機(jī)制不強(qiáng)制使用特定的客戶端球散。
服務(wù)發(fā)現(xiàn)變得簡單多了。
這個(gè)很有趣买决。Netflix編寫了Eureka和Ribbon沛婴,通過這些組合,您可以啟用客戶端負(fù)載平衡督赤∴业疲基本上,服務(wù)注冊中心(eureka/consul/zookeeper/etc)會跟蹤集群中存在哪些服務(wù)躲舌,并將這些數(shù)據(jù)發(fā)送給對此感興趣的客戶端丑婿。然后,由于客戶機(jī)具有集群中節(jié)點(diǎn)的信息没卸,所以它可以選擇一個(gè)節(jié)點(diǎn)(隨機(jī)羹奉、粘性或一些自定義算法),然后調(diào)用它约计。在下一個(gè)調(diào)用中诀拭,如果需要,它可以在集群中選擇不同的服務(wù)煤蚌。這里的優(yōu)點(diǎn)是我們不需要物理/軟件負(fù)載平衡器耕挨,這可能很快就會成為瓶頸。另一個(gè)重要方面:由于客戶機(jī)知道服務(wù)在哪里尉桩,客戶機(jī)可以直接聯(lián)系服務(wù)提供商筒占,而不需要額外的跳轉(zhuǎn)。
客戶端負(fù)載平衡是5%的用例蜘犁。讓我解釋一下翰苫。
我們想要的是一種在沒有任何附加設(shè)備和客戶端庫的情況下實(shí)現(xiàn)可擴(kuò)展負(fù)載平衡的理想方法。在大多數(shù)情況下,我們可能不關(guān)心中間有負(fù)載均衡器的額外跳轉(zhuǎn)(想想看..可能99%的應(yīng)用程序都是以這種方式部署的)奏窑。我們可能會遇到這樣一種情況导披,即服務(wù)A的呼叫服務(wù)B,它呼叫服務(wù)C良哲、D和E盛卡,然后您就可以看到結(jié)果了。在這種情況下筑凫,如果每個(gè)人多跳轉(zhuǎn)一次滑沧,我們會產(chǎn)生很多額外的延遲。所以一個(gè)可能的解決方案是“去掉多余的跳轉(zhuǎn)”巍实。它是……但不僅僅是在跳轉(zhuǎn)中加載平衡程序:更多了您必須對下游服務(wù)進(jìn)行的調(diào)用數(shù)量:)滓技。
使用Kubernetes服務(wù),正如我們在上面的服務(wù)發(fā)現(xiàn)部分所做的那樣棚潦,我們實(shí)現(xiàn)了正確的負(fù)載平衡(同樣令漂,沒有服務(wù)注冊表、自定義客戶端丸边、DNS缺點(diǎn)等的所有開銷)叠必。當(dāng)我們通過其DNS(或IP)與kubernetes服務(wù)交互時(shí),kubernetes將默認(rèn)地在集群中的pods之間實(shí)現(xiàn)負(fù)載平衡(記住妹窖,集群是由標(biāo)簽和標(biāo)簽選擇器定義的)纬朝。如果您不希望在負(fù)載平衡中有額外的跳轉(zhuǎn),不用擔(dān)心骄呼;這個(gè)虛擬IP直接路由到pods共苛,它不會影響物理網(wǎng)絡(luò)。
哎呀蜓萄!對于95%的用例來說很容易隅茎。很有可能,你在95%的用例分布中嫉沽,所以不需要過度設(shè)計(jì)辟犀。
那5%的情況怎么樣?您可能遇到這樣的情況:您必須在運(yùn)行時(shí)做出一些業(yè)務(wù)決策绸硕,確定您真正要調(diào)用的集群中的哪個(gè)確切的后端端點(diǎn)堂竟。基本上臣咖,您需要使用一些比“循環(huán)”跃捣、“隨機(jī)”漱牵、“粘性會話”更復(fù)雜的自定義算法夺蛇,并且這些算法是特定于您的應(yīng)用程序的。為此酣胀,請使用客戶端負(fù)載平衡刁赦。在這個(gè)模型中娶聘,您仍然可以利用Kubernetes的服務(wù)發(fā)現(xiàn)來找出集群中的哪些pod,然后使用您自己的代碼來決定直接調(diào)用哪個(gè)pod(基于標(biāo)簽等)甚脉。對于其他語言也可以這樣做丸升,只需使用kubernetes rest API查詢pods等。對于這些用例牺氨,更合適的方法是將這個(gè)自定義邏輯分解成自己的模塊狡耻,這樣它的依賴關(guān)系就與應(yīng)用程序分離了。使用kubernetes猴凹,您可以將這個(gè)單獨(dú)的模塊部署為應(yīng)用程序/服務(wù)夷狰,并在那里保留定制的負(fù)載平衡邏輯。
這是5%的用例郊霎,并帶來了額外的復(fù)雜性沼头。對于95%的用例,只需使用內(nèi)置的內(nèi)容而無需任何特定于語言的特定客戶端书劝。
容錯(cuò)怎么樣呢进倍?
具有依賴性的系統(tǒng)應(yīng)該始終考慮到promises。這意味著购对,即使依賴系統(tǒng)不可用或崩潰的情況下猾昆,他們也應(yīng)該始終知道他們的義務(wù)是什么。我們應(yīng)該問Kubernetes它在容錯(cuò)方面有什么作用嗎洞斯?
好吧毡庆,Kubernetes確實(shí)有自我修復(fù)能力。如果一個(gè)pod中的pod或容器出現(xiàn)故障烙如,
Kubernetes可以將其恢復(fù)以維護(hù)其ReplicaSet不變量(基本上么抗,如果你告訴Kubernetes我想要10個(gè)“foo”的pod,它總是會嘗試保持該狀態(tài))亚铁。
自我修復(fù)的基礎(chǔ)設(shè)施是非常棒的蝇刀,它與Kubernetes一起推出,但是我們對這個(gè)討論感興趣的是徘溢,當(dāng)應(yīng)用程序的依賴關(guān)系(數(shù)據(jù)庫吞琐、其他服務(wù)等)失效時(shí),它會發(fā)生什么然爆?好吧站粟,這取決于應(yīng)用程序如何處理。例如曾雕,在Netflix奴烙,如果您嘗試觀看特定的電影,則會向“授權(quán)”服務(wù)發(fā)出服務(wù)呼叫,該服務(wù)知道您在觀看電影時(shí)擁有哪些特權(quán)切诀。如果服務(wù)中斷揩环,我們應(yīng)該阻止用戶觀看那部電影嗎?我們應(yīng)該顯示異常堆棧跟蹤嗎幅虑?Netflix的方法就是讓用戶看電影丰滑。
我們想要的是尋找其他方法來履行我們對服務(wù)合同的承諾。Netflix HySrx是Java開發(fā)人員的一個(gè)很好的解決方案倒庵。Netflix Hystrix實(shí)現(xiàn)了一種方法來執(zhí)行“Bulkheading”褒墨、“Circuit Breaking”和“Fallbacks”。其中每一個(gè)都是特定于應(yīng)用程序的命令擎宝,因此在本例中貌亭,為不同的語言提供特定的客戶端庫是合理的。
Kubernetes可以幫助解決這個(gè)問題嗎认臊?是!
再次圃庭,看一下很棒的Kubeflix項(xiàng)目,您可以使用Netflix Turbine項(xiàng)目來聚合和可視化集群中運(yùn)行的所有斷路器失晴。Hystrix可以將服務(wù)器端事件公開為可由Turbine使用的流剧腻。但Turbine如何發(fā)現(xiàn)哪些pods中有hystrix?)我們可以使用Kubernetes標(biāo)簽涂屁。如果我們標(biāo)記使用Hystrix的標(biāo)簽為hystrix.enabled=true那么Kubeflix可以自動發(fā)現(xiàn)每個(gè)hystrix斷路器的SSE流并將其顯示在Turbine網(wǎng)頁上书在。
配置怎樣呢?
Netflix Archius是為處理云中服務(wù)的分布式配置管理而編寫的拆又。要做到這一點(diǎn)儒旬,就像使用Eureka和Ribbon一樣,您可以設(shè)置配置服務(wù)器并使用Java庫查找配置值帖族。它還支持動態(tài)配置更改等(請記住栈源,Netflix是為AWS構(gòu)建的)。他們是Netflix竖般;作為他們的CI/CD管道的一部分甚垦,他們將構(gòu)建AMI并部署它們。在大多數(shù)情況下涣雕,構(gòu)建AMI或任何虛擬機(jī)鏡像都是耗時(shí)的艰亮,并且有很多不必要的開銷……使用docker/linux容器,事情會更加靈活挣郭,正如我將從配置的角度解釋的那樣)迄埃。
那95%的用例呢?我們希望將特定于環(huán)境的配置(這是一個(gè)重要的區(qū)別……不是每個(gè)配置都是特定于環(huán)境的配置兑障,需要根據(jù)我們運(yùn)行的環(huán)境進(jìn)行更改)存儲在應(yīng)用程序外部侄非,并根據(jù)我們運(yùn)行的環(huán)境(dev伶棒、qa、prod等)將其注入彩库。但是,我們確實(shí)希望有一種語言無關(guān)的方式來查找配置先蒋,而不是強(qiáng)迫每個(gè)人使用Java和/或使用其他Java庫將其類路徑復(fù)雜化以進(jìn)行配置骇钦。
在Kubernetes中,我們有三種用于注入基于環(huán)境的配置的構(gòu)造竞漾。
環(huán)境變量
Gitrepo卷
配置映射
基本上眯搭,我們可以通過環(huán)境變量(Java、NodeJS业岁、GO鳞仙、Ruby、Python等可以輕松讀缺适薄)向Linux容器注入配置數(shù)據(jù)棍好,大多數(shù)語言都可以讀取這些配置數(shù)據(jù)。我們可以將配置存儲在Git中(這是一個(gè)好主意)允耿,并且可以將配置報(bào)告直接綁定到POD(作為文件系統(tǒng)上的文件)借笙,然后使用任何框架工具來使用應(yīng)用程序配置文件。最后较锡,我們可以使用kubernetes configmap將我們的版本化配置存儲到configmap中业稼,然后將其作為文件系統(tǒng)裝載到pod中,從而稍微分離git repo蚂蕴。同樣低散,您使用配置文件的方式與使用來自文件系統(tǒng)的任何配置文件的方式相同,它們使用您各自的語言/框架骡楼。
那5%的用例呢熔号?
在5%的用例中,您可能希望在運(yùn)行時(shí)動態(tài)更改配置鸟整。Kubernetes對此有所幫助跨嘉。您可以在configmap中更改配置文件,并將這些更改動態(tài)地應(yīng)用到裝載它們的pods中吃嘿。在這種情況下祠乃,您需要有一個(gè)客戶端庫,它能夠檢測這些配置更改并將它們公開給您的應(yīng)用程序兑燥。Netflix Archais有一個(gè)客戶機(jī)可以做到這一點(diǎn)亮瓷。Java的Spring Cube KubNETes使Kubernetes更容易做到這一點(diǎn)。
那么Spring Cloud呢降瞳?
使用Spring開發(fā)微服務(wù)的Java用戶通常把Spring Cloud與Netflix OSS等同起來嘱支,因?yàn)楹芏喽际腔贜etflix OSS的蚓胸。
如果您正在研究構(gòu)建微服務(wù),并且已經(jīng)傾向于使用Netflix OSS/Java/Spring/Spring Cloud除师,請注意沛膳,您不是Netflix,您不必直接使用AWS EC2原語汛聚,并通過這樣做使應(yīng)用程序復(fù)雜化锹安。如果您希望使用Docker,那么采用Kubernetes是一個(gè)明智的選擇倚舀,它附帶了許多現(xiàn)成的“分布式系統(tǒng)特性”叹哭。在需要的地方分層,并從一開始就避免過度復(fù)雜化服務(wù)痕貌,因?yàn)镹etflix五年前就提出了這種方法(因?yàn)樗麄儽仨氝@樣做风罩!我敢打賭,如果他們5年前發(fā)現(xiàn)有Kubernetes舵稠,他們的Netflix OSS堆棾看起來會大不一樣!)哺徊。