天天看點

微服務治理實戰:服務流的自動化建構與應用

本文根據dbaplus社群第89期線上分享整理而成。

講師介紹  

微服務治理實戰:服務流的自動化建構與應用

張真

宜信技術研發中心進階架構師

目前負責金融基礎服務、微服務架構演進/計算平台、devops平台等。

曾任ibm,負責雲計算、應用伺服器等,擁有多個國際專利。開源社群活躍貢獻者。

主題簡介:

服務流及微服務架構下服務流建構的挑戰

自動化建構(微)服務流

自動化建構服務流的應用場景

先談談這個話題的早期背景,作為一個發展了十年的企業,我們公司内部存在大量的系統,這些系統可能包括多種架構,多種技術棧,它們互相關聯,互相作用成就了複雜的業務體系。随着業務演變,人員更疊,系統演進等諸多因素的疊加,公司級系統的關聯關系與狀态逐漸變得難以精确梳理,難以精細維護。

基于這樣的痛點,便産生了這個話題的思考:能否使用技術手段自動地、精确地、具現化地勾勒公司級的應用/服務關聯圖譜?

1服務流以及微服務架構下面臨的挑戰

描述關聯關系會讓人聯想到一個詞“拓撲”。拓撲是源于數學的一門方法論,它是研究與大小,形狀無關的點、線關系的方法。在計算機領域,拓撲是一組計算機相關的抽象點,以及點之間聯線構成的圖形。

大家最熟悉的是網絡拓撲,它是把計算機和通信裝置抽象為一個點,把傳輸媒體抽象為一條線,由點和線組成的幾何圖形,是對實體網絡環境的描述。網絡拓撲的核心辨別是ip位址,是以每個點就是一個ip位址的抽象,而點與點之間的連線代表網線,光纖或無線連接配接。這個圖形描繪了實體網絡的靜态結構。

網絡拓撲舉例:

微服務治理實戰:服務流的自動化建構與應用

(注:圖源自網絡)

在apm(應用性能管理)領域,提供了應用拓撲。它是将終端(使用者),中間件(包含應用),資料庫等抽象成點,用有向的連線來描述通路關系(資料交流傳輸的路徑)。它強調端到端的流程繪制。

應用拓撲舉例:

微服務治理實戰:服務流的自動化建構與應用

說說今天的話題,什麼是服務流?它與前面二者的差別與聯系是什麼?

服務流(service exchanging topology)是描述服務與服務的靜态拓撲和運作時特性的圖譜。之是以稱為服務“流”,是強調它更加動态,它涵蓋應用拓撲的内容,比應用拓撲提供更加深入的抽象粒度,也提供更加豐富的運作時狀态。同時它不強調應用的概念,但相容不同架構下的應用概念。

在說明服務流如何抽象節點之前,先簡單梳理一下服務,應用以及程序的概念:

程序:提供運作資源的載體,這些資源包括cpu,記憶體,網絡,io等。

應用:符合某種it工業标準的,可獨立部署的單元,比如jee應用通常包括war包,ear包,eba包等。

服務:提供某種處理或計算能力的代碼集合。

通常我們會面對3種架構:單體架構,soa架構和微服務架構。

單體架構并不強調服務的概念,是以可能有服務,也可能無服務,而同一個程序中可能包含多個應用,比如tomcat啟動後,是一個程序,允許部署多個應用。如下圖:

微服務治理實戰:服務流的自動化建構與應用

單體架構中三者的關系

從soa開始,服務開始作為應用的必須單元,一個應用中可能包含多個服務。同時随着服務思想的發展,程序被建議部署單個應用(當然多應用也被允許),服務之間通過服務總線進行互動。如下圖:

微服務治理實戰:服務流的自動化建構與應用

soa架構中三者的關系

微服務架構進一步強化服務的概念,要求服務成為可獨立部署的單元,是以從部署形态上出現了兩種基本模式:

一程序一應用一服務,例如一個tomcat裡面部署一個war應用,這個應用隻包含一個服務

一程序無應用一服務,例如springboot取代了傳統的war部署,直接實作服務部署。

同時微服務之間基于服務發現進行直連互動,而對外部互動通過服務網關進行。如下圖:

微服務治理實戰:服務流的自動化建構與應用

微服務架構中三者的關系

接下來,闡述一下服務流提出的靜态拓撲和運作時特性的含義。

1、靜态拓撲:是描繪服務本體,服務之間的關聯。

服務本體是對以下四種類型服務的抽象:

業務服務:就是業務代碼集合,提供業務邏輯和流程,是服務流主要的抽象存在。

資料源服務:提供資料存儲和查詢,比如關系型資料庫mysql,緩存redis,非關系型資料庫mongodb等。

代理服務:提供通路代理,比如服務網關,nginx,haproxy等。

消息傳輸服務:提供同步或異步消息通道,比如rabbitmq,kafka等。

分類的标準是按照服務之間的關聯特性來确定的:

業務服務可以是輸入入口(有向連線的終點),也可以是輸出出口(有向連線的起點)。

資料源服務隻能是輸入入口。

代理服務盡管不處理任何邏輯,但可以是輸入入口,也可以是輸出出口。

消息傳輸服務隻能是輸入入口,但值得注意的是它的入口類型(用戶端)包括兩種:消息生産者和消息消費者,這是需要差別開的。

2、運作時特性: 主要是描述服務過程以及調用過程的一系列監控名額。

服務過程名額:被通路位址,操作方法,請求/響應内容,響應時間,吞吐量,錯誤數,通路時間戳等。

調用過程名額:調用位址,操作方法,請求/響應内容,異常/錯誤數,響應時間,調用量,調用時間戳,調用服務的特征(服務類型,是否叢集,版本,使用者/權限)等。

之是以能夠提供更深入的粒度是因為服務流使用了服務畫像資料和用戶端畫像資料,第二部分會詳述。是以從領域來看服務流、應用拓撲、網絡拓撲又分别對應服務監控、apm、機房監控這三個領域(如下圖):

微服務治理實戰:服務流的自動化建構與應用

在微服務架構下,服務流的繪制存在如下挑戰:

1) 微服務架構在實作服務獨立部署的同時,也帶來服務節點規模的大幅增長,導緻關聯關系更加複雜。依靠人工收集變得難以落地;如果依賴zookeeper,etcd等建立服務注冊中心,雖然可以收集到服務本體的一些資訊,但沒有服務的關聯資訊,且如何更新維護依然是問題。

2) 服務更加多樣化,變更更頻繁,且不同步。由于服務會被拆分得很細膩(有助于更加靈活的編排和獨立運維),是以服務的種類自然增長,且由于可能是不同團隊維護這些服務,服務的上線,變更等運維過程變得極大的不同步。

3) 微服務的部署形态有多樣性。例如傳統jee應用是由應用伺服器提供一個端口接收通路(一程序一應用一服務);而新的部署形态可能由服務對外提供一個或多個端口接收通路(一程序無應用一服務),如果是多個端口時,可以把這個服務看出一個聚合服務也可以将每個端口抽象成一個服務,從服務流的角度這種服務抽象需要具備聚合和分散的特性。

4) 在一個複雜生産環境下,還要考慮與單體架構,soa架構的相容問題。例如單體架構下需要識别“服務元件”或被抽象成一個“大服務”;soa下同一應用下可能存在多個服務,也需要被識别出來,并被分别抽象。

2自動化建構(微)服務流

對于服務流的建構,我們仍然采用了微智能的思想,希望服務流的建構過程形成完全回報閉環。

微服務治理實戰:服務流的自動化建構與應用

微智能設計思想的三觀

首先,建構服務流主要依賴兩種資料:

1) 服務畫像

是描述服務本體的資訊,包括應用唯一辨別(appid)(相容單體架構,soa架構),服務名(service id),服務執行個體的uri,服務接口的uri,服務接口的中繼資料(類,方法,入參出參,注解,部署描述符)。

服務端的抽象就是服務本體,但關聯線的對象是服務接口,如果服務本體包含n(n>0)個服務接口,則關聯線類型就有n種,關聯線條數=s[1]+s[2]+s[3]+...+s[n](s[k]代表某個服務接口的實際關聯線個數,s[k]>=0,1<=k<=n)

2) 用戶端畫像

是描述調用服務行為的資訊,是服務關聯抽象的基礎。包括應用唯一辨別(appid)(相容單體架構、soa架構),所在服務名(service id),通路的uri,操作的中繼資料(操作,方法,入參出參)。

從抽象的角度,用戶端抽象是以通路的uri(關聯線)為區分的:

同類型的用戶端有多個執行個體,都通路同一個服務uri,是一個用戶端抽象

同類型的用戶端有多個執行個體,通路n(n>1)個不同的服務uri,則應有n個用戶端抽象

不同類型的用戶端有若幹執行個體,都通路同一個服務uri,是一個用戶端抽象

不同類型的用戶端有若幹執行個體,通路n(n>1)個不同的服務uri,則應有n個用戶端抽象

那麼實踐微智能思想,自動化建構服務流,采用以下技術來捕獲這兩種資料:

1)中間件劫持技術

這裡的中間件是一個廣泛的服務運作時的代稱,它可能是應用伺服器(例如tomcat),類應用伺服器運作時(例如springboot)等。采用劫持技術的目的是希望無侵入的實作服務畫像,這裡的無侵入是無需研發團隊去做代碼埋點,也無需在服務代碼層面增加任何依賴(比如jar包)。

服務畫像的操作是發生在應用/服務啟動的階段,根據工業标準做類掃描和部署描述檔案分析提取畫像資料。由于每次啟動,都會觸發畫像,是以畫像資料一直保持最新的實際狀态。

2)用戶端劫持技術

用戶端劫持是根據用戶端實作,清楚分析用戶端的程式設計模型,然後通過程式設計模型配合用戶端實作源代碼,定位需要埋入劫持代碼的位置。從實作上它是以中間件劫持為基礎的,是以也是無侵入的,是對其進行擴充進而實作用戶端畫像。

用戶端畫像的操作是發生在調用實際發生的階段,并不像服務畫像可以在啟動階段一次捕獲,是以用戶端畫像的過程是逐漸積累的,最終達到完整勾勒。如果服務重新開機後,用戶端畫像會重新開始這個過程,同樣也保持最新的實際狀态。

其次,在實際建構時,還需要一種輔助資料,以達到更準确的拟合效果,這就是溯源資料。

溯源資料是從通路協定中提取的特征資料,用來追溯通路源頭以及通路可能經過的路徑。

通路協定可能是工業标準協定(http,rmi,soap,smtp等),也可能是自定義協定。一般來說協定載體都分為header和body兩個部分,這裡主要談談header,header存放協定必須的中繼資料。我們需要從這些中繼資料中找到可以用來描述通路源的線索。

典型場景是兩個服務之間可能通過正向或反向代理進行通路,僅僅依靠服務畫像和用戶端畫像是無法真正關聯這兩個服務(如下圖):

微服務治理實戰:服務流的自動化建構與應用

那麼通過提取各個代理的ip(溯源資料),就能掌握請求的通過路徑,進而關聯兩個服務(如下圖)。

微服務治理實戰:服務流的自動化建構與應用

接下來,在擷取服務流相關的基礎資料後需要進行一個拟合過程。

首先,建立每個服務抽象的ipo模型,ipo是指input(輸入),process(處理),output(輸出)。

微服務治理實戰:服務流的自動化建構與應用

輸入是使用溯源資料實作溯源感覺。這裡補充了浏覽器使用者這個抽象節點,模型展示了四種基本形态:業務服務直連,業務服務通過代理服務,浏覽器使用者直連,浏覽器使用者通過代理服務。

輸出是使用用戶端畫像實作調用感覺。模型展現了四種調用目标:代理服務,業務服務,資料服務,消息服務(注意:消息消費者實際也是用戶端,從關聯角度,并不作為輸入)。

處理是使用服務畫像實作服務抽象。

接着,當每個服務抽象的ipo模型建立後,就可以進行拟合。拟合的基本算法是離散點的有向圖比對(廣度優先better)。在實際生産中,我們還進行了一些優化,因為實際情況複雜得多,而且算法複雜度在萬級節點時會有各種瓶頸:

增加了未知服務(可能是第三方系統),未知服務隻能出現在溯源感覺和調用感覺中,它沒有ipo模型

已知節點優先原則,它有完整的ipo模型,它的調用和溯源是必然存在的,避免重繪

優先調用關聯,後處理溯源關聯。調用關聯包含其他已知節點(可自動延續繪制),終結點(各種資料源,mq,無調用無溯源),未知節點(無溯源,可能有調用)

下面以tomcat+jee服務為例,剖析關鍵實作 。

java技術棧實作代碼劫持是依賴兩種常見的aop技術(java三闆斧之一)。

位元組碼程式設計:不同jdk版本可能存在相容性問題,謹慎使用。推薦javassit,如果需要支援多版本jdk,需要考慮根據不同版本動态加載相容的javassit。我們是在劫持入口類的方法上使用,在之前或之後增加代碼,盡量避免修改代碼(減少出錯,通用性更強)。

java原生代理:無接口不代理。多多益善,性能影響小,無相容問題。

為了擷取服務畫像和溯源資料,先對tomcat進行中間件劫持。劫持核心是掌控tomcat classloader tree,獲得優先加載權,進而可以改變這些行為。盡管各種jee應用伺服器實作不同,但其classloader tree結構基本類似。通過植入一個classloader來擷取優先加載權。通過加載改寫後的class,來改變行為。我們把這個classloader稱為uavclassloader(無人機類加載器):

微服務治理實戰:服務流的自動化建構與應用

uavclassloader算法基本原理

1) uavclassloader建立時,将能夠讀取到的class檔案對應的class名存儲到classmap中。

2)将tomcatloader設定為uavclassloader的parent。

3)将uavclassloader設定為tomcatloader的一個屬性。

4)重寫tomcatloader的loadclass方法。

如果useuavclassloaderflag為true,則使用uavclassloader.loadclass;

加載成功則傳回class;

失敗則使用tomcatloader自己的loadclass;

5)uavclassloader的loadclass方法。

如果classmap中含有要加載的class,則使用自己的findclass加載class

否則,将useuavclassloaderflag設定為false;

使用tomcatloader.loadclass(注:這時tomcatloader會直接用自己的loadclass);

将useplusloader flag設定為true。

服務畫像收集

jee服務啟動實際是web容器的建立過程。在tomcat中的standardcontext就是web容器的根類,在其加載的時候,uavclassloader會感覺,通過改寫或位元組碼手段在其start方法的最後植入代碼,完成兩個步驟:

1)收集将web容器的上文資訊:包括webappclassloader執行個體,context path,應用名,servletcontext,basepath(應用實際路徑),workdir(應用工作目錄)等

2)植入應用、服務畫像的代碼。服務畫像是按照技術規範,常見的技術規範:servlet,jaxws,jaxrs,spring,rmi,rpc(netty,thrift,hessian等)。針對每種技術規範從3個方面進行收集:

class和method:通過java的反射方式提取資訊,如服務類名,方法名,入參出參。

annotation:通過注解掃描工具提取具有相關注解的類,然後通過注解api提取注解資訊。

部署描述符:通過webappclassloader擷取web.xml, spring-config.xml, log4j.xml等部署描述符檔案路徑,然後使用dom解析提取關注的tag資訊。

微服務治理實戰:服務流的自動化建構與應用

溯源資料收集

溯源資料的捕獲實際與服務監控資料捕獲發生在同一個階段。運用中間件劫持技術改寫tomcat的coyoteadaptor.service()方法,它負責整個tomcat的請求處理,在方法開頭攔截請求,方法結尾攔截響應。這裡擷取應用伺服器,應用,所有的url的性能名額;同樣,運用中間件劫持技術改寫tomcat的standardwrapper.service()方法,它負責servlet的請求處理,同上如法炮制,在這裡捕獲溯源資料即可,同時也擷取服務的性能名額。

微服務治理實戰:服務流的自動化建構與應用

tomcat是以http協定為基礎的。http協定的header中的字段可以幫助溯源:

client address:直連用戶端ip位址

x-forwarded-for: 如果存在,則為代理路由位址鍊,則直連用戶端為代理服務

host:表明遠端主機甚至端口資訊,如果直連用戶端是代理服務,則host為代理ip位址和端口

user-agent:代理描述,可用來區分浏覽器還是程式用戶端,當然還可以提取很多浏覽器終端資訊。

同時,還可以提取一些自定義的header資訊幫助拟合,這需要結合用戶端劫持,下文會進行說明。

用戶端畫像收集

首先要标準化用戶端畫像的中繼資料體系。調用感覺是基于調用位址,通路協定,調用結果的特征提取來确定目标服務的。

1)調用位址:以類uri格式。

http/https服務(業務/代理服務): http://:/

關系型資料庫(資料源服務): jdbc:<資料庫類型>://:,:/<資料庫名>

非關系型資料庫或緩存(資料源服務):<資料源類型>://:,:/<資料庫集合名>

消息隊列(消息服務):mq:<消息中間件類型>://:/<隊列名>

2)通路協定:某種通路動作。例如http的post,sql插入,發送/訂閱消息,redis的hgethashall,mongodb的collection操作等。

3)通路結果特征:服務的基礎棧類型,是否叢集,例如nginx,tomcat,apache等。

接下來,就是通過用戶端劫持,以常用的http用戶端apache httpclient為例,隻需兩步:

識别org.apache.http.impl.client.internalhttpclient是apache同步用戶端的核心類

運用位元組碼改寫其doexecute方法,在方法的開頭和結尾插入畫像代碼擷取調用感覺的特征資訊

前文還提到為了幫助溯源感覺,可以在上遊服務的用戶端,通過用戶端劫持在通路協定的header中加入自定義的一些資訊。

例如為了在拟合時,合并兩個通過http代理服務關聯的服務,在上遊服務用戶端調用時,可以添加一個header字段(比如:uav-client-src),這個字段存放服務抽象的唯一辨別;當下遊服務提取溯源資料時,可以将該字段取出,作為源頭服務的唯一辨別,這樣就能完成合并。

微服務治理實戰:服務流的自動化建構與應用

3服務流的應用場景

場景一:具現化的應用/服務運維

我們的服務監控系統叫無人機,代号uav。uav定義了服務流的三種視圖:

1)應用/服務級:如果是單體架構或soa架構,就是應用叢集;如果是微服務架構,就是服務叢集。叢集内每個程序就是一個應用/服務執行個體。

2)應用/服務組級:這是個邏輯概念,可以根據産品線或業務架構來确定。它由多個不同類型的應用/服務叢集組成。

3)全網級:就是整個idc中心所有應用/服務叢集。

在ipo模型基礎上定義視圖的表現層(如下圖):

微服務治理實戰:服務流的自動化建構與應用

下面是實際系統截圖:

應用/服務級視圖(app /service cluster)

微服務治理實戰:服務流的自動化建構與應用

應用/服務組級視圖(app/service business group)

微服務治理實戰:服務流的自動化建構與應用

全網服務流視圖(global service business topology)

微服務治理實戰:服務流的自動化建構與應用

全網視圖又叫服務星雲,因為上圖是縮放後的效果,全網可能如下圖:

微服務治理實戰:服務流的自動化建構與應用

或者:

微服務治理實戰:服務流的自動化建構與應用

場景二:服務風控與關聯分析

這是利用服務的關聯,在一個完整業務鍊路(由一系列的服務組成),當某些服務出現問題(比如很慢)時,可以通過關聯分析快速定位問題源并自動的采取某些措施,常用的措施:實時的,自動化及時管控/熔斷等;預測整體業務鍊路風險,提前可控切換或其他預案措施。

場景三:自動化調用鍊生成

調用鍊一直是服務治理的熱門話題。經典的做法是在業務代碼中進行埋點。通過自動化建構服務流之後,可以大量減少埋點工作。通過一個比喻來說明為什麼可以達到這樣的效果,可以把服務流看成城市間的道路,每個請求的流動可以看成道路上的車輛,當道路已經很清楚的被描繪出來後,每輛車就可以被更自動的追蹤了。

基本思路:

1) 通過中間件劫持,在服務畫像的位置,産生或繼承請求id;

2) 通過用戶端劫持,在用戶端畫像的位置,産生或繼承請求id;

3) 在單線程模式下,自動傳遞請求id;

4) 在跨線程模式下,交換請求id,此處是唯一需要少量的代碼埋點的場景。

由于篇幅的關系,對于場景二,三沒有展開說明,希望未來可以和大家分享。

4總結

最後,總結一下。服務流是應用拓撲的擴充,可以更加深入細緻的描繪服務的關聯關系。可以通過中間件劫持,用戶端劫持,溯源資料提取等手段實作服務抽象的拟合,進而自動化的建構服務流。具體落地需要根據實際使用的技術棧來考慮,本文列舉了tomcat+jee應用的場景下的一種實作方法供大家參考。另外,服務流可以被應用到很多生産場景中去,例如服務監控,服務風控,自動化調用鍊等。

原文釋出時間為:2017-01-16

本文來自雲栖社群合作夥伴dbaplus