從單體應用到微服務開發旅程

youmen發表於2021-07-02

特別說明

這是一個由simviso團隊進行的關於架構演進的雲原生分享的翻譯文件,這個主要是關於Service Mesh 的分享,分享者是Kong這家公司的CTO。 這家公司有一個著名的開源專案:github.com/Kong/kong

讓我們一起來學習下這家CTO是如何從單體應用架構過渡到微服務架構的,Kong又做了哪些事,K8S在其中又做了什麼角色,什麼是狀態機(基於事件架構得到一種設計),在這個過程中又會遇到哪些坑,哪些經驗,盡在視訊分享中

視訊地址

【國外前沿技術分享-雲原生專題-中文字幕】從單體應用到微服務的開發旅程-上
【國外前沿技術分享-雲原生專題-中文字幕】從單體應用到微服務的開發旅程-下
視訊翻譯文字版權歸 simviso所有:

前言

我叫Marco Palladino,我是Kong的創始人,同時也是這家公司的CTO;
如他所說,我來自San Francisco California, 今天我想和大家討論下Service Mesh;
為了打造出適合現代化的架構體系,我們的架構組織採用了Service Mesh來做過渡;
我想說的是,當我們的企業變大並通過拆分變成分散式管理之後,那這個企業組織就會變得像多細胞生物一樣複雜 (由一個單細胞的形式分裂成多細胞進行協作,整體上看去還是這一個生命體);

事實上,無論是我們的團隊還是軟體,一旦複雜了,都會去做解耦並進行分散式化管理;
可以想象一下,在使用service mesh實現架構現代化的過程中,它不僅僅只是技術採用這麼簡單
我們的軟體開發方式也因為以下三個方向而發生著改變

其中一種是技術上的更新換代;
第二種是組織結構上的過渡;

所以架構組織該如何去改變才能去應對新的微服務架構;
也就是說,我們之前對單體架構系統所做的操作模式必須進行改變。即我們不能以之前的方式去部署,擴充套件,版本化和文件化這個全新的微服務架構;

這三個方向正在改變我們開發軟體的方式;
隨著docker和kubernetes在2013和2014年的先後釋出,一場真正的軟體革命也就開始了;
Docker和 kubernetes為我們提供了一種全新的建立應用的方式 隨著時間的推進,基於它們,我們可以以更好的方式來對這些應用進行擴充 不僅僅是從技術上帶來的好處,更重要的是可以作為我們業務擴充的首選;
事實上除了技術層面,在這場演講中我會來談下我們想要實現的業務目標;
如果我們不能在實現業務目標的同時協調新技術的使用,那麼我們也就沒辦法在技術轉型上走下去
在這個過程中,我們必須變得更加務實才行

這是一個從單體架構服務到聚合服務(比如Maven多模組)再到微服務化的過程 Service Mesh就好像一個口袋 口袋裡裝了一堆的糖果,每個糖果都是一個微服務,每一個微服務可能是我們正常實現的服務,也有可能是由函式式實現的服務;

同時,API也會改變它們在我們系統中的角色:

我們通常以API為粒度進行APM(Application performance monitoring)效能監控管理。 自從2007-2008年移動端問世起,我們需要一種方式去和我們單體應用進行互動。於是我們才有了north-south traffic(南北交換,通常指多端與伺服器之間的資料互動,也就是說我們可以通過外部開發者或移動端APP或外部其他形式來訪問伺服器,重點是外部)

我們要對我們的軟體進行功能解耦,此時API在我們的系統中扮演的角色也就越來越重要;

East-west traffic(東西交換,和上面相比,重點是內部),這個通常是指我們不同團隊所開發的系統以及不同系統產品之間所產生的資料互動 接下來,我們將討論使用 Service Mesh來對資料層和控制層進行分離,以此來不斷的優化擴充套件我們的系統;

過渡微服務的一些相關要點

what does it mean?

但退一步來講,從務實的角度出發,為什麼要用Service Mesh來進行微服務的過渡
我們重構單體應用的目的是可以釋放團隊生產力以及提高業務的可擴充套件性
此時整個過渡的關鍵在於團隊生產力以及相關業務的可擴充套件性

在向微服務過渡的過程中,如果我們沒有做到這兩者中的任何一點,那可以這麼說,我們在做的不過是依葫蘆畫瓢 所以在做這個事之前我們必須捫心自問,我們到底是在為生產而使用,還是為了用這個技術而用;

在這個過程中,業務應該是首要驅動力,因為我們寫專案的目的就是為了實現業務目標 在確定業務策略然後採用微服務架構來實現,接下來,我們要確定從什麼時候開始,更重要的是到什麼時候結束;

should we do it?

接下來第二個問題,也是那些想要將專案轉向微服務的人想要問的 我們是否應該這麼做,是否應該轉向微服務,是否應該放棄現在原有的架構?

從技術趨勢而言,我們不得不問自己,一項技術,我們是基於實際需要採用,還是因為這個技術很成熟才去採用;

過渡到微服務的過程,這可要比跑單體應用複雜得多。它難就難在一個系統包含了所有的功能,然後我們將其裂變成一群具有單一功能的系統;

目前而言,我們現在幾乎不再以同一種方式部署或者擴充套件大型單體應用 但我們可以通過將一個完整的系統拆分成成百上千個具有不同功能的單體系統來實現原本的功能;

如果說目前微服務無法去解決我們在管理單體應用上的問題,那麼它就會使情況變得更加糟糕;

因此技術架構和團隊成員必須足夠成熟,才能確實的去解決存在的問題;

事實上,我真的很推薦在這個過程中採取步步為營的方式過渡到微服務;

基於以下幾個理由。首先,通過一步步的去實現階段性的目標,這能增長團隊的信心讓他們覺得這件事他們可以駕馭 同時,我們在這個過程中也可以去適應並隨時改變我們的流程;

同時,業務領導者也會隨著過渡而變得越發自信,因為整個過渡是朝著正確的方向進行,隨著時間的推移來擴充套件和讓業務變得更加與時俱進;

事實上,當我們來看微服務,來看那些大公司例如Netflix,或者Amazon 它們其實很早之前就已經轉型微服務,甚至那時候kubernetes和docker都不存在;

到底是什麼在驅動這些公司去做這樣的轉型?
就拿Netflix而言,為了擴充套件它的業務規模並不再拘泥於一個國家和單一的使用者體系,它想向全世界邁進,所以它改變了;

所以這也是他們的商業目標;
對於想要達成的業務需求而言,他們之前的架構並不能滿足。因此他們轉向了微服務架構以滿足業務需求;
Amazon同樣如此,因為它不單單滿足於賣一種東西,它更傾向於商品的多元性,因此架構的改變才能滿足更為複雜的需要;

因此微服務緊緊地圍繞著這些業務需求。為了完成我們的目標 我們不能各自孤軍奮戰無論是開發團隊或者是管理層。拿Amazon舉例,它就是微服務的成功例子;

那你們誰知道,是誰決定了讓Amazon向微服務去轉型?

Amazon CEO Jeff Bezos曾強制推行了六個原則,如果不遵從這些原則 那這些人就可以直接被炒了(這段話其實是講02年貝佐斯對員工提出必須要遵守的原則性問題)

這種改變很難相信居然不是開發團隊提出的,而是他們的CEO提出的改變;

作為企業的領導者通過逐步的改變去完成目標,同時這樣能讓他們變得更加自信,這才是正確前進的方法;

從上面的所有情況來看,為了達到目標,我們將要經歷無數的艱難險阻
我們可以依據複雜性來決定微服務是大是小
事實上,這些微服務的大小都由業務本身需求所決定,適合就行

Let's do it!

但只有當我們覺得微服務是我們所需要的,同時我們所選擇的路線也是正確的,那麼我們才能繼續轉型;

在轉換到微服務的過程中 ,我定義了兩種不同的策略,

其中一種我稱之為挖冰淇淋,如果有一大桶冰淇淋,就可以從中一勺勺的挖出你們想要的, 大桶冰淇淋可以挖出各自的服務和業務邏輯,然後就可以在不同的流程中單獨執行和部署;

第二種則是樂高法(搭積木),這意味著我們並不會完全擺脫原本的單體應用,這種通常適用於比較老舊的專案;
但新的功能將會以新的架構進行打造;
所以你必須找到一種能夠讓微服務與過去老的應用重新建立聯絡的方法,不然這將很難過渡;

第三種我稱之為nuclear法,這也意味著我們從頭開始打造一切

在轉型為微服務架構的過程中,我們需要去維護原本的單體應用;
從向微服務轉型的第一天開始起,我們就不能從零開始開發,因為它是最差的選擇;
這需要一支實力強勁的技術團隊,同時也需要根據實際情況來確定技術邊界 當你有兩個不同的團隊同時工作的時候,一個可以持續交付,另一個團隊則將專案重構並微服務化

當我們重新構建這個新的程式碼庫時,會將舊程式碼庫的功能重構到新程式碼庫中,這裡 問題來了,我們該在哪裡去建立新功能,因為此時我們的業務依然基於老程式碼庫執行,並沒有使用新程式碼庫;

也就是說,我們遇到了一個很複雜的情況,難以解決,所以,我們千萬不要拋棄一切,從0開始。接下來就是我們今天要探討的冰淇淋策略;

舉個例子,我們有一個物件導向的單體服務架構,它具有我們所需要的所有的功能,這些功能通過不同物件和類在這個單體服務架構去互動實現;

不同的服務共用了同一個資料庫。如果想要擴充套件這個單體應用,那麼我們只能部署更多這個單體應用的例項 (為了緩解某個擴充套件服務的壓力,其他服務被動進行不必要的水平擴充套件,增加了複雜性);

如果這個單體應用是個電商網站,比如我們常見的amazon.com,那我們會有很多不同的服務,比如使用者管理,訂單管理,庫存管理,站內搜尋等;

這就是一個典型的單體服務架構案例,在這張圖裡,每個單獨的方塊代表了一個不同的業務邏輯

因為這是一個規模很大的單體服務架構,我們需要很多團隊一起去維護它 在這個案例中,有三個不同的團隊在對這個單體應用進行維護,為其建立新功能並將它們投入到生產環境中;

現在相信你們現在也知道了單體架構和微服務架構的一些利弊。在單體架構中,會出現一個問題 如果其中一個開發團隊對其進行頻繁的修改提交,那麼就需要在其他團隊之間進行大量的協調,以便在生產環境中正確部署這些改變;

隨著程式碼庫變得越來越大,產品開發團隊也同樣如此。隨著時間的推移,問題會變得越發嚴重。這會嚴重影響我們新版本釋出週期的效率;

當團隊2(有多個團隊一起開發)也開始頻繁的變更程式碼的時候。遇到的問題更復雜,此時,我們該如何改變現狀?

因為團隊2在為搜尋服務,庫存以及其他模組進行開發工作,如果某個模組需要很多迭代,我們該怎樣將這個模組抽取出來(進行單獨開發);

所以我們所用的冰淇淋策略就是從單體架構中提取出業務邏輯,並將其獨立出來;

這些服務都非常重要,但它們並不是微服務。這就是今天我們需要做的工作即將它們逐漸改造成微服務;

我們要確保所抽取出來的新服務能夠不依賴原本老系統所使用的資料庫;

我們的初衷是希望所抽取的新服務真正的獨立;

如果老系統對資料庫進行了過多的請求;

那麼資料庫將變得不可用;

因為我們不想讓服務受到影響,所以我們想要對服務進行分拆和隔離;

然後我們在生產環境下試執行,接著,當遇到一個或多個部分(這裡指圖中的方塊)也需要進行大量修改的時候,指出並將它們抽取出來;

所以我們現在有三個不同的服務(如圖所示),一個是我們的老系統,其次是一個稍大的服務,最後是一個小服務;

從實際出發,通過一次又一次從單體應用中進行這種服務抽取的操作 或者是從已分離的服務中進一步抽取使之粒度變得更小,以此來解決我們當下所面臨的問題;

整個迭代過程不可能一次全部完成,我們只能以務實的態度去一步一步針對所抽取的業務進行敏捷開發;

通過這種循序漸進的過程,我們可以順帶去修改這個專案組織中的其他相關邏輯;

以此來給專案的後續迭代提供更多的解耦支援;

實際上,在過渡的過程中,這就是一個重構,類似於我們以前在單體服務架構內部進行服務的重構。在這我們有一些事需要去明確;

第一件事,我們需要理解這個模型是什麼。如果我們都不理解這些程式碼做了什麼,那對我們而言就很難去確定服務邊界;

你們知道大部分的單體架構服務的邏輯都過於耦合。正因如此,我們才需要去明確服務邊界並解耦服務 如果我們都不知道這些,那我們就根本不可能抽取出來;

為了能夠重構老系統,我們也需要去理解現在系統中使用的client,以及如果當錯誤發生時,會對客戶端產生什麼樣的影響;

在微服務轉型前,我們需要知道哪些服務會受到影響;

我們所以做的第三件事就是像其他所有重構一樣,需要通過整合測試去驗證我們想要修改的邏輯是否正確 以此來確保我們的重構不會對原本的系統產生影響;

我們希望在不影響系統內部執行的情況下,來擴充套件我們的系統;

我們不想要中斷(影響)必要的服務,至少我們不能同時去擴充套件或者改變業務邏輯,這隻能一步一步來;

當老系統在執行時,有一些事情,可能就是一個小方法的改變,那麼我們就沒有必要去將它和之前一樣去進行相同的擴充套件;

比如,升級我們的客戶端或者為了將請求正確路由到不同的服務而去更新路由;

客戶端會對我們的單體應用進行請求,但現在那些請求不再由我們的單體系統處理而是通過其他服務去處理。所以我們該如何重新路由這些請求?

在傳統業務模型中,我們會在客戶端與服務端之間放置一個負載均衡器(比如nginx)

比如我們的客戶端可以是個移動端程式,當我們部署單體系統的時候,我們只需在負載均衡器之後執行此應用的多個例項;

但隨著我們系統一步步抽取解耦形成很多微服務,我們就需要將整個執行架構的某些方面更加智慧化才行;

首當其衝的一件事就是需要採用一個靈敏的API閘道器;
如果這個閘道器能做到智慧化負載均衡;

那麼當我們解耦服務後,我們就能將API閘道器作為服務端與客戶端之間的代理並實現功能路由。 這就可以使得我們無須升級客戶端即可將請求路由到這些新的服務下。這對我們而言十分重要 如果我們不這麼做,那就必須升級客戶端,原有的版本就會出問題,客戶體驗就很差,也就說會對我們的業務產生很不好的影響

客戶端到服務端之間的代理也就是閘道器,它必須足夠智慧化才能夠幫助我們處理我們架構上的一些操作 像我之前說的向微服務過渡,這並不僅僅是技術上的採用例如我們說的kubernetes,同時也是運營管理上的過渡;

我們不能以部署單體應用的方式來部署微服務架構和SOA架構;
我們需要通過一些策略來降低風險;
比如,一個服務的新版本出來了,我們可以通過使用灰度釋出的策略將10%的流量導向新版本的服務;
只有當穩定了,我們才能將流量完全的導向新版本的服務上同時擺脫掉舊版本服務 與此同時我們也需要繼續保持舊版本的執行,以防我們需要回滾到前一個版本;

在深入探究微服務和service mesh之前,我想花點時間去闡述下hybrid和multi-cloud;
當微服務化的時候,我們就需要採用像kubernetes這樣的平臺來執行我們的服務;
因為我們還有不少服務還在老系統上執行,所以我們不會在kubernetes中執行所有的服務 我們仍然會將老系統在我們之前使用的平臺執行,例如虛擬機器;
當我們計劃向微服務轉型的時候,我們必須制定一個策略來將新老應用平臺進行一個有效的連線;
我們沒有辦法在一夜之間將所有東西都執行在Kubernetes之上;
所以,我們該怎麼做才能將kubernetes上執行的服務和原本的老系統的相關依賴服務重新建立聯絡;
就如我之前所說,這裡將整個組織想象成一個複雜的人體組織 那麼我們可以想到,不同的團隊,產品以及業務需求,它們共同的目標都是(所開發的程式單元)要成為彼此獨立的存在;

從更高層次的角度來看,整個組織沒必要非要用hybrid ,也沒必要非要用Multicloud,這需要有一個自上而下的決定;

一些公司的專案組織已經執行在不同的雲平臺上,之所以採用了hybrid 和 Multicloud 也就意味著隨著時間的推移,這些不同的團隊根據專案組織的需要選擇了不同的雲平臺;

從更高層次的角度來看這些公司的整個專案組織,它們為什麼採用hybrid cloud,這已經不是因為他們想要用,而是他們不得不用;

從理想的角度而言,我們想將所有的服務都放在同一個平臺執行;

但我們還是要面對現實,當下的情況是,我們需要將多個系統執行在各個地方 所以我們需要有一個抽象級別更高的架構,在這裡我們需要有工具可以管理這個專案組織下的 Multicloud與hybrid

服務粒度

隨著我們從這個單體服務架構中抽取出越來越多的微服務

我要給一條建議,結合當下的目標,以合理的方式來確定微服務邊界 我認為是十分重要的。這是我在那些已經十分成功的抽取案例中所得到的經驗;

就像我之前的例子,我們不能將微服務化一步到位 我們可以將一個相對較大的服務抽取出來,然後隨著時間的推移一步步解耦它,使之變得越來越小

當我們在看待Service mesh和微服務架構時,理想情況下,這些服務都應該是很小的 並且會以相同的方式互相連線起來。

但現實是,這些服務的大小都取決於我們以最好的方式來達成的業務目標所產生的規模;
我們不要為了追求微服務而強行使用微服務,有時候我們需要的可能是一個比較大的服務;

網路

ok,現在我們通過解耦得到了很多微服務,這些解耦的微服務由不同的團隊獨立建立並獨立部署 需要強調的是,這些服務不能單獨存在,它們需要通過彼此交流才能執行;

so,我們將放棄在單體應用中一些使用方式。我們基於程式碼庫中的物件(這裡的物件是指介面實現類,不是我們的POJO) 介面和函式呼叫,通過完美執行這些函式呼叫,我們可以呼叫和訪問不同的物件;

但是當我們將它們解耦成微服務時,這些介面實現類物件變成了服務;

介面仍然存在,但所有微服務間的訪問將通過網路來進行;

舉個例子,在一個Java單體應用中,當執行一個函式呼叫時(呼叫所定義介面中的方法) 因為底層是基於JVM,我們完全無須擔心這個呼叫,它會被成功處理, java虛擬機器將接收呼叫,並將該呼叫路由到正確的實現類中;

但是在微服務中,我們將無法做到前面這種;

因為我們將通過網路來進行函式呼叫,所以我們將無法保證這種函式請求會在網路中具體哪個地方進行呼叫;

在我們的系統中,網路是一個非常不可靠的因素。網路可能會很慢,有延遲也有可能當機 總之網路和單體應用層面不同的是它會有各種各樣的問題來影響我們的系統服務;

在微服務架構體系中,我們會有不同的團隊來執行和部署這些服務;

團隊的思維方式也需要進行改變;

在單體應用中,它有兩種狀態,工作或者當機;

但是在微服務中,任何時候,如果一個服務在執行過程中出現了問題 此時,我們應該改變思維方式,即這裡應該有一個服務降級,也就是我們的架構中應該有服務降級這一部分;

因為這些不同服務中的每一個都會出現問題,我們會建立的越多降級服務,團隊可以將它們各自進行獨立部署;

同時,在組織結構上,我們的專案團隊也要改變相應的思維模式;

在某個時刻,服務一旦發生問題,服務降級系統必須制定該如何進行處理,同時為終端使用者提供一個非常好的體驗;

為終端使用者所做的這些所有事情,並不是為了我們自己,我們這麼做是為了給終端使用者提供一個更好的產品體驗;

延遲

接下來講延遲,API 間呼叫產生的延遲我們我無法忽略;

我們都知道,網路延時十分重要,對於傳統的移動端到單體應用訪問來說;

如果移動端App訪問我們的系統時延遲達到數百毫秒,這個對我們而言 狀況並不樂觀,我們可以通過CDN或者快取來降低延遲,改善網路處理的速度;

在微服務中,延時的產生是由於不同的微服務間的相互的請求越來越多,服務A在消費 服務B在消費,服務C也在消費,可以看到,這就會產生服務間相互呼叫的延時問題;

在微服務中傳輸架構中,一旦一個基礎服務發生了服務當機,呼叫當機服務的呼叫方也會因此而發生新的當機 在一個單體的服務架構中,一旦一個服務產生異常則和它相關的呼叫都會發生異常

在微服務中,當產生響應超時,這會影響其他相關微服務,產生鏈式反應,情況就好像整個系統不再工作一樣;

所以延遲是我們需要去解決的首要問題,這不是我們事後想fix就fix的 就像安全和效能,這兩個不是功能元件,我們沒辦法後續新增 我們只有在編寫系統的時候時刻保持這個意識,如何寫才能保證效能,如何寫才能保證系統安全;

安全也成為其中的另一個組成部分(如圖所示),所以現在我們在網路上擁有的所有這些通訊,我們希望能夠加密並保護這些互動;

例如,通過強制實施雙向TLS或者在不同服務間使用你所知道的方式來加密網路通訊;

順帶說一下,這些服務沒必要非要通過restful api來執行;

我們可以去使用任何一種對我們所在場景有利的傳輸協議,你們可以用rest或者gRPC或者其他任何一種傳輸協議;

我們不受限於任何一種特定的傳輸方式或者協議,我們需要知道該如何去透明地保護和加密這些所有的通訊;

就像我之前提到的路由,現在我們有不同的服務,我們該怎樣在一個系統的某個地方設定路由服務 路由到我們不同版本的服務上,將請求路由到那些我們部署在不同雲主機的微服務;

同樣如果我們的服務不再執行的時候,此時我們需要進行異常處理 我們需要能夠將請求到這些不工作的例項或者服務的通訊打斷。所以在這裡我們需要斷路器和health check;

在單體服務架構下,我們沒有必要非要設定斷路器或者是health check 但當規模達到一定程度例如跑一千個單體應用的時候,它們就變得極為重要 如果從一開始我們沒有這麼做,那麼我們在過渡到微服務這條路上就會變得岌岌可危;

同樣,可觀測性也和之前在單體架構服務中不同 在單體架構中,我們不需要關心請求會去向哪裡(因為很明確), 但是現在在微服務架構中,我們必須知道;

因為我們需要能夠去定位我們微服務架構中的薄弱環節 所以我們需要追蹤從一個服務到另一個服務的請求,以及收集效能指標和日誌 這樣才能便於我們理解在任何時候微服務做了什麼,以及如果出現問題的話,定位出錯的位置;

在沒有確定服務邊界的情況下,很難去向微服務過渡 因為在某一點上不可避免地會出現問題,而我們將無法使用合適的工具來挖掘並找到問題所在;

Service Mesh Pattern

讓我們接著討論Service Mesh

首先,Service Mesh並不是一種技術,而是一種設計模式,我們可以通過各種各樣不同的方式來實現Service Mesh

但是通常,我們會有一個代理與我們的服務一起執行,通過這些代理可以將不可靠的網路變得可靠;

基於此,我們在構建我們的服務時就不需要擔心如何處理延遲問題、observability(可觀測性)和雙向的TLS等等;

因為連線點不再是服務到服務,而是Data Plane(DP,資料平面)到 Data Plane;

這些點通過外部網路進行聯絡,其實就是這些連線點通過Data Plane進行通訊;

同時,由於Data Plane可以在服務無感知的情況下執行邏輯,那麼我們可以在此進行異常,延遲以及可觀測性處理;

在一個Service Mesh中,Data Plane既是代理也是反向代理,這取決於請求的去向;

例如,如果這個服務想要呼叫那個服務,那麼這個Data Plane將作為一個代理 因為(這個)服務正進行的請求將通過那個Data Plane進行代理;

但是當那個Data Plane收到請求,那個Data Plane將充當一個反向代理,它將接收請求並將其代理到與之關聯的服務;

我們需要有一個Data Plane,我們可以通過不同的方式來實現Service mesh 每個底層虛擬機器或者每個你正在執行的服務的副本都可以擁有一個Data Plane;

後者被稱為Sidecar迴圈代理,因為我們將為每一個伺服器上的服務例項提供一個Data Plane例項;

這裡會有一個觀點,不論我們每個副本擁有一個Data Plane,還是每個底層虛擬機器擁有一個Data Plane都是一樣的 這個觀點就是,每當有一個服務到服務的通訊,首先會將通訊轉到Data Plane,然後由Data Plane接收;

這些服務不再是直接相互通訊,而是必須通過這個不一樣的系統(Data Plane) 這允許我們在Data Plane中實現額外的邏輯,也就是說服務無感知是最好的 因為所有雙向TLS、所有的可觀察性操作都是開箱即用的,團隊無須在服務中構建它們;

如你所見,這些Data Plane作為聯絡點,通過這些連線點我們可以做很任何事 包括將資料庫納入這個系統管理中。也是因為當一個服務使用資料庫時,我們仍然想要這個使用過程進行觀察 我們仍希望擁有Data Plane提供的所有功能,這樣一切都將通過Data Plane進行交流;

因此,我們通過分散代理在不同服務中進行著大量的網路呼叫;

之所以被稱為分散式,是因為不像傳統的ESB那樣,我們沒有將代理例項中心化,而是分散到各個服務中;

Kubernetes定義

so,我剛才提到的Sidecar代理,這會我們應該知道它是什麼了吧。接下來,我們回到關於Kubernetes的定義上來;

Kubernetes將我們在底層虛擬機器上部署Pods的方式進行了抽象;

我們通過使用kubernetes來把我們的虛擬機器群變得看起來就像一臺主機來使用;

Kubernetes將決定這些Pods的去向;

當我們告訴kubernetes我希望這個代理是一個sidecar容器;

對於這種指定服務容器的其他pods來說 我們告訴kubernetes我想要將這個代理部署在這些服務所在的底層虛擬機器上(即每一個服務所在的pod中都有一個sidecar容器);

我們希望Sidecar代理始終部署在底層虛擬機器上,因為我們希望服務和代理之間的通訊始終在localhost上(適用於每一個副本);

假設是因為在localhost中它(通訊)的成功率總是100%;

因為我們沒有離開這裡(進入到外部網路)而是一直在虛擬機器中;

在這裡和那裡之間的網路問題將由Data Plane處理 (譯者特別說明:sidecar是用於Kubernetes的,而Data Plane用於service mesh兩者所處位置不同,請注意);

我們將擁有該代理的一個例項,融合了我們服務的每個例項的Sidecar模型;

現在,這增加了Data Plane中的問題,Data Plane真的要保持很小的資源利用率,並且在佔用上必須非常小;

因為我們將在我們的系統中為每個服務的每個副本都執行一個(代理) 這意味著如果代理本身消耗了許多資源,我們將耗盡記憶體資源(例如在底層虛擬機器中);

所以如果我們採用的迴圈代理越多,我們就要確保這個代理非常非常小,資源佔用很小;

順便說一下,對於我們自己的服務同樣如此,不能佔用太多的記憶體 否則,要麼我們執行在非常大(記憶體)的虛擬機器,要麼我們將很快耗盡記憶體;

因此,在資源利用方面,服務和代理都必須非常的小;

這也是為什麼不能將ESB放在那裡的原因;

你可以想象為每個服務例項執行一個ESB例項,你的服務就甭指望工作了;

現在,我們希望這些不同的服務都執行在不同的Data Plane上,然後我們需要儘快對這些Data Plane進行配置;

當我們的服務在進行通訊的時候,其實就是這些Data Plane在依賴我們設定的協議證照進行交流 從整體來看,整個協議很複雜,我們自己很難去和它們做交流(我們需要做很多潛在準備,一不小心就容易出問題);

所以,我們不希望通過人工的方式來將配置推送到這些不同的Data Plane上;

這裡我們說的就是Control Plane(控制層)了;

Data Plane和Control Plane在網路層處理這塊兒是非常非常有名的

(例如)你在資料中心執行了一堆Cisco交換機,並且你想要將你的配置推送到這些Casco交換機上;

於是我們想要一個可以允許我們這樣做的Control Plane;

把相同的概念應用到軟體上來;

我們通過一個Control Plane把配置推到每一個Data Plane中;

或者是這個Control Plane可以讓Data Plane從一個統一的地方獲取這個配置;

但它也可以成為我們收集指標(執行引數)的一種方式;

現在,Data Plane正在一次性收集所有的這些流量(通訊行為) 我們希望有一個元件,允許我們收集日誌、收集指標,並且仍然是在Control Plane上;

Data Plane位於請求的執行路徑上;

Control Plane僅用於配置,它僅用於獲取這些指標,Control Plane它永遠不會在我們的API請求的執行路徑上;

基本上,我們的north-south gateway只是成為了另一種Data Plane,是另外一種代理 它不是我們的Data Plane,但是允許我們與底層Data Plane進行通訊;

因為它們都是這個Mesh中的一部分,我們可以在這些不同的Data Plane間強制實施雙向TLS,確保我們的系統受到保護;

即便沒有service mesh我們依然可以做這些事情,那這樣的話,我們就不得不在自己的服務中通過構建來做這些事兒了;

從技術上來講,微服務並不一定要必須通過Service mesh來做。但問題在於,如果你想擁有這些優點,就必須自己構建它們;

並且在service mesh中也不一定需要Kubernetes,但service mesh的理念能夠應用於任何平臺;

kubernetes 只是讓我們更容易大規模地執行微服務,但沒有什麼能阻止我們跨虛擬機器來執行service mesh;

我們只需要在服務執行的虛擬機器上部署我們的data plane例項,這樣我們就擁有了一個跑在虛擬機器上的service mesh;

事實上,我們更想要的是service mesh能夠執行在Kubernetes 中;

但就像之前說的,我們目前依舊有單體應用執行在虛擬機器或遺留的平臺上;
並希望它通過某種方式能夠成為serivce mesh中的一部分 所以我們希望資料平臺不僅僅是在kubernetes 中,還要執行在我們單體應用的環境中;

我們希望這種模式(上述的單體應用)也可以成為service mesh的一部分;

如果你想讓轉移到微服務變得更加實際,那麼平臺無關性無疑是非常重要的;

就像之前說的,不同的服務可以建立在不同的語言上,這就是微服務的優勢之一;

因為我們可以將依賴性很小和功能獨立的服務構建在data plane上,這意味著我們不用重複的去做相同邏輯的事了;

在兩種不同的技術編寫的兩個微服務中,data plane就屬於一個對外處理的代理,它和對應的微服務一起執行在同一個虛擬機器中;

基於事件的架構

我再花點時間來談下基於事件的架構

當我們討論 service mesh ,即在討論微服務時,通常會討論服務之間的通訊,但這不是實現這些系統的唯一方式;

還有另一種方式是採用基於事件的體系結構來建立它們;

這意味著,我們將在架構中傳播一個事件,用更有效的方式來處理諸如捕獲狀態之類的事情;

這裡假設有兩個不同的微服務,一個做訂單和一個開發票;

每次我們建立訂單,再開一張發票,聽起來不錯;

但是,如果一些原因導致發票微服務變得不可用了,我們會繼續重試直至請求超時;

最終發票不會被建立成功,當然最好不要出現這種情況;

如果它真的發生了,那麼系統中狀態的傳播就會被中斷,事後需要花很大的代價去修復;

因此對於上述案例用狀態進行傳播的方式,我們可以考慮使用事件;

例如讓發票的微服務就緒之後再去處理訂單建立事件,這樣我們的狀態就不會丟失了;

這種方式的風險在於,我們可以用例如kafka之類的當做事件收集器,但系統中的其他服務可能真的會發生一些異常情況;

所以希望在這些服務前面有一個data plane,因為我們想要確保服務事件能夠到達事件收集器(kafka);

所以我們可以採用Kafka或某種日誌收集器來處理我們的一些用例,當然必須確保日誌收集器可用,不會發生故障;

通常我們更容易將精力用於保證一項服務的正常執行(例如日誌收集),而不是將它放在給每個服務傳播狀態資訊上;

因為我們只有一個元件的話只需要確保它能正確持續執行,相反,如果元件很多,那麼所有的元件都必須處於正常執行 我們可以集中精力讓執行變得更加可靠一點,使得狀態的傳播也變得更加可靠;

就像我所說的企業組織架構正在轉變,而我們的系統也逐漸往一個複雜的生命體方向靠攏,因此我很喜歡用神經系統來做比喻;

我們的身體由大腦中的CNS(中樞神經系統)和PNS(周圍神經系統)兩個不同組成部分組成;

周圍神經系統將我們身體能夠理解的所有資訊存起來,然後將它們傳遞給CNS(中樞神經系統),以便CNS(中樞神經系統)可以處理它們;

這與 control plane 和 data plane 的概念非常相似;

data plane將位於我們每個服務,每個單體應用的外圍,以及每個函式式(例如lambdas)的外圍;

但是相關配置,監控以及可觀察性,都將由control plane處理;

Kong做了什麼

我之前說過 我是Kong的聯合創始人兼CTO, Kong提供了一個有效地開源 control plane和data plane,可以允許在組織中進行不同架構的管理;

在全球範圍內執行著超過一百萬的Kong例項來幫助開發者進行data plane管理 我們給那些需要進行架構轉變的團隊提供了技術支援以幫助他們從單體架構到微服務到 Service Mesh 到Serverless的過渡;

過渡到微服務是一個很複雜的課題,因為它影響了三個不同的方面:

但更重要的是我們必須將這個過程和我們要達成的業務目標相結合,不然就像我說的,它只是依葫蘆畫瓢,為了使用微服務而微服務;

首先是業務轉型
我們必須實事求是,如果沒有必要,我們不需要立馬轉型微服務或者立即擁有數千個微服務
主要在於我們總是有時間來將服務變得越來越小;
因此,不必那麼著急,先將服務提取到中等大小,然後隨著時間的推移使其變得更小;
事實上,我想說只有當服務需要變得更小的時候,那麼我們才能將它變得更小。這才是最好的過渡方式;
因為它既可以提高我們的生產力,也增強了我們的業務;
通過採取使用技術的方式,使我們能夠向這些新架構微服務過渡;
但也可通過一個非常務實的方式連線現在正在提供業務服務的老應用程式(程式待重構);
那些仍然是最關鍵的元件,將它們與我們新的greenfield (新開發的)微服物架構連線起來,這將成我們系統的未來;
所以這需要在新舊之間建立聯絡;

提問

所以你們還有其他問題嗎?

提問部分:就比如說又一個單體應用,按照演講者之前講的意思將服務逐步解耦使之變得越來越小 Amazon就表示對他們來說這樣做就會代價很大,於是他們就中途放棄 直接重新開始,直接開始全面微服務(拋棄原有的系統),對此你有什麼看法?

就像我說的,這其實也是一種選擇。只要企業/開發團隊已經準備好能做全面微服務化的準備 同時也有著清晰的思路,那麼這種過渡到微服務的方案也是可取的;

在採用那個方案的時候,我們必須分析利弊。當然,Amazon通過分析他們的利弊 如果選擇重新打造而不是從單體應用慢慢過渡到微服務,這種情況下,利遠大於弊;

在我看來,它仍然是一個很少有公司能夠成功過渡到微服務的策略;

當然這些事情我們也需要納入考慮;

提問部分大致意思:微服務間存在著大量的呼叫 然而我們通過Data Plane進行網路通訊的延遲遠高於服務與服務之間的本地呼叫,有沒有什麼降低延遲的辦法?

系統可以為我們提供指標,用以瞭解延遲瓶頸的正確位置 所以如果我們需要通過網路,我們將得到比通過本地函式呼叫更多的延遲,這是可行的;

實際上,如果代理沒有正確建立,這個網路處理就會增加更多的延遲;

因為你知道的雙向TLS 以及可觀測性操作都會在我們的處理過程中增加延遲;

所以我們可以做的就是在Data Plane層快取一些資訊,這樣請求可能就不需要進入到外部網路中,所以我想到的是 在這些不同的服務間組織實現某種意義上的全域性快取,假設這的方式是可行的,因為對於某些用例(場景)我們是無法實現(快取)的;

而對於其他人而言,他們完全接受了最終一致架構的概念,延遲只是它的一部分;

並且客戶端就是這樣建立起來的,他們考慮到了這一點,所以一切最終都是一致的,會有一點延遲 我們將在客戶端看到資訊,它不一定是最新的,但它最終會保持一致;

在考慮延遲問題的時候,Service mesh能夠通過一系列方法來幫助我們定位延遲問題,這不僅僅只是網路延遲,同樣也可能是服務延遲;

我們為了能夠確定是否必須對那些已經對其他服務產生效能瓶頸的服務進行升級,所以需要一種觀察的機制 這樣在實際使用中,這也能讓我們實現一些快取方法去提高我們架構的效能;

當然,因為我們是基於網路去請求,所以我們應該從實際出發 去分辨哪些延遲是正常的,哪些是不正常的。如果不正常 那麼我們就必須確保系統的最終一致性,並以此為前提,我們來構建我們的客戶端;

相關文章