服務應該去版本化,不管是微服務還是SOA

weixin_33807284發表於2016-07-12

在閱讀本文之前,你需要先對前面的背景有些瞭解,下面是本系列的前兩篇文章:\

經過前面的熱身,我相信後面兩章我們談S++不會那麼生澀了,尤其是第一篇發表後一位叫lpy的架構師指出:“除非有必要,我們不要創造新的概念”,這就是著名的奧卡姆剃刀定律“如無必要,勿增實體”。本章主要談S++一些基本的特性和基礎應用,看看我們新增的基礎概念是否該被剃刀無情的剔除。然後我們在下一章重點探討S++如何解決微服務帶來的問題以及---SOA的終極目標也就是業務敏捷性。\

我們先簡單回顧一下S++的定義:服務的本質就是行為(業務活動)的抽象。與SOA和微服務相比較,S++不僅僅進行了簡單抽象,更重要的是完成了服務的業務與技術分離以及服務的多型建模。\

那麼,S++作為SOA的更高階版本,為了完成SOA的終極目標也就是業務敏捷性,必須具有以下幾個特徵:\

1、服務的業務要素必須唯一併不具有歧義

\

在S++中,通過引入服務後設資料的概念來描述業務要素,服務後設資料的引入是實現業務與技術分離的重要手段。通過服務後設資料的全域性唯一性來保證業務要素的全域性唯一性,舉例說明如果兩個不同的服務中都包含後設資料A的引用,那麼在這兩個服務中的這個業務要素是一致的,所謂一致是指的在同一個業務流程的上下文中,這兩個欄位的取值是相同的。下面大家來看個簡單的例子來理解一下如何用後設資料來表達服務:\

後設資料定義表,後設資料ID全域性唯一,不可重複。\

1d6bb203d88fd6fe6b77c8a6ce6be3da.jpg

\\

服務定義樹:\

9b8014f9270189512d2ed1dc10e7868c.jpg

\

我們看到,由於後設資料全域性唯一,所以決定了要素一致的服務是相同的。\

2、服務必須在空間和時間上具有唯一性和穩定性

\

服務要素後設資料化後,後設資料的時空唯一性就決定了服務在時空上也是唯一的。當任意兩個服務,如果其定義中引用的所有後設資料集合完全一致的時候,無論這兩個服務的結構上有什麼差異,這兩個服務都是同一個服務。\

服務的時空穩定性是指,服務的一旦被嚴肅的定義出來,那麼在任何使用環境中、任何時刻其已經明確的業務要素不會被改變,任何要素的改變意味著一個新的服務被定義。比如打球含有兩個要素:人和球,無論在任何時間任何地點打球都需要這兩個要素;假設某個場景需要去掉球這個要素,那麼需要定義一個新的服務,這個服務可以只有人這個要素,但新的服務可能就是打架了。\

3、服務需要具備多型性

\

服務多型性是指,服務可以在執行時刻動態的轉變為另外一個服務的特性。\

服務的內涵

\

所有與服務的具體實現者無關的服務屬性,都屬於服務的內涵範疇。除了服務的基本資訊之外,主要還包含三大類:\

  1. \

    服務的SDA(Service Definition Agreement),服務的定義部分。

    \
  2. \

    服務的SLA(Service Level Agreement),對服務提供者的服務水平的約束部分。

    \
  3. \

    服務的OLA(Service Operation Agreement)的一部分,對服務的操作層面的描述。

從服務的內涵來看,服務具有唯一性,只要具有相同要素的服務,無論你是否願意承認,他們都是一種行為。而且,服務不但具有空間的唯一性,還具有時間的唯一性,比如古代的餐飲服務,和現代的餐飲服務,其實在要素上幾乎沒有差別。我可以推測,馬車時代的修車服務和現代的修車服務在要素上也不會有什麼差異,甚至可以產生完全一致的抽象。\

服務的外延

\

自然地每一個服務具體的實現者都是服務的外延,為方便起見我們也可以把服務的消費者也看作服務的外延。每一個服務的外延都有各自的不同,事實上傳統大服務的WebService和微服務的RESTful都可以看作服務的不同外延,我們管這種外延叫服務的介面。\

服務通過一致的內涵來統一服務的功能,通過多樣化的外延來適應不同的消費需求。其實,正是通過服務的多樣性外延我們才可以體驗服務在空間和時間上的一致性。在這裡我們再次去體會第一章騎大象的例子,同樣一個事情,從不同的角度看就具有不同的要求。那麼上面那個簡單的例子裡,服務一樣需要外延來表達,比如下面的介面定義:

056fe007c74f7ec6e6e75808158998bb.jpg

\

畫紅圈的部分就是一個特定的實現需要額外新增的技術要素,這些技術要素是實現者因為技術或管理原因要求的。比如序列號,是因為系統需要標識每一筆交易不能重複;櫃員號是因為從管理上要求知道每一筆交易是哪個業務員操作的,以便未來的績效、查錯等。而這些技術要素就沒有繫結業務後設資料,所以就不會和業務相混淆。\

服務的多版本

\

傳統的,如果我們把WebServices或者RESTful當作服務來看的話,那麼服務一定是有版本的。但是,根據S++對服務內涵的定義,服務具有空間和時間上的一致性,所以服務本身是不需要版本的。服務的變遷是因為我們對服務的抽象過程的缺陷造成的,一旦最新的抽象形成了,那麼這個抽象必然完全滿足時間和空間上的所有外延實現(大家可以回顧打球和打架的例子)。這就是說,我們只需要儲存最新的內涵抽象就夠了,那麼歷史的版本在哪裡呢?其實,歷史的版本在已經使用的外延中幫你儲存了,當然為了更好的記錄變遷,你可以對服務的變更過程做一些批註記錄。\

其實,傳統服務的多版本對SOA甚至是有壞處的,比如在服務組合流程當中。當我們認定服務在空間和時間上的唯一性後,服務的組合中呼叫的原子服務就具備唯一性,一旦版本被引入後破壞了服務在時間上的唯一性,那麼服務組合就要決定其呼叫的原子服務在不同時間點的副本,這本身和業務流程毫無關係,從而破壞了業務流程的完整性造成流程不穩定。\

服務的業務與技術分離

\

業務與技術分離是個老生常談的話題,在S++中服務的業務和技術分離包含兩個方面:\

業務內涵和技術結構的分離

\

通過上面後設資料與元結構的概念說明,可以看到服務對外表達是通過一個結構化的樹狀資料結構完成的,這種表達有利於在技術上幫助服務的消費者通過結構化的報文完成服務的呼叫。而元結構的結構點可以和業務後設資料繫結,意味著任何一種結構的資料都可以轉化成僅關注業務要素的服務內涵。\

這種分離帶來兩個好處:就是可以在不改變服務內涵的前提下任意的修改服務對外的技術表達形式和結構(對相同內涵的任意表達);或者在保證不修改服務對外技術表達的前提下,通過更改業務要素後設資料的方法來改變服務的內涵(對存量表達的任意相容)。這種分離給系統帶來巨大的靈活性。\

業務內涵與技術介面的分離

\

為了進一步的完成業務與技術的分離,在S++中將服務的最基本元結構作為服務內涵和預設外延(預設對外技術介面)的同時,又進一步的給服務增加更多的獨立介面作為滿足不同需求的技術外延。\

在介面中,可以描述不同結構的、經過裁剪和定製的服務要素,並且可以攜帶與服務內涵無關的技術要素。這樣就可以使服務的抽象定義滿足各種不同場景的技術需求,提高系統的靈活性和適應性。\

前面舉的只是一個很簡單的例子,其實在服務的介面中可以描述非常豐富的技術資訊,包括報文的型別、資料的Format、資料的邊界檢查、與後設資料不同的資料型別(方便資料轉換),甚至資料的拆分合合併等等。實際上,介面就是一個從服務實現到服務的一個報文對映和翻譯規則描述檔案。\

S++的服務多型性

\

服務的多型性是S++的一個重要特性,也是實現SOA業務敏捷性的一個關鍵。\

服務多型性的概念

\

服務的多型性是指的業務流程在開發態所引用的服務,在執行態會根據業務要素的內容動態的變化為與開發態所定義的服務不同的、但具有一定繼承關係的服務。\

舉個例子說明,開發態流程編寫中會呼叫繳費服務,但是在執行態會根據“待繳費ID”的內容進行判斷,動態的變化為呼叫諸如繳電話費、繳水費、繳煤氣費等等不同的服務。\

服務多型具有以下特徵:\

  1. \

    服務多型必須是執行態提供的能力,開發態只需要關注服務的抽象定義,從而實現業務流程的穩定性。

    \
  2. \

    服務多型必須對業務透明。即,在業務流程中不應該出現與執行時動態變化相關的程式碼。如果在業務流程中需要判斷一些要素,根據要素由業務來完成服務的動態變化,那麼就不是服務多型。

    \
  3. \

    服務多型必須支援跨系統的遠端服務呼叫。當業務流程中需要呼叫外部服務的時候,服務動態變化的實現必須是自動的,不需要本地業務系統進行支撐。

    \
  4. \

    服務多型必須自動的支援業務要素的過載和對映轉換。當業務流程呼叫的父類抽象服務時,其業務要素可以被子類服務的業務要素過載,例如繳費服務中一個業務要素“待繳費標識號”,繳電話費子類中就會被過載為“待繳費電話號碼”,那麼這個過載對映的過程必須由系統來完成,應用應該完全透明。

服務多型性解決的問題域

\

服務多型性主要為解決系統間相互訪問產生的耦合性問題,由於物件導向方法引入的強耦合性,造成了傳統的系統間呼叫必須手工的維護業務分支,從而進一步導致業務流程不穩定難以維護。\

  1. \

    服務多型主要面向系統間相互訪問,系統內更高效的方法還是物件的多型性。

    \
  2. \

    服務多型用於解決系統擴充套件問題,防止業務流程中服務節點的擴充套件對流程本身造成影響,從而導致需要人工修改流程的問題。

    \
  3. \

    服務多型可以遮蔽同類業務分支,例如繳費服務存在繳電話、繳水費等這些種情況;對於不同型別的業務分支無法利用多型性,例如當賬戶餘額充足時繳費,不足時返回異常,這樣的分支是無法利用多型性進行簡化的。

    \
  4. \

    服務多型不能解決應用架構問題,就如物件導向一樣,在不同應用架構下服務多型的實現方法可能有很大的差異,甚至某些架構下服務多型性不一定能優雅的實現。

S++的應用

\

解決流程中資料處理問題

\

S++的出現最初就是要解決流程穩定性問題,所以業務和技術分離第一個主要的應用場景就是消除掉傳統業務流程編排過程中和業務無關的(造成流程不穩定的)環節。舉個例子來說明:\

\

在某流程X中,先後呼叫服務A和B,那麼傳統的任何要在A節點和B節點之間要傳遞的資料,我們會定義一個技術節點,這個技術節點大體上做的事情就是賦值,比如B.field1=A.return1; B.field2=A.return2….

\

假如未來A和B服務發生了變化,比如增加了欄位,那麼就需要修改這個賦值節點,增加諸如B.fieldx=A.returnx這樣的賦值對映,這個過程就會造成流程的不穩定。也就是說任何服務的變更都會影響已經做好的流程的改變,這樣的話我們就不能大規模的利用流程編排來開發業務系統,這也是傳統SOA和微服務架構無法避免的問題,這個問題導致了SOA理念無法完整的實施落地。\

S++通過後設資料隔離了元結構之間的差異性,在服務治理的過程中,通過定義B.fieldx=Metadatax;A.returnx=Metadatax,將後設資料Metadatax與具有相同業務要素的元節點繫結,這樣在上述的業務流程中,系統就會自動的動態的生成形如B.field1=A.return1; B.field2=A.return2這樣的程式碼,如果服務A和B發生上述變更,編譯器會動態的生成程式碼B.fieldx=A.returnx,從而自動的維護了流程的穩定性。\

解決服務變更問題(時空穩定性)

\

我們知道,服務的抽象定義是一個過程,誰也不能保證定義的完美無缺,但是服務的修改往往會帶來所有相關係統的修改,非常麻煩。舉個虛構的例子:\

  1. \

    我們定義一個取款服務,其中賬號定義為AccountNo,我們為賬號這個元節點繫結一個後設資料(假設也叫AccountNo)。

    \
  2. \

    我們又定義了一個存款服務,其中賬號也被定義為AccountNo(有可能這個兩個服務不是一個人定義的),並且也被預設的繫結了同名後設資料AccountNo。

    \
  3. \

    隨後有個需求(假設叫轉賬服務)需要定義一個流程,這裡需要先進行取款操作,然後將取出的款項存入另外一個賬號。那麼會為轉賬服務定義一個轉出賬號AccountNo_Out,一個轉入賬號AccountNo_In,顯然這兩個業務要素是不同的,所以分別為他們繫結不同的同名後設資料。

    \
  4. \

    問題來了,由於當初定義取款和存款服務的時候,沒有考慮到這兩個服務的組合情況,所以如果按上一小節中同名後設資料對映的方式,存款和取款賬號作為同一個業務要素就具有相同的數值,顯然就無法完成轉賬業務了。

    \
  5. \

    傳統的解決方案是在轉賬流程中增加手工的對映節點,但是這樣顯然就影響了流程的穩定性,而且增加了開發人員的工作量和出錯的概率。但是如果我們去改變服務的結構,比如把取款服務中的AccountNo節點改名為AccountNo_Out,存款服務中的節點改名為AccountNo_In,就會造成現存的服務訪問者需要變更程式,顯然也是不可取的。

    \
  6. \

    針對這個問題,S++的解決辦法是保持存、取款服務對外的結構不變,AccountNo這個節點的名稱維持不變,但是將AccountNo所繫結的同名後設資料變更為AccountNo_Out和AccountNo_In。這樣,在轉賬服務的流程中系統就會自動的完成正確的資料對映,同時服務對外的介面不發生任何變化,也不會引起存量的服務消費者變更程式。

通過S++的業務與技術分離,可以簡潔的、完全透明的解決服務變更引起的外圍變更,從而達成了服務在時空上的相對穩定性。\

2142a5f0f5d291c85905af57740af9cd.jpg

\

解決外圍變更問題(時空穩定性)

\

S++服務的時空唯一性和穩定性可以通過介面的形式來體現,當服務的外圍系統(包括消費者或提供者)發生變化時,比如升級或更換系統,那麼在不修改服務內涵的前提下就可以通過定義新的服務介面來適應外圍變更,從而減小甚至消除變更對整體帶來的影響。\

其實,從某種意義上,服務的定義可以看作一種預設的介面,服務內涵僅關注和定義無結構的、扁平化的後設資料作為業務要素。那麼不同的介面可以看成用不同方式來定義的服務,用於適應不同的服務消費者和服務提供者,介面就像一個翻譯工具,可以通過介面把不同的語言和方言翻譯成按後設資料語言描述的服務。\

延伸思考:對真實業務流程的抽象

\

服務的業務與技術分離以及多型性,帶來一個意想不到的可能性,也就是說我們可以建立與業務和技術都完全無關的抽象的流程模型。我也沒有深入思考過的這個問題,下面只是簡單描述一下抽象流程模型的概念。\

我們知道,做任何稍微複雜的事情一般都會有一定的步驟,我們社會中有很多做事的步驟是相類似的,這是因為長期的社會實踐積累了大量的經驗,這些經驗和知識往往都包含了經過實踐驗證的合理的做事步驟。這種步驟是非常抽象的,可以適用於非常多的不同的社會活動。舉個例子,比如購物這種商業行為,無論你是購買的有型的商品,還是購買無形的服務,我們都可以用一個高度抽象的商業流程來概括完成,如下:\

  1. \

    首先我們需要一個商品檢索挑選的流程

    \
  2. \

    然後我們需要一個維護購物車的流程

    \
  3. \

    接下來需要一個下訂單的流程

    \
  4. \

    然後是支付的流程

    \
  5. \

    然後是物流送貨流程

    \
  6. \

    最後是售後流程

事實上,淘寶之類的購物系統已經完成了這種什麼都可以賣的需求,但我並不知道他的內部是否是用一種高度抽象的流程來完成所有類似的商業行為的。傳統的業務流程編排工具是無法完成的,因為傳統的流程工具在編排流程的過程中需要關注業務要素,就比如我們前面舉得例子,需要完成B.fieldx=A.returnx這樣的工作,所以這樣的流程就無法滿足各種不同的服務A和服務B的編排(因為A和B的要素會隨著業務的不同而發生變化)。同時,由於傳統的流程引擎無法解決多型問題,所以必須在流程中引用業務服務的具體實現,所以無法執行一個高度抽象的流程。\

S++通過業務與技術分離的技術手段,消除了流程引擎對業務要素的依賴,在被編排的流程中只需要引用服務的名稱就可以,不需要關注所呼叫的服務的要素細節,所以這個抽象的流程就可以執行在任何一個服務系統中,只要能把特定的業務服務與流程中的節點關聯上,就可以由S++系統自動的完成業務要素的匹配工作。同時,用於S++流程中可以呼叫和具體實現完全無關的抽象服務,這樣就可以不用在開發時刻就決定流程節點的具體服務實現,讓抽象服務在執行時刻再去決定真實的實現。\

S++的這種特性,決定了傳統流程工具無法實現的抽象流程模型成為可能。由於本文主要關注S++的特性,所以感興趣的讀者可以自己去研究如何用抽象流程實現跨行業統一的業務流程。\

小結

\

回顧本章,我們從S++的基本概念推匯出幾個有價值的推論,再基於這幾個推論解決了我們在面向服務的實踐中遇到的幾個棘手問題,稍微有點兒燒腦…\

這幾個推論是:\

  1. \

    服務具有時空唯一性和穩定性

    \
  2. \

    服務無需維護版本

    \
  3. \

    在不變更服務的前提下,對同一個服務可以有無數種不同的表達(介面)

    \
  4. \

    服務的變更不會影響已經存在的任何一個表達(介面)

基於這幾個推論,我們幸運的發現新增的概念還是能解決一些問題的,大家已經看到:\

  1. \

    簡化業務流程,穩定開發成果。

    \
  2. \

    遮蔽服務變更和外圍變更對系統穩定性的影響,降低系統維護成本。

想通過增加基礎概念來解決實際問題,其實是非常困難的一件事,稍不留神就會被奧姆剃刀無情的剃成禿子,白白的燒腦。\

下一章節我們主要探討微服務的業務流程問題,我們所說的業務流程不僅僅是狹義的工作流,而是包含了原本業務系統用硬編碼完成的物件間互動的業務邏輯,同時我們還會通過S++所支撐的演算法解決一個效率問題。\

作者介紹

\

李東,14歲開始學習計算機語言,作為課外興趣自學了BASIC和彙編,利用放假期間編寫了貪吃蛇、打飛碟等遊戲。高中、大學期間繼續自學軟體程式設計,曾將C和彙編結合使得從高階語言中能夠呼叫繪圖功能,並模仿Borland C++開發了一套適合學校機器的圖形化開發環境的原型。\

93年大學畢業後在西門子合資公司作為交換機軟體安裝人員工作兩年,然後來到JInfonet公司先後參與4GL的研發和JReport的研發。作為JReport的第一代主要研發人員,編寫了從原型一直到3.0版本的核心引擎部分。2000年與合夥人一起建立了Bi-Soft公司,主營業務是商業智慧軟體Bi-Pilot,負責整個產品的研發及管理工作,從最基本的查詢一直到多維分析模型和引擎都是產品的涵蓋範圍。\

2007年Bi-Pilot被神州資訊收購合併,李東開始在神州資訊研發SmartESB產品,用SOA的方法論為客戶提供底層產品服務。


感謝郭蕾對本文的審校。

\

給InfoQ中文站投稿或者參與內容翻譯工作,請郵件至editors@cn.infoq.com。也歡迎大家通過新浪微博(@InfoQ@丁曉昀),微信(微訊號:InfoQChina)關注我們。

相關文章