微服務架構之咱們應該從Dubbo中學到什麼

文章首發於公衆號:松花皮蛋的黑板報編程

做者就任於京東,在穩定性保障、敏捷開發、高級JAVA、微服務架構有深刻的理解後端

1、 模塊分包

總體上按分層進行分包,而後每一個包又分API包和具體的方案包,從中提煉出三個須要注意的點安全

  • 1.1複用度
    1) 包中的類應具備相同的重用可能性
    2) 緊密協做的類應放在同一包
    3) 對於變化因子,包中的類應全改或全不改
    4) 變化應在包內終止,不該傳播到其餘包
  • 1.2 穩定度
    1) 被依賴的包老是比依賴者更穩定
    2) 不要讓一個穩定的包依賴於不穩定的包
    3) 單向依賴,無環依賴
  • 1.3 抽象度
    1) 越穩定的包應越抽象
    2) 抽象的包不穩定致使其全部依賴包處於常常的變化中

2、 框架擴展之微核和插件

大凡發展的比較好的框架,都遵照微核的理念, Eclipse的微核是OSGi(依賴META-INF/MANIFEST.MF配置), Spring的微核是BeanFactory,Maven的微核是Plexus,Dubbo的微核是SPI(依賴META-INF/services/com.xxx.xxx配置)。一般核心是不該該帶有功能性的,而是一個生命週期和集成容器,負責加載、卸載、運行插件模塊,這樣各功能能夠經過相同的方式交互及擴展,而且任何功能均可以被替換。若是作不到微核,至少要平等對待第三方,即原做者能實現的功能,擴展者應該能夠經過擴展的方式所有作到,原做者要把本身也看成擴展者,這樣才能保證框架的可持續性及由內向外的穩定性。架構

3、 框架擴展之平等對待第三方

  • 3.1 Dogfoodin-吃本身的狗糧
    1) 框架本身的功能具有擴展點實現
    2) 微核的加載方式也能夠擴展
  • 3.2 Autowire-依賴注入
    1) 裝配邏輯由擴展點之間互助完成
    2) 杜絕硬編碼的橋接和中間代碼
  • 3.3 Cascading-層疊
    1) 層疊擴展粒度,逐級細分
    2) 由大的擴展點加載小的擴展點
  • 3.4 Low of Demeter-最少知識原則
    1) 只與觸手可及的擴展點交互,間接轉發
    2) 保持行爲單一,輸入輸出明確
    3) 一個對象應該對其餘對象有最少的瞭解

4、 框架擴展之Filter-Chain模型

將一個事件處理流程分派到一組執行對象上,這一組執行對象造成一個鏈式結構,事件處理在這一組對象上進行傳遞app

5、 框架擴展以外置生命週期

框架不該該控制實現類的生命週期,框架最多提供工具類輔助管理,而不是絕對控制,應知足下面的規範框架

  • 1. 儘可能引用外部對象的實例,不是類元。正確示例:usrInstance.xxx(),Spring IoC,錯誤示例:Class.forName(userClass).newInstance().xxx
  • 2. 使用IoC注入,減小靜態工廠方法。正確示例:setXxx(xxx),錯誤示例:XxxFactory.getXxx(),applicationContext.getBean(「xxx」)

6、 框架擴展之一致性數據模型

URL做爲Dubbo一個公共契約,全部的擴展點都包含URL參數,URL做爲上下文信息貫穿整個擴展點設計體系。全部的配置信息都轉換成URL的參數,全部的元信息傳輸都採用URL,全部的接口均可以獲取到URL微服務

7、 領域模型劃分

  • 1. 服務域:也稱爲行爲域,做爲組件的功能集,同時負責實體域和會話域的生命週期管理,如Velocity的Engine\Spring的BeanFactory
  • 2. 實體域:表示操做的對象模型,任何產品都有核心概念,圍繞它轉,如Velocity的Templcat\Spring的Bean
  • 3. 會話域: 表示每次操做或運行的瞬時狀態,操做前建立,操做後銷燬,如Spring中的Invocation

領域模型劃分好處:結構清晰,可直接套用;充血模型,實體域帶行爲;可變和不可變狀態分離,可變狀態集中;全部領域線程安全,不須要加鎖工具

8、 Dubbo核心領域模型

  • 1. 服務域Protocol: Invoker暴露和引用的主功能入口,負責Invoker的生命週期管理
  • 2. 實例域Invoker: 它是Dubbo的核心模型,任何模型都向它靠攏或者轉換成它,它表明一個可執行體,可它向發起Invoke調用,多是一個本地實現,也多是遠程調用,也有多是集羣實現
  • 3. 會話域Invocation: 持有調用過程的變量,好比方法名和參數等

9、 領域模型線程安全性

  • 1. 服務域:一般無狀態,是線程安全的
  • 2. 實體域:經過設計爲不變類,全部屬性只讀,或整個類引用替換,是線程安全的
  • 3. 會話域:保持全部可變狀態,且會話域只在線程棧內使用,每次調用都在線程棧內建立實例,調用完即銷燬,是線程安全的

10、 API和SPI分離

Dubbo中的API如ServiceConfig\ReferenceConfig\RpcContext是給使用者使用的,Dubbo中的SPI如Protocol\Transporter\LoadBalance,是給擴展者使用的,API應該是聲明式的,描述須要什麼,SPI應該是過程式的,描述怎麼實現。它們不該該混在一塊兒,使用者不該該看到擴展者寫的實現編碼

11、 API可配置必定可編程

  • 1. 配置用於簡化常規使用
  • 2. 編程接口用於框架集成

12、管道和派發

管道通常適用於組合行爲,主功能以截面AOP實現,好比Servlet。派發通常適用於策略行爲,主功能以事件Event實現,好比Flux插件

十3、主過程攔截

沒有哪一個公用的框架能夠Cover住全部的需求,不論是Web框架的請求響應流、ORM框架的SQL-Mapping過程,仍是Service框架的調用過程,容許外置行爲是框架的基本擴展方式,否則若是須要添加安全、日記或者修改分頁SQL等不得不hack源代碼了

十4、Dubbo調用過程攔截

Dubbo中使用全管道設計,框架自身邏輯,均使用截面攔截實現,好比常見於消費端的context\collect\generic\activelimit\monitor\future等鏈式過濾器,常見於生產端的token\exception\echo\accesslog\trace\executelimit等鏈式過濾器

十5、事件派發

攔截器是在切點執行先後生效的,它是干預過程的,會觸發非關鍵行爲,而事件是基於狀態數據的,會觸發狀態觀察者行爲

十6、Reactor和Proactor事件驅動模型

Reactor模型關注就緒狀態,好比可讀了就通知咱們主動去讀,相似Linux epoll,而proactor關心的是完成狀態,好比咱們指定存放數據的內存地址(Buffer)和讀事件,當它讀完了就會通知咱們,相似Windows IO completion port

十7、Dubbo 暴露/引用/調用事件

Dubbo在關鍵路徑上採用攔截鏈分離職責,保持界面功能單一,不易出問題。在非關鍵路徑上,採用後置派發,即便派發失敗也不會影響主流程運行

十8、協做防護

  • 1. 可靠性分離。不可靠操做盡可能縮小
  • 2. 狀態分離。有狀態儘可能縮小可變域,不可變類儘可能聲明爲final
  • 3. 狀態驗證。儘早失敗,在有傳入參數或者狀態變化時,均在入口處所有斷言
  • 4. 異常防護。不要生吃異常,應該儘可能保證異常信息給出解決方案,日記信息包含上下文
  • 5. 下降修改時的無界性,不埋雷。避免基於異常類型的分支流程,同時保持NULL和Empty語義一致

十9、開閉原則

開閉原則,對擴展開放,對修改關閉,由於風險每每來自於修改。擁抱變化時應該繼承原有類而後重寫方法擴展邏輯,而不是修改原來的類

二10、增量式和擴充式

若是現有一個無狀態消息發送的場景,後來新增一個會話消息發送需求,若是採用增量式擴展,無狀態消息發送原封不動,同步消息發送,在無狀態消息基礎上加一個 Request/Response 處理,會話消息發送,再加一個 SessionRequest/SessionResponse 處理

二11、Dubbo增量式擴展

傳統的C\S模型是一問一答模式,而Dubbo的RPC模型中包括了Proxy\Custer\Protocol, Protocol只負責協議實現,它是不透明的、點對點的,Cluster只負責將集羣中多個提供者假裝成一個,Proxy只負責透明化接口,橋接動態代理,總體的架構很是容易擴展

二12、在高階附加功能

儘量少的依賴低階契約,用最少的抽象概念實現功能。當低階切換實現時,高階功能能夠繼續複用

二十3、Dubbo高階泛化調用

以PHP到Router的request body中的方法名和方法參數做爲Router遠程調用後端Java服務的入參,最後將遠程調用的result返回給PHP端就是兼容Restful服務的高階泛化調用

二十4、總結

文章來源:www.liangsonghua.me
做者介紹:京東資深工程師-梁鬆華,長期關注穩定性保障、敏捷開發、JAVA高級、微服務架構

clipboard.png

相關文章
相關標籤/搜索