從結(jié)構(gòu)來看,右邊的網(wǎng)狀結(jié)構(gòu)其實比左邊星型的結(jié)構(gòu)更復(fù)雜,聯(lián)系更多。那么這樣一個復(fù)雜架構(gòu)的好處表現(xiàn)在哪里?

1.復(fù)雜度可控:在將應(yīng)用分解的同時,規(guī)避了原本復(fù)雜度無止境的積累。每一個微服務(wù)專注于單一功能,并通過定義良好的接口清晰表述服務(wù)邊界。由于體積小、復(fù)雜度低,每個微服務(wù)可由一個小規(guī)模開發(fā)團(tuán)隊完全掌控,易于保持高可維護(hù)性和開發(fā)效率。

2.獨(dú)立部署:由于微服務(wù)具備獨(dú)立的運(yùn)行進(jìn)程,所以每個微服務(wù)也可以獨(dú)立部署。當(dāng)某個微服務(wù)發(fā)生變更時無需編譯、部署整個應(yīng)用。由微服務(wù)組成的應(yīng)用相當(dāng)于具備一系列可并行的發(fā)布流程,使得發(fā)布更加高效,同時降低對生產(chǎn)環(huán)境所造成的風(fēng)險,最終縮短應(yīng)用交付周期。

3.技術(shù)選型靈活:微服務(wù)架構(gòu)下,技術(shù)選型是去中心化的。每個團(tuán)隊可以根據(jù)自身服務(wù)的需求和行業(yè)發(fā)展的現(xiàn)狀,自由選擇最適合的技術(shù)棧。由于每個微服務(wù)相對簡單,當(dāng)需要對技術(shù)棧進(jìn)行升級時所面臨的風(fēng)險較低,甚至完全重構(gòu)一個微服務(wù)也是可行的。

4.容錯:當(dāng)某一組建發(fā)生故障時,在單一進(jìn)程的傳統(tǒng)架構(gòu)下,故障很有可能在進(jìn)程內(nèi)擴(kuò)散,形成應(yīng)用全局性的不可用。在微服務(wù)架構(gòu)下,故障會被隔離在單個服務(wù)中。若設(shè)計良好,其他服務(wù)可通過重試、平穩(wěn)退化等機(jī)制實現(xiàn)應(yīng)用層面的容錯。

5.擴(kuò)展:單塊架構(gòu)應(yīng)用也可以實現(xiàn)橫向擴(kuò)展,就是將整個應(yīng)用完整的復(fù)制到不同的節(jié)點。當(dāng)應(yīng)用的不同組件在擴(kuò)展需求上存在差異時,微服務(wù)架構(gòu)便體現(xiàn)出其靈活性,因為每個服務(wù)可以根據(jù)實際需求獨(dú)立進(jìn)行擴(kuò)展。

七牛圖片處理微服務(wù)應(yīng)用案例

以七牛云的圖片處理(簡稱FOP)場景為例。七牛能夠為用戶提供格式轉(zhuǎn)換、尺寸和加水印等圖片處理服務(wù),從而幫助他們節(jié)省計算資源和帶寬資源。FOP服務(wù)早期的架構(gòu)很簡單,以它的每一個應(yīng)用為后端。但由于原始圖片一般都很大,隨著用戶越來越多,流量越來越高,負(fù)載均衡逐漸出現(xiàn)了帶寬和流量的壓力。而面對這種情況,加更多的前端只是權(quán)宜之計,因為圖像處理對于CPU要求很高,意味著后端的數(shù)量會越來越多,負(fù)載均衡和后端流量方面始終是不平衡的,并且這也不是一個環(huán)保和節(jié)省資源的方式。

于是,F(xiàn)OP服務(wù)做了一個架構(gòu)上的調(diào)整:把服務(wù)再做拆分。圖像處理服務(wù)拆成兩個部分,分別負(fù)責(zé)處理文件的傳輸和圖像本身的處理。從負(fù)載均衡過來的請求不再是完整的文件,而是文件的地址。這樣,我們可以以更靈活來處理,把負(fù)載均衡和流量優(yōu)化,優(yōu)化和部署也可以跟整個圖像處理沒有關(guān)系,可以做單獨(dú)的部署。下面兩幅圖即是一個對微服務(wù)再進(jìn)行細(xì)分的例子。

 

而細(xì)分之后,對于稍微復(fù)雜一些的請求,比如一個圖片需要改變格式和尺寸,并且打上自定義水印。那么就用管道的方式把不同的服務(wù)串聯(lián)起來最終實現(xiàn)。

容器在微服務(wù)中的應(yīng)用

目前微服務(wù)架構(gòu)的主流技術(shù)方案中都使用了Docker,七牛也是如此。將Docker理解為輕量級的虛擬機(jī),它的一些特性如隔離、物理機(jī)制等可以說和微服務(wù)架構(gòu)有天然的契合度。但是Docker并不能解決微服務(wù)的所有問題,它最初是一個單機(jī)的工具,雖然后來官方也推出了很多的工具鏈,要真正解決部署的問題,還有很長的路要走。

肖勤推薦了一個去年谷歌發(fā)布的開源容器系統(tǒng)Kubernetes。   Kubernetes提供了管理多個容器的方式,能夠令它們在真正的物理機(jī)或者虛擬機(jī)以一個合理的方式運(yùn)用起來,供外界訪問。Kubernetes存在的意義,是因為它解決了微服務(wù)另外一個部署的問題,拆分之后不同模塊之間的聯(lián)系和依賴會更加復(fù)雜,勢必對于運(yùn)營和部署有更高的要求,如果沒有工具和系統(tǒng)能夠提供這樣的能力,或者沒有更好的方法去做的話,微服務(wù)就是空中樓閣。而Kubernetes提供的能力是用戶只需要去定義它的服務(wù)期望的狀態(tài),而不用去關(guān)心它的過程。整個調(diào)度的過程,整個提供服務(wù)的過程都由這個系統(tǒng)去幫你實現(xiàn)。

Kubernetes提出了很多概念。比如說Kubernetes Master,它是一個中心的服務(wù)而不是工具。首先由API接受容器的配置,提供一個調(diào)度器,把容器調(diào)度到合理的位置運(yùn)行,再提供一定的控制技術(shù),保證容器運(yùn)行的狀態(tài)。Minion可以理解為容器運(yùn)行的真正節(jié)點,Pods是一個或者一組容器,在Kubernetes 中是可以調(diào)動的最小程序,Replication Controller保證了它運(yùn)行的數(shù)據(jù),如果它掛掉了,就不能再提供服務(wù)?,F(xiàn)在也會有很多服務(wù)的副本,以保證Pods的數(shù)量和運(yùn)行狀態(tài)。另外一個標(biāo)簽是Labels,是容器運(yùn)行時附加的。它的作用是容器在被使用的時候,能夠有一個規(guī)則讓前面的服務(wù)正確找到它。服務(wù)是一個虛擬的概念,是描述一組Pods對外提供的接口和對外提供的能力,通過代理的方式來實現(xiàn)。

上圖是Kubernetes官方文檔中的描述。值得注意的是,Kubernetes系統(tǒng)是按照微服務(wù)架構(gòu)設(shè)計的。因為項目很多部分和逐漸,比如說調(diào)度器和復(fù)制器,甚至包括Docker在整個系統(tǒng)中都會被替換,如果有更好的容器,Docker有可能會被棄用,變成另外的技術(shù)。

如何評價Kubernetes系統(tǒng)呢?是不是整個微服務(wù)在實踐上的一個未來呢?目前無法確定,因為從學(xué)習(xí)的角度上來看, Kubernetes也表現(xiàn)出了一定的局限性。比如說Pods的網(wǎng)絡(luò),雖然它提供了文檔可以某些方式體現(xiàn),但是1.0提供的方式還是和自己的云服務(wù)相關(guān)。這些局限性可能跟谷歌的策略有關(guān),因為谷歌非常希望去推它的GCE平臺。我們發(fā)現(xiàn)Kubernetes在設(shè)計當(dāng)中,如果不適用他們的云服務(wù),摘出來的話,這一部分還需要做很多事情,才可以把Kubernetes在自己的基礎(chǔ)上做一個比較好的網(wǎng)絡(luò)服務(wù)。

基于Docker的微服務(wù)架構(gòu)云端實踐

應(yīng)用設(shè)計架構(gòu)的演變

十年前想構(gòu)建一個具備基本功能流程的電子商務(wù)網(wǎng)站,包括用戶瀏覽產(chǎn)品信息、加入購物車、下單,在線支付和完成配送,在進(jìn)行系統(tǒng)構(gòu)建時,典型做法是把功能模塊簡單地做一些劃分,后臺會訪問統(tǒng)一數(shù)據(jù)庫,包括用戶管理、商品信息、支付。后來有些程序員意識到可以把一些軟件應(yīng)用當(dāng)中的最底層和數(shù)據(jù)庫獨(dú)立起來,緊接著出現(xiàn)了很多的工具做這些東西,如JDBC、ADO.Net等。

接下來就出現(xiàn)了比較傳統(tǒng)的經(jīng)典三層架構(gòu)Web方式:最上面是展現(xiàn)層,主要是處理UI,中間層處理基本業(yè)務(wù),下面是數(shù)據(jù)訪問層,后面是作為它的存儲方。如下圖所示。

時至今日,這種多層次的應(yīng)用構(gòu)架仍然具備一些優(yōu)勢:層次劃分清晰,層與層之間有比較清晰的接口,每層之間非常清晰。展現(xiàn)層只負(fù)責(zé)UI,邏輯層負(fù)責(zé)業(yè)務(wù)邏輯,每一層又可以進(jìn)而被分解成邏輯的組建。特別是業(yè)務(wù)邏輯層,一般來說都會把它分為邏輯組建,包括服務(wù)于用戶管理的,服務(wù)于產(chǎn)品信息的,服務(wù)于支付的,等等。而處于最下面的數(shù)據(jù)訪問層,雖然能夠被分成若干個模塊和組建,但是從部署上來講,仍然是單塊的組建。所有的程序基本上運(yùn)行在一個進(jìn)程上,所有的代碼都會被打包、編譯和部署,我們把它做成一塊的東西。

在項目初期,多層架構(gòu)能夠使程序員更容易開發(fā)、測試和部署。但隨著應(yīng)用程序逐漸增長,業(yè)務(wù)復(fù)雜度會變的越來越高。這種情況下三層構(gòu)架并不是特別適合業(yè)務(wù)的繼續(xù)發(fā)展,可維護(hù)性和敏捷程度都會變差,并且團(tuán)隊擴(kuò)大后成員之間的溝通也會影響產(chǎn)品的交付。從而最終影響到對市場需求新的跟進(jìn)。而微服務(wù),就是解決這些問題的一個很好的方案。

什么是微服務(wù)

上圖即為通過微服務(wù)架構(gòu)把原來的應(yīng)用拆分成一系列的微服務(wù),它們之間可以用比較輕量級的協(xié)議互相溝通,因為每個服務(wù)是運(yùn)行在自己獨(dú)立的進(jìn)程上,完全可以進(jìn)行非常獨(dú)立的部署和維護(hù)。另外一點微服務(wù)提倡的是技術(shù)選型去中心化,在不同的服務(wù)中可以選擇最適合這部分的持久化方案。

靈雀云對已Docker化的微服務(wù)的支撐

靈雀云認(rèn)為,Docker是運(yùn)行微服務(wù)的最佳解決方案。Docker實際上是一個應(yīng)用容器的引擎,可以讓開發(fā)者非常方便地把自己的應(yīng)用以及這個應(yīng)用所需要的所有依賴都打進(jìn)容器鏡像當(dāng)中,且具有可移植性,能夠部署到任何服務(wù)器上。靈雀云是基于Docker構(gòu)建的,如果把封裝的微服務(wù)比喻成集裝箱的話,靈雀云則提供了一個大輪船,裝載了所有集裝箱,為微服務(wù)運(yùn)行提供一個穩(wěn)定的運(yùn)行環(huán)境,用戶也可以在此基礎(chǔ)上進(jìn)行管理。這里就可以享受到很多云端服務(wù)的優(yōu)勢。

創(chuàng)建:靈雀云的鏡像構(gòu)建和持續(xù)集成服務(wù)幫助用戶將獨(dú)立、可復(fù)用的微服務(wù)打包,轉(zhuǎn)化為隨時可以部署的容器鏡像。

集成:靈雀云不僅在平臺的鏡像倉庫中匯集了大量來自社區(qū)的優(yōu)質(zhì)鏡像,也支持平臺以外的任意鏡像源。用戶可以自由組合、復(fù)用數(shù)以萬計的容器化微服務(wù),像搭積木一樣輕松集成應(yīng)用。

部署:微服務(wù)由于組件數(shù)量眾多,云端部署成為實踐上的一個難點。靈雀云以容器為應(yīng)用發(fā)布的載體,用戶不必指定傳統(tǒng)部署方式中繁瑣的步驟,只需提供容器鏡像和簡單的容器配置,平臺會將整個部署流程自動化。靈雀云與docker-compose兼容,實現(xiàn)對于由多個微服務(wù)容器組成的完整應(yīng)用的一鍵部署。

運(yùn)維:微服務(wù)由于獨(dú)立進(jìn)程眾多,部署后的運(yùn)維、管理成為實踐上的另一個難點。靈雀云完全屏蔽底層云主機(jī)和基礎(chǔ)架構(gòu)運(yùn)維,讓用戶專注于應(yīng)用。同時,靈雀云通過容器編排、自動修復(fù)、自動擴(kuò)展、監(jiān)控日志等高級應(yīng)用生命周期服務(wù)實現(xiàn)容器化微服務(wù)的智能托管,進(jìn)一步幫助用戶降低運(yùn)維成本和難度。

網(wǎng)絡(luò):微服務(wù)架構(gòu)下各組件之間的溝通、協(xié)調(diào)對網(wǎng)絡(luò)有較高要求,尤其在云端實踐中,各個微服務(wù)組件的物理位置是動態(tài)的,且不受應(yīng)用控制。靈雀云提供完整的容器網(wǎng)絡(luò)解決方案,支持負(fù)載均衡、服務(wù)發(fā)現(xiàn)、跨主機(jī)關(guān)聯(lián),以及應(yīng)用安全內(nèi)網(wǎng)來確保微服務(wù)對內(nèi)、對外網(wǎng)絡(luò)的可用性及安全性。

存儲:微服務(wù)提倡多元化持久性(Polyglot Persistence),應(yīng)用內(nèi)的每個微服務(wù)可根據(jù)實際需求選擇最合適的數(shù)據(jù)服務(wù)。靈雀云將持久性云存儲抽象成數(shù)據(jù)卷,可以直接掛載在容器上,并在容器重啟、遷移中自動重新掛載??芍С秩我馊萜骰瘮?shù)據(jù)服務(wù),供微服務(wù)應(yīng)用集成。

微服務(wù)架構(gòu)的誕生和容器技術(shù)的流行,幾乎是同時發(fā)生的,這并不是偶然。這是互聯(lián)網(wǎng)時代倒逼傳統(tǒng)技術(shù)和架構(gòu)而產(chǎn)生的變革,最前線的開發(fā)者和他們所在的互聯(lián)網(wǎng)企業(yè)最先感受到了這場變革。靈雀云希望與開發(fā)者一起共同引領(lǐng)這場變革,幫助互聯(lián)網(wǎng)企業(yè)真正專注于自身的核心業(yè)務(wù),并在技術(shù)和架構(gòu)上保持領(lǐng)先。

京東對于微服務(wù)底層的技術(shù)支持實踐

京東資深架構(gòu)師李鑫主要負(fù)責(zé)京東的服務(wù)框架, 他所分享的內(nèi)容是對微服務(wù)底層的技術(shù)框架支持。

為何要微服務(wù)化?

原因有以下幾點。

1.系統(tǒng)規(guī)模隨著業(yè)務(wù)的發(fā)展?而增長,原有系統(tǒng)架構(gòu)模式中邏輯過于耦合,不再適應(yīng);

2.拆分后的?系統(tǒng)邏輯內(nèi)聚,易于局部擴(kuò)展;

3.?系統(tǒng)之間通過接?口來進(jìn)?交互,接?契約不變的情況下可獨(dú)?變化。

上圖中,左邊是幾年前京東的架構(gòu),很多服務(wù)都是訪問同樣一個DB。這種架構(gòu)的問題在于:流量來了以后全部壓力都在DB上。而且在之前京東的架構(gòu)里比較強(qiáng)調(diào)快速開發(fā),很多邏輯比如說倉儲配送服務(wù)都不存在,全都依靠BD來進(jìn)行。這樣可擴(kuò)展性相當(dāng)差,性能也不太可控。后來,我們根據(jù)業(yè)務(wù)模塊和特性進(jìn)行水平拆分,應(yīng)用和應(yīng)用之間都要通過接口進(jìn)行交互,有同步和異步接口。

京東服務(wù)平臺演變歷程

下圖是京東服務(wù)平臺的基本功能構(gòu)成。

在2012年初,京東開始做第一代服務(wù)框架,用的是zookeeper集群作為注冊中心,base on開源的服務(wù)體系。如下圖所示。

第一代架構(gòu)在運(yùn)營過程中,暴露出了很多問題。

1.    客戶端

•    許多邏輯放到客戶端,客戶端邏輯太多,一旦需要修改,就面臨升級問題。

2.    注冊中?

•    將ZooKeeper作為注冊中?,功能定制擴(kuò)展受限。

3.    服務(wù)治理

•    缺乏流控手段,大流量打爆線程池;

•    更改配置需要重啟,對于運(yùn)營不夠友好;

•    缺乏調(diào)用監(jiān)控,沒有調(diào)用分析圖表。

為了解決以上問題,團(tuán)隊在2014年推出了新服務(wù)平臺JSF,其框架示意圖如下。

可以看出,服務(wù)注冊和尋址沒有太大變化,主要變化在于注冊中心。采用團(tuán)隊自己寫的服務(wù),并提供了index服務(wù)數(shù)據(jù)庫。相對來講,詢問注冊中心地址,會進(jìn)行一個服務(wù)的調(diào)用。因為這一塊有自己內(nèi)部的邏輯,沒有辦法實現(xiàn),所以定期會發(fā)送性能統(tǒng)計數(shù)據(jù)。把RPC轉(zhuǎn)化,生成負(fù)載均衡管理重試策略,然后經(jīng)過序列化以后發(fā)送到server并解碼,再進(jìn)行實際的業(yè)務(wù)調(diào)用,然后進(jìn)行一些過濾的邏輯。

京東服務(wù)平臺核心技術(shù)

1.協(xié)議

•    采?異步事件通訊框架Netty來實現(xiàn)?絡(luò)協(xié)議棧;

•    同?端?同時支持Http、TCP協(xié)議訪問,根據(jù)數(shù)據(jù)包情況掛載不同解碼器;

•    TCP長鏈接下使?用?定義二進(jìn)制協(xié)議;

•    HTTP網(wǎng)關(guān)來應(yīng)對跨語?言訪問。

2.RPC-callback

•    TCP長鏈接是雙?的,服務(wù)方可以主動推送消息到調(diào)?方;

•    調(diào)?端檢測到參數(shù)列表中有Callback類型,登記相應(yīng)的callback對象;服務(wù)端收到調(diào)用時,生成相應(yīng)的反向調(diào)用代理;

•    服務(wù)端持有此代理,并在需要時調(diào)用此代理來推送消息

3.負(fù)載均衡

一個服務(wù)至少部署兩個以上實例,掛了一個以后,另外一個可以正常服務(wù)。服務(wù)消費(fèi)者這一塊,有一個負(fù)載均衡的算法選擇服務(wù)提供者,可以設(shè)置權(quán)重。有一個可用列表,還有一個重連列,系統(tǒng)會定時連接。還有一個是非健康列表,雖然可以長鏈接建立起來,這個時候給出的反饋是不正常的,維護(hù)的時候會把它挪動可用列表里。

4.性能優(yōu)化

首先有一個批量處理,請求先寫入RingBuffer為,打成序列化與反序列化這種耗時的操作從Netty的I/O線程中挪到用戶線程池中。啟用壓縮以應(yīng)對大數(shù)據(jù)量的請求,默認(rèn)snappy壓縮算法。最后是定制msgpack序列化,序列化模板,同時還支持fast json、hessian等多種序列化協(xié)議。

5.注冊中心

京東有很多機(jī)房,對于跨機(jī)房來說是耗用更多資源,也占用了專線資源。這里實現(xiàn)了優(yōu)先訪問本機(jī)房的注冊中心,不可用的話才會去連起來機(jī)房。對于注冊中心來說,后面會連一個數(shù)據(jù)庫。但是這一塊連數(shù)據(jù)庫失敗的話,也會有一些單點的問題。對于這種情況,實現(xiàn)了一個LDS,在寫數(shù)據(jù)庫的同時會寫到本地的存儲,在后臺進(jìn)行數(shù)據(jù)的同步。如果說DB服務(wù)不可用的話,還是可以取得相應(yīng)的注冊。

6.配置

配置這一塊是服務(wù)提供者列表維護(hù),動態(tài)推送??梢圆榭串?dāng)前服務(wù)生效的配置和狀態(tài),可以看出調(diào)用的平均耗時和失敗的次數(shù)。對服務(wù)動態(tài)分組無須啟動,而且機(jī)房也有備份,出現(xiàn)問題直接調(diào)用就可以了。

7.限流

每一個服務(wù)調(diào)用者都有可能成為潛在的DDOS攻擊者,這里會給服務(wù)的所有調(diào)用者帶上標(biāo)示,在系統(tǒng)環(huán)境變量中帶上APPID。此外,開發(fā)了計數(shù)器服務(wù),限定單位時間內(nèi)最大調(diào)用次數(shù)。如果說你是一個推送服務(wù),限定每分鐘四百次,其實調(diào)用已經(jīng)超限了。為了保護(hù)服務(wù)端,系統(tǒng)同時限定了并發(fā)數(shù),服務(wù)端執(zhí)行時檢查請求的狀態(tài),如等待時間大于超時時間,直接丟棄。

8.降級

• 每個服務(wù)接?口的每個?方法都有災(zāi)備降級開關(guān);

• 配置mock邏輯,返回的結(jié)果?用json格式預(yù)先設(shè)好;

• 降級開關(guān)打開時將在consumer端短路RPC調(diào)?用,直接返回JSON結(jié) 果。

9.彈性云部署

在京東內(nèi)部,CAP負(fù)責(zé)資源調(diào)度,JDOS負(fù)責(zé)資源的虛擬和部署。CAP會定時調(diào)度JSF監(jiān)控平臺的方法,如果說告訴它調(diào)用的次數(shù)已經(jīng)超了,CAP會調(diào)用JDOS,分配具體的服務(wù)資源,把一些新服務(wù)自動部署。最終,到注冊中心進(jìn)行注冊。

下一步研發(fā)方向

首先會做的是服務(wù)治理,根據(jù)應(yīng)用ID的一系列管理增強(qiáng)。增強(qiáng)接口文檔管理,建立接口文檔中心,幫助用戶使用接口。最后是增強(qiáng)跨語言支持,對于一些比較小規(guī)模的,直接通過網(wǎng)站來更新。

以上是牛小七對于本次開發(fā)者最佳實踐日內(nèi)容的概括性介紹,如需獲取詳細(xì)的演講信息和往期內(nèi)容回顧,可以訪問活動專題。

分享到

fanz

相關(guān)推薦