轉(zhuǎn):https://my.oschina.net/CraneHe/blog/703173
本系列七篇文章列表如下:
微服務(wù)實(shí)戰(zhàn)(一):微服務(wù)架構(gòu)的優(yōu)勢(shì)與不足
微服務(wù)實(shí)戰(zhàn)(二):使用API Gateway
微服務(wù)實(shí)戰(zhàn)(三):深入微服務(wù)架構(gòu)的進(jìn)程間通信
微服務(wù)實(shí)戰(zhàn)(四):服務(wù)發(fā)現(xiàn)的可行方案以及實(shí)踐案例
微服務(wù)實(shí)踐(五):微服務(wù)的事件驅(qū)動(dòng)數(shù)據(jù)管理
微服務(wù)實(shí)踐(六):選擇微服務(wù)部署策略
微服務(wù)實(shí)踐(七):從單體式架構(gòu)遷移到微服務(wù)架構(gòu)
這是關(guān)于使用微服務(wù)架構(gòu)創(chuàng)建應(yīng)用系列的第四篇文章。第一篇介紹了微服務(wù)架構(gòu)的模式粮彤,討論了使用微服務(wù)架構(gòu)的優(yōu)缺點(diǎn)沥阳。第二和第三篇描述了微服務(wù)架構(gòu)內(nèi)部的通訊機(jī)制。這篇文章中,我們將會(huì)探討服務(wù)發(fā)現(xiàn)相關(guān)問題份名。
為什么要使用服務(wù)發(fā)現(xiàn)?
設(shè)想一下菠赚,我們正在寫代碼使用了提供REST API或者Thrift API的服務(wù),為了完成一次服務(wù)請(qǐng)求抗愁,代碼需要知道服務(wù)實(shí)例的網(wǎng)絡(luò)位置(IP地址和端口)馁蒂。傳統(tǒng)應(yīng)用都運(yùn)行在物理硬件上,服務(wù)實(shí)例的網(wǎng)絡(luò)位置都是相對(duì)固定的蜘腌。例如沫屡,代碼可以從一個(gè)經(jīng)常變更的配置文件中讀取網(wǎng)絡(luò)位置。
而對(duì)于一個(gè)現(xiàn)代的撮珠,基于云微服務(wù)的應(yīng)用來說沮脖,這卻是一個(gè)很麻煩的問題。其架構(gòu)如圖所示:
服務(wù)實(shí)例的網(wǎng)絡(luò)位置都是動(dòng)態(tài)分配的芯急,而且因?yàn)閿U(kuò)展勺届、失效和升級(jí)等需求,服務(wù)實(shí)例會(huì)經(jīng)常動(dòng)態(tài)改變娶耍,因此免姿,客戶端代碼需要使用一種更加復(fù)雜的服務(wù)發(fā)現(xiàn)機(jī)制。
目前有兩大類服務(wù)發(fā)現(xiàn)模式:客戶端發(fā)現(xiàn)和服務(wù)端發(fā)現(xiàn)榕酒。
我們先來來討論一下客戶端發(fā)現(xiàn)胚膊。
客戶端發(fā)現(xiàn)模式
當(dāng)使用客戶端發(fā)現(xiàn)模式時(shí),客戶端負(fù)責(zé)決定相應(yīng)服務(wù)實(shí)例的網(wǎng)絡(luò)位置奈应,并且對(duì)請(qǐng)求實(shí)現(xiàn)負(fù)載均衡澜掩。客戶端從一個(gè)服務(wù)注冊(cè)服務(wù)中查詢杖挣,其中是所有可用服務(wù)實(shí)例的庫(kù)肩榕。客戶端使用負(fù)載均衡算法從多個(gè)服務(wù)實(shí)例中選擇出一個(gè)惩妇,然后發(fā)出請(qǐng)求株汉。
下圖顯示的是這種模式的架構(gòu)圖:
服務(wù)實(shí)例的網(wǎng)絡(luò)位置是在啟動(dòng)時(shí)注冊(cè)到服務(wù)注冊(cè)表中,并且在服務(wù)終止時(shí)從注冊(cè)表中刪除歌殃。服務(wù)實(shí)例注冊(cè)信息一般是使用心跳機(jī)制來定期刷新的乔妈。
Netflix OSS提供了一種非常棒的客戶端發(fā)現(xiàn)模式。Netflix Eureka是一個(gè)服務(wù)注冊(cè)表氓皱,為服務(wù)實(shí)例注冊(cè)管理和查詢可用實(shí)例提供了REST API接口路召。Netflix Ribbon是一種IPC客戶端勃刨,與Eureka合同工作實(shí)現(xiàn)對(duì)請(qǐng)求的負(fù)載均衡。我們會(huì)在后面詳細(xì)討論Eureka股淡。
客戶端發(fā)現(xiàn)模式也是優(yōu)缺點(diǎn)分明身隐。這種模式相對(duì)比較直接,而且除了服務(wù)注冊(cè)表唯灵,沒有其它改變的因素贾铝。除此之外,因?yàn)榭蛻舳酥揽捎梅?wù)注冊(cè)表信息埠帕,因此客戶端可以通過使用哈希一致性(hashing consistently)變得更加聰明垢揩,更加有效的負(fù)載均衡。
而這種模式一個(gè)最大的缺點(diǎn)是需要針對(duì)不同的編程語(yǔ)言注冊(cè)不同的服務(wù)敛瓷,在客戶端需要為每種語(yǔ)言開發(fā)不同的服務(wù)發(fā)現(xiàn)邏輯叁巨。
我們分析過客戶端發(fā)現(xiàn)后,再看看服務(wù)端發(fā)現(xiàn)琐驴。
服務(wù)端發(fā)現(xiàn)模式
另外一種服務(wù)發(fā)現(xiàn)的模式是服務(wù)端發(fā)現(xiàn)模式(server-side discovery pattern)俘种,下圖展現(xiàn)了這種模式的架構(gòu)圖:
客戶端通過負(fù)載均衡器向某個(gè)服務(wù)提出請(qǐng)求,負(fù)載均衡器向服務(wù)注冊(cè)表發(fā)出請(qǐng)求绝淡,將每個(gè)請(qǐng)求轉(zhuǎn)發(fā)往可用的服務(wù)實(shí)例。跟客戶端發(fā)現(xiàn)一樣苍姜,服務(wù)實(shí)例在服務(wù)注冊(cè)表中注冊(cè)或者注銷牢酵。
AWS Elastic Load Balancer(ELB)是一種服務(wù)端發(fā)現(xiàn)路由的例子,ELB一般用于均衡從網(wǎng)絡(luò)來的訪問流量衙猪,也可以使用ELB來均衡VPC內(nèi)部的流量馍乙。客戶端使用DNS垫释,通過ELB發(fā)出請(qǐng)求(HTTP或者TCP)丝格。ELB負(fù)載均衡器負(fù)責(zé)在注冊(cè)的EC2實(shí)例或者ECS容器之間均衡負(fù)載,并不存在一個(gè)分離的服務(wù)注冊(cè)表棵譬,而EC2實(shí)例和ECS實(shí)例也向ELB注冊(cè)显蝌。
HTTP服務(wù)和類似NGINX和NGINX Plus的負(fù)載均衡器都可以作為服務(wù)端發(fā)現(xiàn)均衡器。例如订咸,這篇博文就描述如何使用Consul Template來動(dòng)態(tài)配置NGINX反向代理曼尊。Consul Template是周期性從存放在Consul Template注冊(cè)表中配置數(shù)據(jù)重建配置文件的工具。當(dāng)文件發(fā)生變化時(shí)脏嚷,會(huì)運(yùn)行一個(gè)命令骆撇。在如上博客中,Consul Template產(chǎn)生了一個(gè)nginx.conf文件父叙,用于配置反向代理神郊,然后運(yùn)行一個(gè)命令肴裙,告訴NGINX重新調(diào)入配置文件。更復(fù)雜的例子可以用HTTP API或者DNS動(dòng)態(tài)重新配置NGINX Plus涌乳。
某些部署環(huán)境蜻懦,例如Kubernetes和Marathon在集群每個(gè)節(jié)點(diǎn)上運(yùn)行一個(gè)代理,此代理作為服務(wù)端發(fā)現(xiàn)負(fù)載均衡器爷怀。為了向服務(wù)發(fā)出請(qǐng)求阻肩,客戶端使用主機(jī)IP地址和分配的端口通過代理將請(qǐng)求路由出去。代理將次請(qǐng)求透明的轉(zhuǎn)發(fā)到集群中可用的服務(wù)實(shí)例运授。
服務(wù)端發(fā)現(xiàn)模式也有優(yōu)缺點(diǎn)烤惊。最大的優(yōu)點(diǎn)是客戶端無需關(guān)注發(fā)現(xiàn)的細(xì)節(jié),客戶端只需要簡(jiǎn)單的向負(fù)載均衡器發(fā)送請(qǐng)求吁朦,實(shí)際上減少了編程語(yǔ)言框架需要完成的發(fā)現(xiàn)邏輯柒室。而且,如上說所逗宜,某些部署環(huán)境免費(fèi)提供以上功能雄右。
這種模式也有缺陷,除非部署環(huán)境提供負(fù)載均衡器纺讲,否則負(fù)載均衡器是另外一個(gè)需要配置管理的高可用系統(tǒng)功能擂仍。
服務(wù)注冊(cè)表
服務(wù)注冊(cè)表是服務(wù)發(fā)現(xiàn)很重要的部分,它是包含服務(wù)實(shí)例網(wǎng)絡(luò)地址的數(shù)據(jù)庫(kù)熬甚。服務(wù)注冊(cè)表需要高可用而且隨時(shí)更新逢渔。客戶端可以緩存從服務(wù)注冊(cè)表獲得的網(wǎng)絡(luò)地址乡括。然而肃廓,這些信息最終會(huì)變得過時(shí),客戶端也無法發(fā)現(xiàn)服務(wù)實(shí)例诲泌。因此盲赊,服務(wù)注冊(cè)表由若干使用復(fù)制協(xié)議保持同步的服務(wù)器構(gòu)成。
如前所述敷扫,Netflix Eureka是一個(gè)服務(wù)注冊(cè)表很好地例子哀蘑,提供了REST API注冊(cè)和請(qǐng)求服務(wù)實(shí)例。 服務(wù)實(shí)例使用POST請(qǐng)求注冊(cè)網(wǎng)絡(luò)地址呻澜,每30秒必須使用PUT方法更新注冊(cè)表递礼,使用HTTP DELETE請(qǐng)求或者實(shí)例超時(shí)來注銷「遥可以想見脊髓,客戶端可以使用HTTP GET請(qǐng)求接受注冊(cè)服務(wù)實(shí)例信息。
Netflix通過在每個(gè)AWS EC2域運(yùn)行一個(gè)或者多個(gè)Eureka服務(wù)實(shí)現(xiàn)高可用性栅受,每個(gè)Eureka服務(wù)器都運(yùn)行在擁有彈性IP地址的EC2實(shí)例上将硝。DNS TEXT記錄用于存儲(chǔ)Eureka集群配置恭朗,其中存放從可用域到一系列Eureka服務(wù)器網(wǎng)絡(luò)地址的列表。當(dāng)Eureka服務(wù)啟動(dòng)時(shí)依疼,向DNS請(qǐng)求接受Eureka集群配置痰腮,確認(rèn)同伴位置,給自己分配一個(gè)未被使用的彈性IP地址律罢。
Eureka客戶端—服務(wù)和服務(wù)客戶端—向DNS請(qǐng)求發(fā)現(xiàn)Eureka服務(wù)的網(wǎng)絡(luò)地址膀值,客戶端首選使用同一域內(nèi)的服務(wù)。然而误辑,如果沒有可用服務(wù)沧踏,客戶端會(huì)使用另外一個(gè)可用域的Eureka服務(wù)。
另外一些服務(wù)注冊(cè)表例子包括:
-
– 是一個(gè)高可用巾钉,分布式的翘狱,一致性的,鍵值表砰苍,用于共享配置和服務(wù)發(fā)現(xiàn)潦匈。兩個(gè)著名案例包括Kubernetes和Cloud Foundry。
-
– 是一個(gè)用于發(fā)現(xiàn)和配置的服務(wù)赚导。提供了一個(gè)API允許客戶端注冊(cè)和發(fā)現(xiàn)服務(wù)茬缩。Consul可以用于健康檢查來判斷服務(wù)可用性。
-
– 是一個(gè)廣泛使用吼旧,為分布式應(yīng)用提供高性能整合的服務(wù)寒屯。Apache ZooKeeper最初是Hadoop的子項(xiàng)目,現(xiàn)在已經(jīng)變成頂級(jí)項(xiàng)目黍少。
另外,前面強(qiáng)調(diào)過处面,某些系統(tǒng)厂置,例如Kubernetes、Marathon和AWS并沒有獨(dú)立的服務(wù)注冊(cè)表魂角,對(duì)他們來說昵济,服務(wù)注冊(cè)表只是一個(gè)內(nèi)置的功能。
現(xiàn)在我們來看看服務(wù)注冊(cè)表的概念野揪,看看服務(wù)實(shí)例是如何在注冊(cè)表中注冊(cè)的访忿。
服務(wù)注冊(cè)選項(xiàng)
如前所述,服務(wù)實(shí)例必須向注冊(cè)表中注冊(cè)和注銷斯稳,如何注冊(cè)和注銷也有一些不同的方式海铆。一種方式是服務(wù)實(shí)例自己注冊(cè),也叫自注冊(cè)模式(self-registration pattern)挣惰;另外一種方式是為其它系統(tǒng)提供服務(wù)實(shí)例管理的卧斟,也叫第三方注冊(cè)模式(third party registration pattern)殴边。我們來看看自注冊(cè)模式。
自注冊(cè)方式
當(dāng)使用自注冊(cè)模式時(shí)珍语,服務(wù)實(shí)例負(fù)責(zé)在服務(wù)注冊(cè)表中注冊(cè)和注銷锤岸。另外,如果需要的話板乙,一個(gè)服務(wù)實(shí)例也要發(fā)送心跳來保證注冊(cè)信息不會(huì)過時(shí)是偷。下圖描述了這種架構(gòu):
一個(gè)很好地例子是 Netflix OSS Eureka client。Eureka客戶端負(fù)責(zé)處理服務(wù)實(shí)例的注冊(cè)和注銷募逞。Spring Cloud project蛋铆,實(shí)現(xiàn)了多種模式,包括服務(wù)發(fā)現(xiàn)凡辱,使得向Eureka服務(wù)實(shí)例自動(dòng)注冊(cè)時(shí)更容易戒职。可以用@EnableEurekaClient注釋Java配置類透乾。
自注冊(cè)模式也有優(yōu)缺點(diǎn)洪燥。一個(gè)優(yōu)點(diǎn)是,相對(duì)簡(jiǎn)單乳乌,不需要其他系統(tǒng)功能捧韵。而一個(gè)主要缺點(diǎn)則是,把服務(wù)實(shí)例跟服務(wù)注冊(cè)表聯(lián)系起來汉操。必須在每種編程語(yǔ)言和框架內(nèi)部實(shí)現(xiàn)注冊(cè)代碼再来。
另外一個(gè)方法,不需要連接服務(wù)和注冊(cè)表磷瘤,則是第三方注冊(cè)模式芒篷。
第三方注冊(cè)模式
當(dāng)使用第三方注冊(cè)模式時(shí),服務(wù)實(shí)例并不負(fù)責(zé)向服務(wù)注冊(cè)表注冊(cè)采缚,而是由另外一個(gè)系統(tǒng)模塊针炉,叫做服務(wù)管理器,負(fù)責(zé)注冊(cè)扳抽。服務(wù)管理器通過查詢部署環(huán)境或訂閱事件來跟蹤運(yùn)行服務(wù)的改變篡帕。當(dāng)管理器發(fā)現(xiàn)一個(gè)新可用服務(wù),會(huì)向注冊(cè)表注冊(cè)此服務(wù)贸呢。服務(wù)管理器也負(fù)責(zé)注銷終止的服務(wù)實(shí)例镰烧。下圖是這種模式的架構(gòu)圖。
一個(gè)服務(wù)管理器的例子是開源項(xiàng)目Registrator楞陷,負(fù)責(zé)自動(dòng)注冊(cè)和注銷被部署為Docker容器的服務(wù)實(shí)例怔鳖。Reistrator支持多種服務(wù)管理器,包括etcd和Consul猜谚。
另外一個(gè)服務(wù)管理器例子是NetflixOSS Prana败砂,主要面向非JVM語(yǔ)言開發(fā)的服務(wù)赌渣,也稱為附帶應(yīng)用(sidecar application),Prana使用Netflix Eureka注冊(cè)和注銷服務(wù)實(shí)例昌犹。
服務(wù)管理器是部署環(huán)境內(nèi)置的模塊坚芜。有自動(dòng)擴(kuò)充組創(chuàng)建的EC2實(shí)例可以自向ELB自動(dòng)注冊(cè),Kubernetes服務(wù)自動(dòng)注冊(cè)并且對(duì)發(fā)現(xiàn)服務(wù)可用斜姥。
第三方注冊(cè)模式也是優(yōu)缺點(diǎn)都有鸿竖。主要的優(yōu)點(diǎn)是服務(wù)跟服務(wù)注冊(cè)表是分離的,不需要為每種編程語(yǔ)言和架構(gòu)完成服務(wù)注冊(cè)邏輯铸敏,替代的缚忧,服務(wù)實(shí)例是通過一個(gè)集中化管理的服務(wù)進(jìn)行管理的。
一個(gè)缺點(diǎn)是杈笔,除非這種服務(wù)被內(nèi)置于部署環(huán)境中闪水,否則也需要配置管理一個(gè)高可用的系統(tǒng)。
在一個(gè)微服務(wù)應(yīng)用中蒙具,服務(wù)實(shí)例運(yùn)行環(huán)境是動(dòng)態(tài)變化的球榆。實(shí)例網(wǎng)絡(luò)地址也是動(dòng)態(tài)變化的,因此禁筏,客戶端為了訪問服務(wù)必須使用服務(wù)發(fā)現(xiàn)機(jī)制持钉。
服務(wù)發(fā)現(xiàn)關(guān)鍵部分是服務(wù)注冊(cè)表,也就是可用服務(wù)實(shí)例的數(shù)據(jù)庫(kù)篱昔。服務(wù)注冊(cè)表提供一種注冊(cè)管理API和請(qǐng)求API每强。服務(wù)實(shí)例使用注冊(cè)管理API來實(shí)現(xiàn)注冊(cè)和注銷。
請(qǐng)求API用于發(fā)現(xiàn)可用服務(wù)實(shí)例州刽,相對(duì)應(yīng)的空执,有兩種主要服務(wù)發(fā)現(xiàn)模式:客戶端發(fā)現(xiàn)和服務(wù)端發(fā)現(xiàn)。
在使用客戶端發(fā)現(xiàn)的系統(tǒng)中穗椅,客戶端向服務(wù)注冊(cè)表發(fā)起請(qǐng)求脆烟,選擇可用實(shí)例,然后發(fā)出服務(wù)請(qǐng)求
而在使用服務(wù)端發(fā)現(xiàn)的系統(tǒng)中房待,客戶端通過路由轉(zhuǎn)發(fā)請(qǐng)求,路由器向服務(wù)注冊(cè)表發(fā)出請(qǐng)求驼抹,轉(zhuǎn)發(fā)此請(qǐng)求到某個(gè)可用實(shí)例桑孩。
服務(wù)實(shí)例注冊(cè)和注銷主要有兩類方式。一種是服務(wù)實(shí)例自動(dòng)注冊(cè)到服務(wù)注冊(cè)表中框冀,也就是自注冊(cè)模式流椒;另外一種則是某個(gè)系統(tǒng)模塊負(fù)責(zé)處理注冊(cè)和注銷,也就是第三方注冊(cè)模式明也。
在某些部署環(huán)境中宣虾,需要配置自己的服務(wù)發(fā)現(xiàn)架構(gòu)惯裕,例如:Netflix Eureka、etcd或者Apache ZooKeeper绣硝。而在另外一些部署環(huán)境中蜻势,則自帶了這種功能,例如Kubernetes和Marathon 負(fù)責(zé)處理服務(wù)實(shí)例的注冊(cè)和注銷鹉胖。他們也在每個(gè)集群節(jié)點(diǎn)上運(yùn)行代理握玛,來實(shí)現(xiàn)服務(wù)端發(fā)現(xiàn)路由器的功能。
HTTP反向代理和負(fù)載據(jù)衡器(例如NGINX)可以用于服務(wù)發(fā)現(xiàn)負(fù)載均衡器甫菠。服務(wù)注冊(cè)表可以將路由信息推送到NGINX挠铲,激活一個(gè)實(shí)時(shí)配置更新;例如寂诱,可以使用 Consul Template拂苹。NGINX Plus 支持額外的動(dòng)態(tài)重新配置機(jī)制,可以使用DNS痰洒,將服務(wù)實(shí)例信息從注冊(cè)表中拉下來瓢棒,并且提供遠(yuǎn)程配置的API。
在未來的博客中带迟,我們還將深入探討微服務(wù)其它特點(diǎn)音羞。可以注冊(cè)NGINX郵件列表來獲得最新產(chǎn)品更新提示仓犬。
原文地址:https://www.nginx.com/blog/service-discovery-in-a-microservices-architecture/