基於APM實現RPC服務和消息隊列的指定消費

 

本文內容是基於公司現有框架整理的一篇專利文章.該框架包含完整的一套DevOps流程,包括工單系統(容器申請、服務部署等)\配置中心\路由配置中心\服務治理平臺\消息治理平臺\葛朗臺(基於Docker+K8S)等.前端

該專利的目的爲:在業務場景比較複雜,業務流程比較長而且涉及Dubbo\消息隊列等服務調用時,指定服務路由和消息路由等,從而實現服務和消息的指定消費功能,可方便測試或者開發人員的工做.java

轉載請說明出處.git

 1.背景

  隨着公司業務的發展和增加,一個完整的業務流程涉及到不少服務,各個服務可能同時又由於版本迭代或者其餘需求部署了多套環境,致使同一服務存在多個版本,而各個服務之間可能經過RPC服務或者消息隊列存在關聯,使整個業務流程的服務調用呈現爲樹狀結構,每個分支是一種可能的調用鏈路。在測試過程當中,測試人員想要按照特定的調用鏈路進行功能測試變得錯綜複雜,難以實現。github

  在進行某個服務的功能測試時,不少狀況下須要調用指定生產者的RPC服務或者消息被指定消費者消費。對於RPC服務調用來講,消費者服務調用提供者每每會隨機調用一個提供者服務;對於消息隊列來講,消息會被隨機的消費者消費,從而達不到調用指定環境的某個服務或者消息被指定服務的消費者消費的目的,爲測試帶來很大不便,致使工做效率低。apache

當前測試過程存在的問題總結以下:

  1. 服務調用鏈路沒法指定。服務與服務之間調用鏈路複雜,沒法指定具體的服務調用鏈路,服務與服務之間隨機調用,達不到測試目的。
  2. RPC消費者沒法指定消費特定的提供者。每一個服務存在多個版本,致使RPC服務提供者會存在多個,當RPC消費者調用提供者時,會隨機調用一個提供者的服務,沒法實現服務的指定消費功能。
  3. MQ隊列消息沒法被指定的消費者消費。MQ生產者生產的消息,會被隨機的消費者消費,特定消息被指定的消費者消費沒法實現。
  4. 完整的服務調用鏈路沒法可視化。對於用戶,服務的調用過程徹底透明,沒法直觀的查看服務調用過程,即服務調用的具體節點信息等。

  針對以上問題,提出了基於應用性能管理(Application Performance Management,簡稱APM)java agent技術在對業務代碼無侵入徹底透明的狀況下,結合路由碼(Route Code),實現RPC服務(下以Dubbo爲例)KafkaRabbitMQ等消息隊列的指定消費功能,也稱爲路由功能,實現了服務調用按照指定的調用鏈路執行,極大的提升了測試效率和測試的方便性。架構

2.平臺框架圖

 

架構說明:

  1. 在一般狀況下,業務的測試流程是經過前端H5頁面或者經過接口工具等觸發測試流程。其中整個業務流程可能的涉及的調用鏈路包括Http、SpringMVC、Dubbo、RabbitMQ、Kafka等。
  2. Squid代理,負責將不論是IP訪問仍是域名訪問,統一構建出Http Header,置入用戶IP或用戶標識,即路由碼。
  3. 基於現有的服務調用鏈路,提出路由碼(Route Code)概念,結合APM和java agent技術,在對業務代碼無侵入,徹底透明的狀況下,實現路由碼、服務調用鏈路的層層服務傳遞和基於路由碼的指定消費功能,包括Dubbo指定消費、RabbitMQ隊列指定消費和Kafka指定消費。

具體技術方案描述以下:

  1. 首先創建路由配置中心(Route Configure Center),配置路由碼(路由碼能夠是IP或者隨機生產的字符串)對應的消費關係等元數據,即攜帶該路由碼的Dubbo消費者或者消息將調用哪些服務提供者或者被哪些消費者消費。經過改造Skywalking(APM),結合TransmittableThreadLocal(在使用線程池等會池化複用線程的組件狀況下,提供ThreadLocal值的傳遞功能,解決異步執行時上下文傳遞的問題),將路由碼在服務調用鏈路過程當中向下傳遞,開發符合業務流程需求的Snowwalking。
  2. 經過Snowwalking,開發SpringMVC攔截器。對SpringMVC的DispatcherServlet類進行攔截加強,獲取請求的Http Header做爲路由碼並組裝鏈路信息,放入TransmittableThreadLocal中,便於後繼服務調用路由碼的向下傳遞。
  3. 經過Snowalking,開發Http的攔截器。對Http請求進行攔截加強,若是TransmittableThreadLocal中存在路由碼和鏈路信息,則將TransmittableThreadLocal內容取出放入Http請求Header中,不然獲取當前請求節點IP做爲路由碼放入TransmittableThreadLocal中,並設置入Http請求的Header中。
  4. 經過Snowwalking,開發RabbitMQ攔截器。對RabbitMQ的生產者和消費者分別作攔截加強。對於生產者,對生產類進行攔截加強,將TransmittableThreadLocal內容取出放入消息的Properties中,將路由碼和鏈路信息向下傳遞。對於消費者,對消費者的消費方法進行攔截加強,當消費者隨機拉取一條消息後,將消息Properties中的路由碼取出,根據在路由配置中心配置和消息治理平臺(Message Governance Platform,簡稱MGP,用於配置服務之間消息發佈、消費關係等元數據)判斷當前消費者是否有消費權限,若是有消費權限,則當前消費者可繼續消費該消息,不然,該消費者沒法消費該消息,將該消息從新入隊到消息隊列,再從新從消息隊列拉取其餘消息進行消費,其中還包括處理特殊狀況下的消息丟棄和消息重發等。
  5. 經過Snowwalking,開發Dubbo攔截器。對Dubbo消費者的調用入口方法進行攔截,根據當前TransmittableThreadLocal中的路由碼、路由配置中心路由元數據以及服務治理平臺(Service Governance Platform,簡稱SGP,用於配置各個服務發佈、消費關係等元數據)生產消費關係元數據,獲取當前Dubbo消費者可消費的生產者,過濾Invoker列表,將符合配置的生產者返回給消費者,從而實現Dubbo服務根據路由碼實現指定消費功能。
  6. 經過Snowwalking,開發Kafka攔截器。對Kafka的生產者和消費者分別進行攔截加強。對於生產者,對消息發送類進行攔截加強,若是Kafka的版本低於0.11,則從TransmittableThreadLocal中解析出路由碼,經過特定格式存入消息的Payload中;若是Kafka的版本高於0.11版本,則將TransmittableThreadLocal中的路由碼以及鏈路信息存入消息的Header中,發送至Kafka。同理,對於消費者,想要實現Kafka的指定消費,前提是經過參數加強或者其餘方式,將消費者的group.id隔離成不一樣的值,使須要執行指定消費的消費者屬於不一樣的group,這樣每一個消費者均可以消費某個Topic的全部partition。而後對Kafka的消費方法進行攔截加強,若是Kafka的版本低於0.11,則消費服務解析消息Payload,獲取路由碼,而後經過路由配置中心配置的消費關係,判斷當前消費者是否有權限消費該條消息,若是有權限,則消費,不然,跳過該消息,繼續執行獲取下一條消息進行消費判斷;若是Kafka的版本高於0.11版本,則將路由碼和鏈路信息從消息Header中獲取出來,解析出路由碼,再經過統一路由配置中心配置的消費關係,判斷當前消費者是否有權限消費該條消息,邏輯同上。
  7. 若是存在服務其餘調用方式,一樣能夠對其進行加強攔截,實現路由碼和調用鏈路的向下傳遞等,而保證服務調用鏈路不間斷。
  8. 經過以上對各類調用鏈路作攔截加強,便可將路由碼結合APM、TransmittableThreadLocal和java agent技術在各類業務場景下進行傳遞,根據路由配置等元數據實現攜帶指定路由碼服務或者消息的指定消費功能。

3.關鍵技術點

  1.路由碼(Route Code)傳遞

  路由碼是指定消費的基礎。服務發起者在調用提供者時,會攜帶路由碼,服務提供者提供服務的同時,會經過Snowwalking獲取消費者的路由碼,並放入TransmittableThreadLocal中,使路由碼在鏈路中進行傳遞。下圖爲一種可能的服務調用鏈路路由碼傳遞時序圖:框架

  

  2.Snowwalking

  Snowwalking基於Skywalking改造,結合TransmittableThreadLocal,使路由碼在跨線程的狀況下,依然能夠進行傳遞。經過Snowwalking對服務鏈路的各類調用方式進行攔截加強,達到路由碼、調用鏈路信息向下傳遞和指定消費等功能,對業務代碼零侵入且徹底透明。異步

4.效果

  實現該技術方案以後,測試人員或者開發人員只須要進行簡單的配置便可實現RPC服務、RabbitMQ和Kafka等消息隊列的指定消費功能,知足了測試需求的同時極大的提升了相關工做人員的工做效率,該技術方案簡單高效,針對開發人員和測試人員徹底透明且對業務代碼無侵入,不會影響生產環境服務和消息的隨機消費。工具

  下圖給出了一種服務指定消費關係。假設路由配置中心配置路由碼code1對應的路由鏈路爲B1,C2,D3,則前端H5頁面觸發測試流程時,經過Squid代理將路由Code(code1)設置到Http請求的Header當中,當SpringMVC接收到Http請求時,就會被SpringMVC plugin攔截,取出Http請求Header中的路由Code(code1)放入TransmittableThreadLocal中.當SpringMVC須要調用Dubbo服務B時,在服務調用以前就會被Dubbo plugin攔截,根據路由Code(code1)和路由Code配置的服務調用關係,過濾服務B的Invoker List,從而過濾出B1爲須要指定調用的服務,進而定向調用至服務B1,服務B調用服務C和服務C調用服務D邏輯相同,從而完成RPC服務的指定消費,其餘狀況同理,再也不贅述。性能

相關文章
相關標籤/搜索