1. 程式人生 > >服務治理咋這麼難?我想得換個治法了。

服務治理咋這麼難?我想得換個治法了。

引出問題 在服務開發的時候,我們一般將功能開放為介面。而功能的驅動來源於上游,但上游需要按照下游的介面定義進行通訊才能驅動,這樣介面就將兩個系統耦合在了一起。因為介面是面向功能的,我們稱這種模式為功能驅動。這在系統規模較小時問題不大,但現在是(微)服務化的年代,我們需要大量的介面用於服務間的通訊,這時耦合問題就變得比較突出了。 現舉例說明,假設我們要做一個金豆系統,我們常規的做法是將增、刪、改等功能開放給外系統並由它們進行呼叫,對接的系統非常多,如購物、評價、活動等,每個系統都按照自己的規則對金豆系統進行控制。因為規則限定在各自的業務系統內,所以不存在複用及打架的問題。但在運行了一段時間後,業務部門打算引入會員制,針對不同的業務依據不同的會員級別定義不同的獎勵係數。於是問題出來了,會員級別該在哪裡處理?開發團隊商量了一下,給出兩個方案並做了評估: 方案1:改造金豆系統,提供V2版的增、刪、改介面,每個介面增加對會員規則的處理。接入方換個地址就好,不需要引數變更,但因為需要重新開發介面且相關的對接專案都要改造,開發週期較長。 方案2:金豆介面不動,由各個對接系統各自處理會員規則。好處是週期短,可由各個團隊分頭實施,缺點是是存在功能重複。 這個例子也許不具有代表性,這裡也不評價這兩個方案的好壞,這裡的重點不是金豆專案本身,而是這個例子所折射出來的擴充套件性設計問題。那麼擴充套件性問題與開頭提到的耦合又有啥關係?因為擴充套件性不好的設計會使介面過多,這個多有可能是業務職能分配不合理造成的重複性的多,有可能是版本迭代造成的重複性多,這會放大系統間的耦合問題。也就是說擴充套件性如果做的比較好,那麼介面的數量和穩定性都會得到很好的控制。 問題分析 其實這個問題要比想象的還要複雜,假設在金豆系統開發之前我們就知道有會員等級這一需求,我們也往往很難抉擇系統的邊界,因為我們會有很多的維度去劃分這個邊界,最終大多是一個權衡的結果。如果要以金豆的複用性為考量依據則不應該將規則納入到金豆系統裡,因為規則多且易變。但如果以控制的集中性為依據則恰好相反。雖然市面上有很多的設計模式,但每個設計模式都有特定的應用場景,但現實世界往往是多個場景的綜合,所以這非常考驗設計人員的能力,素養以及經驗等。 那麼我們有沒有辦法使多個場景各自獨立呢?如果可以那麼問題將極大的簡化。但很可惜功能驅動模式是不支援的,因為系統間存在著硬相關性。下游需要實現這個功能介面,而上游需要控制這個功能介面。注意這裡沒有用“呼叫”一詞而是用的“控制”,因為呼叫是技術層面的內容,而這裡講的是業務,功能是面向業務的,業務當然需要控制。由此可見控制和實現必然要耦合在一起,否則不能行使功能。這種耦合必然成為場景獨立的絆腳石。 於是,當我們的系統開始龐大起來的時候,這種耦合便成了程式設計師的噩夢,尤其是基礎服務!因為想控制它的系統實在是太多了,每當我們對基礎服務進行調整的時候,你會發現異常的困難,我在京東主導訂單賬歷時半年多才搞定,這個是最主要的原因。這也是微服務化建設道路中一般都會遇到的普遍性問題。 雖然大家都在強調服務治理,但我感覺目前市面上的解決方案大都在外圍打圈圈,都是在自動化,視覺化上做文章,並沒有看到有關減少複雜度的理論或產品面世。它們基本上沒有觸及服務化的實質性矛盾:服務單一職責與服務間關係複雜之間的矛盾。而服務間關係的複雜性的根本原因在於服務間業務控制的複雜性。 既然問題這麼普遍那是不是我們的方法論出了問題?當前所有的系統基本上都是基於面向物件技術構建的,我們的類、庫、服務都是這一思想的產物,可以說沒有面向物件就沒有現在軟體產業的蓬勃發展,所以在基本面上我們是不能懷疑面向物件的價值的,雖然有人已經指出了面向物件的一些問題(見參考1),我想還不足以動搖面向物件的支撐地位,尤其在單個系統內部設計上。 然而時代在變遷,系統由原先的單體已經演變為現在的分散式服務網格,如果把所有服務當做一個整體來看,每個服務就是一個物件,用於對外提供可複用的功能,這完全符合面向物件的思想。不過我們的場景已經發生了很大的變化,服務之間的呼叫已經把強力的控制降格為公平的協作,具體表現為:控制者和實現者各自擁有獨立的程序,這便為功能變更造成了很大的障礙,這會導致控制的複雜性、脆弱性、延遲性等一系列問題。其次控制者和實現者很可能由不同的團隊來主導,團隊之間的地位相對來講是平等的,這會為介面變更製造困難,所以控制的效果將大打折扣。 控制要求對資源進行強有力的佔有,最好的體現形式是內聚而不是耦合,畢竟內部問題解決起來要比外部輕鬆的多。然而現有的微服務體系大多是由鬆散的多個團隊來協作完成任務的,我們需要克服大量的溝通問題,系統規模越大困難越大,而且這個問題要比程序獨立更難以解決,是矛盾的主要體現。所以面向物件在(微)服務場景下顯得力不從心了!。 解決的方法   既然服務間的控制這麼難做,我們是否可以“捨棄”控制呢?   如果“捨棄”服務間的控制,我們將面對功能如何驅動的問題。驅動方式無非兩種:主動和被動。我們現在的服務大多是被動的,它不能自主完成任務,需要上游發出針對自己的指令才可以工作。主動方式的也有,如基於訊息消費的服務,這類服務可以依據別人的資料自行啟動處理程式。顯然被動驅動是無法捨棄控制的,所以我們只能寄希望於自主控制。 要想自主控制,現行的介面的工作方式是不可以的,現在的介面名稱是業務功能的識別符號,實際上等同於指令控制編碼,要想“捨棄”控制,就得捨棄這一部分。既然介面沒有必要對功能進行標記,我們只需要一個純通訊意義上的介面就好了。但我們的資料要做下特殊處理,否則我們無法識別不同的資料,更別說驅動功能,這個下面會講到,這裡先不展開。 當然我們不能真的把“控制”給丟掉,我們只是希望它不要成為管理上的負擔。所以我們得為他安排一個去處。這裡有兩個地方,第一個地方我們可以把控制放到一個獨立的類似於訊息系統的中間平臺上,由它來進行集中控制;另一個地方是將控制轉移到下游,把控制由耦合轉變為內聚,讓它從呼叫關係上消失。 我們先說平臺思路,由於我們把控制從介面中剔除,平臺和各個服務之間只能交換資料,所以所有的控制邏輯都要在平臺內實現。而這顯得非常的不現實,畢竟控制是非常複雜且個性的。然而有人確實做了這方面的工作,如各種工作流引擎。調研了一下,發現這些引擎最終都是功能的選擇,而我們的功能標記已經去除了,所以根本無法滿足我們的要求。 這裡有一個例外:Nature 專案。Nature 雖然也是一個流引擎,但 Nature 是面向資料的而不是面向物件的。Nature 用資料與資料之間的上下游關係來代替顯式的控制,也就是說 Nature 把控制真的“幹掉”了,這正好與業務系統無業務意義的純技術介面相吻合,那控制從哪裡來呢?答案就是資料間的上下游關係,只不過這是一種隱式控制,這樣 Nature 只通過資料就可以將不同的業務系統串起來,從而簡化了業務系統的開發。 有關 Nature 專案請請見參考2。 也許你還發現了另一個例外:訊息系統。其實就金豆和訂單這個事情來講完全可以由訊息系統來解決,業務系統與訊息系統的介面也是不區分業務意義的純技術介面,那麼訊息系統與 Nature 系統的區別是什麼呢?答案是:訊息系統是完全沒有控制,因為訊息系統是不能定義資料之間的關係的,所以訊息系統不能對整個流程進行控制,要想控制還的藉助於外部的業務系統。就服務治理來講訊息系統可以降低系統間的耦合,但遺憾的是它沒有流程控制能力。 如果你覺得 Nature 在認知上過於顛覆,那麼我們可以採取另一個方法,就是將控制放到下游系統裡去,使之成為內聚的一部分。那麼接下來的問題是如何去定義我們的資料,以及如何去觸發下游系統的不同功能,答案就是事件!上游只需告訴下游我發生了什麼,不需要告訴你該怎麼做。 繼續以下單獎勵金豆為例進行說明,我們在下單時定義一個下單事件,事件內容為訂單內容,其形式如下:
{
      "eventType": "order.paid",
      "eventID": "訂單號,如123456",
      "eventPara": "訂單內容的JSON串"
}
然後我們將這個資料傳遞給金豆的統一介面,在金豆系統內部,我們依據不同的 eventType 值進行自主控制。只要“我發生了什麼”資訊是全面的,下游是完全有能力自行完成任務,從而也能起到降低耦合的作用,只不過這個耦合沒有 Nature 來的徹底。因為即便金豆系統提供了一個去功能化的介面,但這個介面的url必定要耦合“金豆”這個業務系統而不是其他業務系統,也就是說使用此種方式我們沒有辦法來徹底解決業務系統耦合的問題。其帶來的最大的問題就是流程硬編碼,而 Nature 則不存在這個問題。 控制內聚化除了這個遺憾外,還是有一個讓人困惑的問題:eventType 的值以及 eventPara 中的內容應該由哪個業務來定義?由訂單業務來定義可以說的通,因為大家都依賴於訂單。但是由金豆業務來定義也可以說的通,因為這畢竟是金豆相關的業務,所以統一由金豆業務來定義也說的過去。這又是一個權衡的問題,這個權衡不一定是技術合理性為依據的,所以這裡就不討論了,但如果使用 Nature 的方式,則不需這個權衡了,因為對資料定義的“控制”必須都要在 Nature 上進行。 其它 事件機制給了下游自主控制的能力,下游介面的穩定性、獨立迭代的靈活性以及功能的可擴充套件性都可以得到大幅度的提升。除此之外事件還有一個天然的特性:業務溯源能力。對下游來講來自上游的事件型別和事件ID必須作為下游資料的一部分來儲存,資料來源於哪裡一目瞭然。這一點在我們的常規功能性介面上往往是需要特意設計才能具有此功能,或者藉助笨重的第三方工具或平臺來實現。 事件的溯源能力還有另一個好處,因為事件是外部傳入的,我們需要唯一標記一個事件,這會為業務的冪等處理打下天然的基礎,我們無需進行額外的防重入設計。 還有一個好處,因為我們移除了介面的功能標籤,使得介面得到統一,原先需要做切面處理的現在可以不用了,這可以降低相關技術的難度,提升系統的可維護性。但這也同時是一個壞處,一些功能性的資訊在 url 上就無法體現了,這會對一些監控或管理工具的使用造成影響。 參考 參考1:面向物件程式設計—價值萬億美元的災難
參考2:Nature 專案