日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

本文是對幾年前我在公司做的服務框架的梳理。

本文假設你已經了解了什么是服務化,只闡述針對現有的服務框架所存在的問題,如何根據實際需求去考量并解決對應問題。

首先,我們先來聊一聊服務框架的核心RPC!

RPC

RPC全稱是Remote Procedure Call,即遠程過程調用。它和HTTP不是同級的概念。HTTP是協議,而RPC是一種遠程調用方式。它可以基于HTTP來實現,也可以基于TCP來實現。

從RPC到服務化框架

 

乍看之下RPC不就是個客戶端調用服務端嗎?實際上它確實就是客戶端調用服務端而已,只不過,在大部分情況下,RPC在調用時看起來像是在調用本地方法/接口。

從RPC到服務化框架

 

注意看上面的Consumer Stub和Provider Stub,這里可以理解為是代理,即

  • Consumer和Consumer Stub交互
  • Consumer Stub通過RPCLibrary將調用內容序列化,通過網絡傳輸給Provider端
  • Provider端反序列化,然后根據傳遞的內容去調用實際的方法
  • 接著再將結果序列化后,通過網絡回傳給Consumer端
  • Consumer端接收到數據后,再反序列化獲取到結果,然后進行后續的操作

一個具體的例子可以看SpringCloud套件中Feign的使用。

如下圖所示,這里通過Feign定義了一個接口

從RPC到服務化框架

 

可以直接通過方法調用的方式來調用,看起來和調用普通方法一樣沒有任何區別。

從RPC到服務化框架

 

這里實際上就是進行了上面所述流程的操作,具體的源碼流程,可以自行梳理,并不復雜。如果比較懶,可以等我后面SpringCloud的源碼梳理,不過時間未定!

解釋完RPC,我們就來看一看服務化框架。

服務化框架

上面所說的RPC還遠遠達不到框架的程度!

首先,Consumer是需要知道Provider的地址信息的,否則它無法將消息發送給Provider。這會導致什么問題呢?所有的Consumer都需要維護Provider地址信息。假設Provider地址信息發生了變化,則所有的Consumer都需要修改對應的配置信息。

從RPC到服務化框架

 

其次,Consumer和Provider之間是直連的,假設Provider多了以后,則Consumer與Provider之間的連接將會很多,要人工維護會非常的麻煩。

從RPC到服務化框架

 

另外,還有一個問題,Provider地址信息是配置到Consumer中的,那如果Provider掛了該怎么辦?如何去除Provider的單點問題呢?

最后,Provider升級后,Consumer該如何處理?

如果你熟悉分布式系統的話,那答案是顯而易見的,就是引入注冊中心。

從RPC到服務化框架

 

  • Provider啟動后將自己的信息注冊到注冊中心,注冊中心接收到消息后,將新的Provider信息列表推送到已經連接上來的Consumer
  • 同時Consumer啟動時從注冊中心獲取Provider注冊信息
  • Consumer內部實現了負載均衡,通過負載均衡算法,來選擇合適的Provider來發送請求

服務框架的功能

上圖的Consumer,Provider和Registry實際上就是一個服務框架所需要的三個必要組件。而一個較為完善的服務框架,需要至少提供如下功能:

從RPC到服務化框架

 

實現

當初編寫這個服務框架實際上是為了解決幾個問題:

  • 一般服務框架的升級問題
  • 服務元數據管理問題
  • 模塊化服務開發

我們從「服務升級」這個場景開始!服務升級應該算是服務化里最基本的功能了,我們以dubbo為例,看看使用dubbo框架的情況下,如何進行服務升級?

一般服務升級可以分為兩種情況:

  • 服務修改保持兼容,也就是說接口不變,實現改變。
  • 另外一種情況是服務修改不兼容,即接口也改變了。

我們先看第一種情況,當服務保持兼容的情況下,我們的升級流程大致是什么樣的!以下圖為例,我們有三個服務節點和兩個客戶端:

從RPC到服務化框架

 

 

  • 首先,停止一個服務節點,發布新服務,啟動服務節點
  • 然后,再停止一個服務節點,發布服務,啟動服務節點
  • 直到所有的服務節點都更新完成

而當服務不兼容的情況下,升級流程大致是這個樣子:

  • 停止一個服務節點,發布新服務,啟動服務節點。并保證當前客戶端無法訪問到這個新服務
  • 升級一個客戶端到新版本,并將調用指向新服務
  • 重復如上步驟,直至全部發完

從上面的流程,我們可以發現如下幾個問題:

  • 頻繁重啟容器,累積耗時很長:服務發布需要重啟容器,而容器中一般不會只有一個服務,發布一個服務需要啟動整個容器,耗時會比較長
  • 對同一服務節點下的其他服務有影響:上面提到一個容器下一般不會只有一個服務,當重啟這個容器時,該容器內的其它服務也無法對外服務
  • 在進行升級的過程中,會導致服務容量減少,相對的負載增加:在服務節點停止后,無法對外服務,原本路由到該節點上的請求被分配到了其他節點上,變相增加了其他服務的負載壓力

對于這個問題,我們該如何解決呢?

其實很簡單,

  • 重啟容器會使發布時間變長,那我們就不重啟容器,直接發布服務,也就是「熱部署」。
  • 而對于不兼容服務的發布,我們可以通過版本管理來處理。
  • 另外,我們希望能模塊化的開發服務,使得服務能像積木一樣的組合

對于如上的問題和需求,我們如何解決和實現呢?

如果你熟悉JVM的話,其實第一個想到的方法應該是自定義ClassLoader!而在我們服務框架的早期版本里,是使用OSGi來實現的。

現在應該很少有人了解OSGi了!在JAVA模塊化出來之前,OSGi是Java模塊化編程事實上的標準。eclipse就是基于OSGi來實現插件化的。

OSGi默認就提供了多版本管理,動態部署,模塊化管理等功能(看起來很契合我們的需求)。它也是通過ClassLoader來實現的,不過和我們已經很熟悉Java的雙親委托模型不同,OSGi自己實現了一套網狀的ClassLoader結構,通過這樣的結構OSGi實現了上述功能。

從RPC到服務化框架

 

我們來看下,在基于OSGi實現的服務框架下,服務發布的流程變成了什么樣:

假設當前服務版本是1.0.0,欲發布2.0.0版本

  • 直接將2.0.0版本的服務添加到服務容器中,自動啟動、注冊、推送
  • 客戶端目前版本為1.0.0,服務端目前包含了1.0.0和2.0.0版本的服務
  • 客戶端會查找最符合要求的服務進行調用:
    • 如果版本號一致,則調用版本號一致的服務,
    • 否則調用版本號最新的服務。目前客戶端會調用1.0.0版本的服務
  • 如果服務是兼容的,則可以直接卸載1.0.0版本的服務
  • 而不管服務兼容不兼容,通過將客戶端升級到2.0.0版本即可完成服務升級.1.0.0版本的服務可刪可不刪,因為目前沒有請求會調用它了

最終服務框架的架構如下,客戶端,注冊中心,服務端和其它框架無異,主要區別在使用了OSGi來作為服務發布的容器。

從RPC到服務化框架

 

新的問題

這樣看起來很完美,OSGi完美的實現了我們的需求。但是實際上,在實際使用過程中還有很多新問題:

  • OSGi增加開發復雜度

前面說了OSGi提供了多版本管理,動態部署,模塊化管理等功能。而相應的帶來了開發復雜度的提高。OSGi通過METAINF.MF文件來配置相關信息,而這些信息在Java中是靜態的,通過這些信息,OSGi在運行時處理版本、導入導出等信息。導致的問題就是,開發修改了METAINF.MF文件后,不部署到OSGi容器內,無法確認配置是否正確。而每次發布都要打包,大大降低了開發效率。且由于需要發布到OSGi容器,所以只能遠程調試。

如何解決這個問題呢?是繼續為了使用OSGi帶來的便利而忍受其帶來的開發復雜度,還是放棄OSGi呢?

其實我們使用OSGi,需要的是它的多版本管理和熱部署功能,模塊化并不是強制需求,是我們的美好愿望,為了這個美好愿望犧牲開發效率值不值得呢?這是個問題。

最終我們放棄了OSGi,而使用自定義ClassLoader的方式來實現版本管理和熱部署。

大致結構并不復雜,主要在ApplicationClassLoader下增加了BaseContainer和ServiceContainer,其中ApplicationClassLoader加載服務節點應用,主要負責通信,BaseContainer加載一些公共服務,例如日志,數據源等服務。ServiceContainer加載業務服務,在ServiceContainer加載的服務中,有一個比較特殊的服務,我們稱為系統服務,它的作用是用來發布其他服務,具體作用后面再說。

從RPC到服務化框架

 

  • 耗時服務導致超時

我們使用netty作為服務框架的通信框架,實現的是從Reactor模型,在服務端獲取到客戶端請求后,會首先將其丟到一個隊列中,由消費線程去異步處理請求,如果某個服務耗時比較長,則會導致隊列阻塞,影響其它的服務響應。這個問題在其他的服務化框架中應該也是存在的。在新版服務框架中,我們可以將耗時服務獨立到一個隊列中進行執行,使該服務不會影響其他服務的正常調用。具體操作只需要在提供的界面做些配置就可以動態調整了。

從RPC到服務化框架

 

  • 服務發布分散

在我們發布服務時,我們需要登錄每個需要發布服務的機器,進行發布服務的操作。公司的運維平臺提供了界面可以操作發布,不過它是個運維平臺,而不是業務平臺,發布完成后如何確認服務都注冊成功了呢?新版服務框架中提供了管理中心,實現在一處發布所有的服務。流程如下:

  1. 管理中心通知需要發布服務的節點,將需要發布的服務信息發送給節點
  2. 節點收到信息后,從Maven倉庫下載需要發布的服務,進行部署
  • 缺少完善的服務治理

在服務發布完成后,如何確認服務都注冊成功了呢?

舉個例子:我們發布服務A,注冊中心可以看到其下的服務接口1和服務接口2,當我們更新服務A后,注冊中心只能看到服務接口1,那么請問,消失的服務接口2是注冊失?。窟€是版本更新給刪除了?這個問題目前的服務框架都沒有處理。

在我們新版服務框架中,提供了基于元數據的服務監控與提醒,可以配置監控重要的服務接口,如果發布后服務接口消失,則通過監控來進行及時的提醒。

除了上面所說的問題,新版服務框架還提供了完善的服務治理,權重的動態調整,服務自動升降級,服務端管理,客戶端管理等操作。

新版服務框架的架構如下:

從RPC到服務化框架

 

  • 主要將注冊中心升級為了管理中心
  • 管理中心包含了注冊中心,一個WebApp提供給相關人員進行服務管理操作,一個LocalClient來進行通信
  • 這個LocalClient是個特殊的客戶端,主要就是和上面提到的系統服務進行通信,來進行相關的管理操作

在新版服務框架下,所有的操作都可以在管理中心執行,結合公司管理平臺提供的部署與監控,可以實現服務開發、部署、發布的閉環,大致流程如下:

  • 通過管理平臺發布客戶端,注冊中心,服務端。通過相應的配置,發布完成后三者即可通信
  • 在管理中心服務頁面,選擇需要發布或更新服務的節點,進行發布或更新操作
  • 相應節點接收到消息后,從Maven倉庫下載需要發布或更新的服務,進行發布或更新
  • 管理平臺中可以查看服務調用的相關監控,同時如果出現了相關問題,例如上面提到的服務未注冊成功,會及時通過管理平臺通知相關人員

總結

本文主要是對之前開發的服務化框架的設計過程的一個梳理總結,并對一些特殊的考量做了特別說明。

分享到:
標簽:框架 服務
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定