- Service Mesh實(shí)戰(zhàn):用Istio軟負(fù)載實(shí)現(xiàn)服務(wù)網(wǎng)格
- 周遙
- 165字
- 2019-07-29 18:22:34
1.3 服務(wù)化時(shí)期
1.3.1 應(yīng)用到服務(wù)
重復(fù)建設(shè)在軟件工程思想中向來(lái)就是不可取的,工程師們?cè)O(shè)想將共同的功能組件抽象出來(lái),形成獨(dú)立的“應(yīng)用”,不過(guò)這里的關(guān)鍵問(wèn)題就是這些“應(yīng)用”沒(méi)有直觀上的入口,因此用傳統(tǒng)的思想來(lái)定義并不妥。為此工程師們想出了“服務(wù)(Service)”一詞來(lái)描述這種功能性的組件,它們?yōu)閼?yīng)用提供通用功能性的支撐,“服務(wù)”于具體應(yīng)用。
如今“服務(wù)”這個(gè)詞在軟件工程中已經(jīng)泛化,可以說(shuō),凡是向其他組件提供“支撐”功能的系統(tǒng)都可以稱為服務(wù),甚至還出現(xiàn)“軟件即服務(wù)”(SaaS)這樣的概念。在這種概念下,軟件不再是整體打包一次性賣(mài)給消費(fèi)者,而是消費(fèi)者在使用時(shí)按需獲取,而且服務(wù)還會(huì)不定期升級(jí),消費(fèi)者無(wú)須感知,并可以按使用時(shí)長(zhǎng)或者資源的消耗率來(lái)計(jì)算費(fèi)用。
“服務(wù)”思想其實(shí)就是把其他應(yīng)用當(dāng)成了消費(fèi)者,為其提供特定功能。上述應(yīng)用架構(gòu)中的“登錄、采集用戶基本信息”等功能可以抽象成一個(gè)名為“用戶中心”的服務(wù)組件。以此類推,還可以繼續(xù)抽象出“消息中心”“索引搜索”“文件存儲(chǔ)”“緩存系統(tǒng)”等通用服務(wù)組件,總的原則就是盡量提取公共的部分以避免重復(fù)的開(kāi)發(fā)工作。
之后,功能的開(kāi)發(fā)也即服務(wù)的開(kāi)發(fā)了。
1.3.2 遠(yuǎn)程調(diào)用
服務(wù)拆分后,就像天上的繁星一樣分散到不同網(wǎng)絡(luò)的各角落了,那么現(xiàn)在的問(wèn)題是如何互相訪問(wèn)呢?前面說(shuō)過(guò)了,服務(wù)與應(yīng)用不同,沒(méi)有可視化的頁(yè)面可以訪問(wèn),而且調(diào)用者是計(jì)算機(jī)程序而不是人類用戶,工程師們需要一個(gè)程序之間的通信協(xié)議,就好像下面的對(duì)話一樣明了方便。
“我需要用戶A的記錄,請(qǐng)給我它的結(jié)構(gòu)及數(shù)據(jù)”
“好,這是A的記錄的結(jié)果及數(shù)據(jù),請(qǐng)拿好”
“遠(yuǎn)程過(guò)程調(diào)用(Remote Procedure Call,簡(jiǎn)稱RPC)”協(xié)議應(yīng)運(yùn)而生,其作用就是讓?xiě)?yīng)用(服務(wù))之間的程序調(diào)用變得像本地一樣簡(jiǎn)單,這種技術(shù)完全屏蔽了各種網(wǎng)絡(luò)拓?fù)涞膹?fù)雜性,只要知道對(duì)方的“地址”就可以發(fā)起調(diào)用。
RPC在Java生態(tài)中,最早出現(xiàn)在1.1版本中的RMI(Remote Method Invocation)中。Oracle后來(lái)又提出的EJB那一套,基于JAX-RPC接口——JAX-RPC基于SOAP(簡(jiǎn)單對(duì)象訪問(wèn)協(xié)議),調(diào)用地址都是由“類目服務(wù)器(Name Server)”來(lái)注冊(cè)管理的。
在這種方案下,訪問(wèn)某個(gè)遠(yuǎn)程服務(wù)需通過(guò)以下類似代碼:
1: public class HelloClient { 2: public static void main(String args[]){ 3: try { 4: //在RMI服務(wù)注冊(cè)表中查找名稱為RHello的對(duì)象,并調(diào)用其上的方法 5: IHello rhello =(IHello)Naming.lookup(〝rmi://localhost:8888/RHello〝); 6: System.out.println(rhello.helloWorld()); 7: System.out.println(rhello.sayHelloToSomeBody(〝熔巖〝)); 8: } catch(NotBoundException e){ 9: e.printStackTrace(); 10: } catch(MalformedURLException e){ 11: e.printStackTrace(); 12: } catch(RemoteException e){ 13: e.printStackTrace(); 14: } 15: } 16: }
可以看到上述代碼中有一個(gè)URI,這就是該服務(wù)的地址,消費(fèi)端通過(guò)它可以發(fā)起訪問(wèn)以獲得數(shù)據(jù)。
1.3.3 虛擬IP地址
可不要認(rèn)為RPC就只是調(diào)用。這里有個(gè)前提,就是服務(wù)端得把自己的地址注冊(cè)上去,但是在集群環(huán)境下有多臺(tái)機(jī)器,如何處理呢?這些地址URI又怎么告訴消費(fèi)方呢?另外,當(dāng)服務(wù)不可用時(shí),誰(shuí)又去把這些注冊(cè)信息拿掉呢?
這里工程師們想到的解決方案就是前面提到的負(fù)載均衡設(shè)備概念中的“虛擬IP地址(簡(jiǎn)稱VIP)”,只需要在注冊(cè)的時(shí)候填寫(xiě)VIP,那么在調(diào)用的時(shí)候,請(qǐng)求經(jīng)過(guò)負(fù)載均衡設(shè)備,其就會(huì)自動(dòng)地將流量均分到下屬已經(jīng)注冊(cè)的機(jī)器中,并且在應(yīng)用上下線的時(shí)候,會(huì)自動(dòng)對(duì)下發(fā)的機(jī)器列表進(jìn)行調(diào)整。
在增加了RPC功能后,工程師們終于可以將公共的服務(wù)單獨(dú)部署,現(xiàn)在整個(gè)架構(gòu)如圖1.5所示。

圖1.5 “服務(wù)化后的部署架構(gòu)”
1.3.4 復(fù)雜的調(diào)用關(guān)系
歷史的車(chē)輪繼續(xù)向前,業(yè)務(wù)量再一次發(fā)生了巨大的增長(zhǎng),請(qǐng)求不斷涌進(jìn)來(lái),新的應(yīng)用不斷增加,這使得公共服務(wù)也變得越來(lái)越多,整個(gè)調(diào)用網(wǎng)由最開(kāi)始的十幾條線變成成百上千條甚至上萬(wàn)條,甚至到了后期,已經(jīng)沒(méi)人能弄清楚到底有多少條調(diào)用關(guān)系了。
圖1.6就是某企業(yè)的全局調(diào)用關(guān)系,可以看到,這里面的調(diào)用鏈錯(cuò)綜復(fù)雜。

圖1.6 “某公司的服務(wù)調(diào)用關(guān)系”
1.3.5 服務(wù)治理
復(fù)雜的服務(wù)訂閱關(guān)系必須要很好地維護(hù)起來(lái),否則在出現(xiàn)問(wèn)題的時(shí)候可能完全不知從何入手,所以這個(gè)時(shí)候,一種叫“服務(wù)治理(Service Governance)”的軟負(fù)載產(chǎn)品出現(xiàn)了。它的基礎(chǔ)工作跟注冊(cè)中心一樣是維護(hù)一個(gè)訂閱關(guān)系,不過(guò)在訂閱關(guān)系的數(shù)據(jù)之上,還提供了更多高級(jí)功能,比如:根據(jù)負(fù)載情況選擇最優(yōu)服務(wù)節(jié)點(diǎn)、多版本鏈路支持、訂閱關(guān)系鑒權(quán)限流降級(jí)以及灰度發(fā)布等。
經(jīng)典的RPC框架Dubbo就有一個(gè)專門(mén)的服務(wù)治理子系統(tǒng),其底層采用ZooKeeper作為數(shù)據(jù)存儲(chǔ),如今經(jīng)常提到的Spring Cloud則是采用名為Eureka的自研產(chǎn)品。
Dubbo的“服務(wù)治理”采用的是ZooKeeper,由于其自身數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì),其服務(wù)關(guān)系存儲(chǔ)采用的是樹(shù)狀結(jié)構(gòu),如圖1.7所示:

圖1.7 “Dubbo在ZooKeeper中的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)”
這種存儲(chǔ)結(jié)構(gòu)的優(yōu)點(diǎn)在于可以很容易地監(jiān)聽(tīng)數(shù)據(jù)變化,例如需要監(jiān)聽(tīng)“服務(wù)A”對(duì)應(yīng)的“提供者”變化情況時(shí),只需要將監(jiān)聽(tīng)點(diǎn)掛載到服務(wù)A的“提供者”父節(jié)點(diǎn)即可。同理,如果需要同時(shí)監(jiān)聽(tīng)“提供者”與“消費(fèi)者”,只需要將監(jiān)聽(tīng)掛載到“服務(wù)”節(jié)點(diǎn)即可。然而不足也是很明顯的,例如需要進(jìn)行關(guān)聯(lián)查詢時(shí),樹(shù)狀的層次結(jié)構(gòu)就不那么方便了。比如需要查詢機(jī)器M1訂閱的所有服務(wù),這種情況下只能逐一遍歷,其時(shí)間復(fù)雜度為O(n),其中n為服務(wù)數(shù)量,并不高效,再加上ZooKeeper強(qiáng)一致的設(shè)計(jì),從性能與功能上來(lái)講,我個(gè)人認(rèn)為都不適合作為“服務(wù)發(fā)現(xiàn)”來(lái)使用。
現(xiàn)今,工程師們普遍傾向使用etcd來(lái)實(shí)現(xiàn)“注冊(cè)中心”,其特點(diǎn)是采用KV存儲(chǔ),對(duì)于結(jié)構(gòu)性查詢,更加輕量、易運(yùn)維,優(yōu)勢(shì)更佳。
訂閱關(guān)系可不僅在RPC中,任何鏈路,只要存在服務(wù)一說(shuō),都會(huì)涉及這個(gè)概念,比如著名的開(kāi)源消息框架RocketMQ,也會(huì)使用一個(gè)目錄服務(wù)器(官方名稱是nameserver)來(lái)維護(hù)Topic與Broker之間的映射關(guān)系。
服務(wù)治理維護(hù)的數(shù)據(jù),從根本上說(shuō)就是“提供者”與“消費(fèi)者”之前的映射關(guān)系,例如有3臺(tái)機(jī)器在提供服務(wù)A,則標(biāo)記為Aprovider= {M1, M2, M3},同時(shí)有2個(gè)消費(fèi)者在調(diào)用A的服務(wù),則記為Asubscriber= {N1, N2},可以看見(jiàn)這兩條數(shù)據(jù)均為矢量數(shù)據(jù),因此如何較好地結(jié)構(gòu)化存儲(chǔ),是鏈路關(guān)系維護(hù)的關(guān)鍵。
當(dāng)然可以嘗試將其存儲(chǔ)在數(shù)據(jù)庫(kù)中,但這里的問(wèn)題是,訂閱關(guān)系通常是實(shí)時(shí)變化的,而且需要通知功能。比如提供A服務(wù)的M1這臺(tái)機(jī)器宕機(jī),消費(fèi)者Asubscriber需要監(jiān)聽(tīng)到這種變化,否則會(huì)將請(qǐng)求路由到一個(gè)已經(jīng)宕機(jī)或者下線的服務(wù)上,導(dǎo)致錯(cuò)誤的請(qǐng)求。更復(fù)雜的情況是,可能一個(gè)關(guān)系變化會(huì)連鎖式地影響到其他鏈路。
例如B服務(wù)其實(shí)就是A服務(wù)的一個(gè)消費(fèi)者N3,而B(niǎo)服務(wù)本身又有消費(fèi)者,那么當(dāng)M1出現(xiàn)故障時(shí),Aprovider變成{M2, M3},這時(shí)B的流量入口從之前的三臺(tái)下降到了兩臺(tái),B服務(wù)的鏈路能力是有下降的,即整條鏈路的吞吐量都受到了影響。如何及時(shí)、直觀地反映問(wèn)題,到如今也是個(gè)棘手的問(wèn)題,這點(diǎn)更是彈性調(diào)度不可或缺的基礎(chǔ)。
可以說(shuō)軟負(fù)載中的“服務(wù)治理”發(fā)展到今天已經(jīng)遠(yuǎn)不只“服務(wù)注冊(cè)”那么簡(jiǎn)單了。
1.3.6 旁路負(fù)載
由于“服務(wù)治理”系統(tǒng)的存在,工程師們?cè)僖膊挥脼閼?yīng)用之間復(fù)雜的調(diào)用關(guān)系而擔(dān)驚受怕了,分布式得以空前發(fā)展。
因?yàn)椤胺?wù)治理”通常都提供健康檢測(cè)功能,已經(jīng)能夠很好地維護(hù)服務(wù)對(duì)應(yīng)的機(jī)器列表,所以之前講到的VIP(虛擬IP地址)便變得不那么必需了。這個(gè)時(shí)候工程師們想出了一種“旁路負(fù)載”(亦稱透明負(fù)載)的軟負(fù)載架構(gòu),它的特點(diǎn)是并不直接通過(guò)代理流量來(lái)分發(fā)負(fù)載流量,而是在RPC客戶端中直接埋入負(fù)載及其他鏈路邏輯,這樣就省下了網(wǎng)關(guān)代理這層,但是由于對(duì)外需要統(tǒng)一暴露接口,因此對(duì)外的網(wǎng)關(guān)仍然需要保留。
當(dāng)然,對(duì)外的網(wǎng)關(guān)已經(jīng)不是簡(jiǎn)單的流量負(fù)載均衡,像“接口版本管理、攻擊防御、請(qǐng)求重定向”等功能也被加入了,這個(gè)時(shí)候它有了一個(gè)更貼切的名字,叫“API網(wǎng)關(guān)”。像讀者熟知的Spring Cloud框架,其Zuul組件充當(dāng)?shù)谋闶恰癆PI網(wǎng)關(guān)”的角色。
最終系統(tǒng)架構(gòu)便變成了圖1.8的樣子:

圖1.8 “采取旁路負(fù)載后的架構(gòu)”
如此一來(lái),系統(tǒng)內(nèi)部的訪問(wèn)阻礙已經(jīng)減少到很少了,同時(shí)隨著Docker容器化及DevOps思想的迅速崛起,服務(wù)的粒度可以拆分得比以前更細(xì),讓需求開(kāi)發(fā)更加獨(dú)立、互不影響,這就是之后出現(xiàn)的微服務(wù)一說(shuō)。
- 常用工具軟件案例教程
- Maya 2019三維動(dòng)畫(huà)基礎(chǔ)案例教程
- Mastering phpMyAdmin 3.3.x for Effective MySQL Management
- iPhone Applications Tune/Up
- 剪映視頻后期剪輯零基礎(chǔ)入門(mén)到精通
- SolidWorks2016中文版從入門(mén)到精通/CAX工程應(yīng)用叢書(shū)
- 三維建模與3D打印從入門(mén)到精通
- Moodle Course Conversion: Beginner's Guide
- ChatGPT+AI文案寫(xiě)作實(shí)戰(zhàn)108招
- iOS智能手機(jī)APP界面設(shè)計(jì)實(shí)戰(zhàn)教程
- 中文版CorelDRAW X7基礎(chǔ)培訓(xùn)教程
- Deep Inside osCommerce: The Cookbook
- 中文版Photoshop CS5基礎(chǔ)培訓(xùn)教程(移動(dòng)學(xué)習(xí)版)
- 設(shè)計(jì)必修課:Axure RP 9互聯(lián)網(wǎng)產(chǎn)品原型設(shè)計(jì)
- Linux Shell腳本攻略(第3版)