日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

美团服务体验平台对接业务数据的最佳实践-海盗中间件

發(fā)布時間:2024/7/5 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 美团服务体验平台对接业务数据的最佳实践-海盗中间件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

背景

移動互聯網時代,用戶體驗為王。美團服務體驗平臺希望能夠幫助客戶解決在選、購、用美團產品過程中遇到的各種問題,真正做到“以客戶為中心”,為客戶排憂解難。但服務體驗平臺內部只維護客戶的客訴數據,為了精準地預判和更好地解決客戶遇到的問題,系統必須依賴業(yè)務部門提供的一些業(yè)務數據,包括但不限于訂單數據、退款數據、產品數據等等。 本文會著重講一下在整個系統交互過程中遇到的一些問題,然后分享一下在實踐中探索出來的經驗和方法論,希望能夠給大家?guī)硪恍﹩l(fā)。

問題

對接場景廣而雜

首先,需要接入服務體驗平臺服務(包括直接面向用戶的C端服務、面向客服的工單服務等等)的業(yè)務方非常多且雜,而且在不斷拓展。美團有非常多的業(yè)務線,比如外賣、酒店、旅游、打車、交通、到店餐飲、到店綜合、貓眼等等。其中部分業(yè)務又延展出多條子業(yè)務線,比如大交通部門包含火車票、汽車票、國內機票、國際機票、船票等等。具體到每一條子業(yè)務線的每一個業(yè)務場景,客戶都有可能會遇到問題。對于這些場景,服務體驗平臺服務都需要調用對應的業(yè)務數據接口,來幫助用戶自助或者客服協助解決這些問題。就美團現有的業(yè)務而言,這樣的場景數量會達到萬級。而且業(yè)務形態(tài)在不斷迭代,還會有更多的場景被挖掘出來,這些都需要持續(xù)對接更多的業(yè)務數據來進行支撐。

接入場景定制化要求高

其次,接入服務體驗平臺服務的業(yè)務方定制化要求很高。因為業(yè)務場景的差異化非常大,不同的接入方都希望能夠定制特殊復雜邏輯,需要服務體驗平臺提供的服務解決方案與業(yè)務深度耦合。這就需要服務體驗平臺側對接入方業(yè)務邏輯和數據接口深入了解,并對這些業(yè)務數據進行組裝,針對每個場景進行定制開發(fā)。

方案

早期方案

為了解決上述問題,初期在做系統設計時候,考慮業(yè)務方多是既有系統,所以服務體驗平臺服務趨向平臺化設計,并引入了適配層。服務體驗平臺內部對所有的業(yè)務數據和邏輯進行統一抽象,對內標準化接口,屏蔽掉業(yè)務邏輯和接口的差異。所有的定制化邏輯都在適配層中封裝。但這需要客服側RD對所有的場景去編寫適配器代碼,將從一個或者多個業(yè)務部門接口中拿到的業(yè)務數據,轉成內部實際場景需要的數據。

其系統交互如下圖所示:

缺點

雖然上述系統設計能滿足業(yè)務上的要求,但是存在兩個比較明顯的缺點。

編碼工作量繁重

如上圖所示,每個業(yè)務場景都需要編寫適配器來滿足需求,如果依賴的外部接口比較少,場景也比較單一,按照上述方案實施還可以接受。但業(yè)務接入非常多且雜,給客服側RD帶來了非常繁重的工作量,包括適配器編寫以及后續(xù)維護過程中對下游業(yè)務接口的持續(xù)跟蹤和監(jiān)控。

客服側RD需要深入了解業(yè)務方邏輯

另外,由于客服側RD對于業(yè)務模型的不熟悉,解析業(yè)務模型然后組裝最終展示給客戶的數據,需要比業(yè)務方RD花更多的時間來梳理和實現,并且花費更多的時間來驗證正確性。比如下面是一個真實的組裝業(yè)務接口并對業(yè)務數據進行處理的案例:

public class TicketAdapterServiceImpl implements OrderAdapterService {@Resource(name = "tradeQueryClient")private TradeTicketQueryClient tradeTicketQueryClient;@Resourceprivate ColumbusTicketService columbusTicketService;/** * 根據訂單ID獲取門票相關的訂單數據、門票數據、退款數據等**/@Overridepublic OrderInfoDTO handle(OrderRequestDTO orderRequestDTO) {List<ITradeTicketQueryService.TradeDetailField> tradeDetailFieldList = new ArrayList<ITradeTicketQueryService.TradeDetailField>();tradeDetailFieldList.add(ITradeTicketQueryService.TradeDetailField.ORDER);tradeDetailFieldList.add(ITradeTicketQueryService.TradeDetailField.TICKET);tradeDetailFieldList.add(ITradeTicketQueryService.TradeDetailField.REFUND_REQUEST);try {//通過接口A得到部分訂單數據、門票數據和退款數據RichOrderDetail richOrderDetail = tradeTicketQueryClient.getRichOrderDetailById(orderRequestDTO.getOrderId(), tradeDetailFieldList);if (richOrderDetail == null) {return null;}if (richOrderDetail.getOrderDetail() == null) {return null;}OrderDetail orderDetail = richOrderDetail.getOrderDetail();RefundDetail refundDetail = richOrderDetail.getRefundDetail();OrderInfoDTO orderInfoDTO = new OrderInfoDTO(); //解析和處理接口A返回的字段,得到客服側場景真正需要的數據orderInfoDTO.put("dealId", orderDetail.getMtDealId());orderInfoDTO.put(DomesticTicketField.VOUCHER_CODE.getValue(), getVoucherCode(richOrderDetail));orderInfoDTO.put(DomesticTicketField.REFUND_CHECK_DUE.getValue(), getRefundCheckDueDate(richOrderDetail));orderInfoDTO.put(DomesticTicketField.REFUND_RECEIVED_DUE.getValue(), getRefundReceivedDueDate(richOrderDetail));//根據接口B獲取另外一些訂單數據、門票詳情數據、退款數據ColumbusTicketDTO columbusTicketDTO = columbusTicketService.getByDealId((int) richOrderDetail.getOrderDetail().getMtDealId());if (columbusTicketDTO == null) {return orderInfoDTO;}//解析和處理接口B返回的字段,得到客服側場景真正需要的數據orderInfoDTO.put(DomesticTicketField.REFUND_INFO.getValue(), columbusTicketDTO.getRefundInfo());orderInfoDTO.put(DomesticTicketField.USE_METHODS.getValue(), columbusTicketDTO.getUseMethods());orderInfoDTO.put(DomesticTicketField.BOOK_INFO.getValue(), columbusTicketDTO.getBookInfo());orderInfoDTO.put(DomesticTicketField.INTO_METHOD.getValue(), columbusTicketDTO.getIntoMethod());return orderInfoDTO;} catch (TException e) {Cat.logError("查詢不到對應的訂單詳情", e);return null;}} }

探索

將適配層交由業(yè)務方實現

為了克服早期方案的兩個缺點,最初,我們希望能夠把場景數據的準備和業(yè)務模型的解析工作,都交給對業(yè)務比較熟悉的團隊來處理,即將適配層交由業(yè)務方來實現。

這樣做的話優(yōu)勢和劣勢也比較明顯。

優(yōu)勢

客服這邊關注自己的領域服務就好,做好平臺化,數據提供都交給業(yè)務團隊,解放了客服側RD。

劣勢

但對業(yè)務方來說帶來了比較大的工作量,業(yè)務方既有服務的復用性很低,對客服側每一個需要數據的場景,都要重新封裝新的服務。

更好的解決方案?

這個時候我們思考:是否可以既能讓業(yè)務方解析自己的業(yè)務數據,又能夠盡量利用既有服務呢?我們考慮把既有服務的組裝過程以及模型的轉換都讓一個服務編排的中間件來實現。但是使用這個中間件有一個前提,就是業(yè)務方提供出來的既有服務必須支持泛化調用,避免調用方直接依賴服務方客戶端(文章下一個小節(jié)也會補充下對于泛化調用的解釋)。其交互模型如下圖所示:

結果-海盜中間件

簡介

什么是海盜?

海盜就是一個用來對支持泛化調用(上述所說)的服務進行編排,然后獲取預期結果的一個中間件。使用該中間件調用方可以根據場景來對目標服務進行編排,按需調用。

何為泛化調用?

通常服務提供方提供的服務都會有自己的接口協議,比如一個獲取訂單數據的服務:

package com.dianping.demo;public interface DemoService{OrderDTO getById(String orderId);}

而調用方調用該服務需要引入該接口協議,即依賴該服務提供的JAR包。如果調用方需要集成多方數據,那就需要依賴非常多的API,同時服務方接口升級客戶端也需要隨之進行升級。而泛化調用就可以解決這個問題,通過泛化調用客戶端可以在服務方沒有提供接口協議和不依賴服務方API的情況下對服務進行調用,通過類似GenericService這樣一個接口來處理所有的服務請求。

如下是一個泛化調用的Demo:

public class DemoInvoke{public void genericInvoke(){/** 調用方配置 **/ InvokerConfig<GenericService> invokerConfig = new InvokerConfig("com.dianping.demo.DemoService", com.dianping.pigeon.remoting.common.service.GenericService.class);invokerConfig.setTimeout(1000);invokerConfig.setGeneric(GenericType.JSON.getName());invokerConfig.setCallType("sync"); /** 泛化調用 **/final GenericService genericService = ServiceFactory.getService(invokerConfig);List<String> paramTypes = new ArrayList<String>();paramTypes.add("java.lang.String");List<String> paramValues = new ArrayList<String>();paramValues.add("0000000001");String result = genericService.$invoke("getById", paramTypes, paramValues);}}

有了這個泛化調用的前提,我們就可以重點去思考如何對服務進行編排,然后對取得的結果進行處理了。

DSL設計

首先重新梳理一下海盜的設計目標:

  • 對既有服務進行編排調用
  • 對獲取的數據進行處理

而為了實現服務編排,需要定義一個數據結構來描述服務之間的依賴關系、調用順序、調用服務的入參和出參等等。之后對獲取的結果進行處理,也需要在這個數據結構中具體描述對什么樣的數據進行怎么樣的處理等等。

所以我們需要定義一套DSL(領域特定語言)來描述整個服務編排的藍圖,其語法如下:

{//定義好需要調用的接口以及接口之間的依賴關系,一個接口調用即為一個task"tasks": [ //第一個task{ "url": "http://helloWorld.test.hello", //url 為pigeon發(fā)布的遠程服務地址:"alias": "d1", //別名,結果取值的時候可以通過別名引用"taskType": "PigeonGeneric", //task的類別一般可以設置為PigeonGeneric,默認是pigeonAgent方式。"method": "getByDoubleRequest", //要調用的pigeon接口的方法名"timeout": 3000, //task的超時時間"inputs": { //入參情況,多個入參通過key:value的結構書寫,key的類別通過下面的inputsExtra定義。"helloWorld": {"name": "csophys", //可以通過#orderId,從上下文中獲取值,可以通過$d1.orderId的形式從其他的task中獲取值"sex": "boy"},"name": "winnie"},"inputsExtra": { //入參key的類別定義"helloWorld": "com.dianping.csc.pirate.remoting.pigeon.pigeon_generic_demo_service.HelloWorld","name": "java.lang.String"} },//另一個task{ "url": "http://helloWorld.test.hello","alias": "d2","taskType": "PigeonGeneric","method": "getByDoubleRequest","inputsExtra": {"helloWorld": "com.dianping.csc.pirate.remoting.pigeon.pigeon_generic_demo_service.HelloWorld","name": "java.lang.String"},"timeout": 3000,"inputs": {"helloWorld": {"name": "csophys","sex": "boy"},"name": "winnie"}}],"name": "pigeonGenericUnitDemo", //DSL的名稱定義,暫時沒有特別含義"description": "pigeon泛型調用測試", //DSL的描述"outputs": { //定義好最后輸出的數據模型"d1name": "$d1.name","languages": "$d2.languages","language1": "$d2.languages[0]","name": "csophys"} }

架構設計

有了DSL來描述整個編排藍圖之后,海盜自然要對該DSL進行解析,然后對服務進行具體調用。其整體架構如下所示:

其中涉及到幾個重點概念:

  • Facade:對外提供統一接口,供客戶端調用。
  • Parser:對于輸入的DSL進行解析,解析成內部流轉的數據結構,同時得到所有的task,并且構建task調用邏輯樹。
  • Executor:真實發(fā)起調用的模塊,目前支持平臺內部的Pigeon和MTThrift調用方式,同時對HTTP等其他協議有良好的擴展性。
  • DataProcessor:數據后處理。這邊會把所有接口拿到的數據轉換層客服場景這邊需要的數據,并且通過設計的一些內部函數,可以支持一些如數據半脫敏等功能。
  • 組件插件化:對日志等功能實現可插拔,調用方可以自定義這些組件,即插即用。

主要Feature

海盜具有如下主要特點:

  • 采用去中心化的設計思路,引擎集成在SDK中。方案通用化,每一個需要業(yè)務數據的場景都可以通過海盜直接調用數據提供方。
  • 服務編排支持并行和串行調用,使用方可以根據實際場景自己構造服務調用樹。通過DSL的方式把之前硬編碼組裝的邏輯實現了配置化,然后通過海盜引擎把能并行調用的服務都執(zhí)行了并行調用,數據使用方不用再自己處理性能優(yōu)化。
  • 使用JSON DSL 描述整個工作藍圖,簡單易學。
  • 支持JSONPath語法對服務返回的結果進行取值。
  • 支持內置函數和自定義指令(語法參考ftl)對取到的元數據進行處理,得到需要的最終結果。
  • 編排服務樹可視化。
  • 目前集團內部RPC中間件包括Pigeon、MTThrift,已進行了泛化調用支持,可以通過海盜實現Pigeon服務和MTThrift的服務編排。不需要限制業(yè)務團隊的服務提供方式,但需要升級中間件版本。這里特別感謝服務治理團隊的大力支持。

Tutorial

場景:需要根據訂單ID查詢訂單狀態(tài)和支付狀態(tài),但目前沒有現成的接口支持該功能,但有兩個既有接口分別是:

  • 接口1:根據訂單ID,獲取到訂單狀態(tài)和支付流水號
  • 接口2:根據支付流水號獲取支付狀態(tài)

那我們可以對這兩個接口進行編排,編寫DSL如下:

{"tasks": [{"url": "http://test.service","alias": "d1","taskType": "PigeonGeneric","method": "getByOrderId","timeout": 3000,"inputs": {"orderId": "#orderId"},"inputsExtra": {"name": "java.lang.String"}},{"url": "http://test.service","alias": "d2","taskType": "PigeonGeneric","method": "getPayStatus","timeout": 3000,"inputs": {"paySerialNo": "$d1.paySerialNo"},"inputsExtra": {"time": "java.lang.String"}}],"name": "test","description": "組裝上述接口獲取訂單狀態(tài)和支付狀態(tài)","outputs": {"orderStatus": "$d1.orderStatus","payStatus": "$d2.payStatus"} }

然后客戶端進行調用:

String DSL = "上述DSL文件";String params = "{\"orderId\":\"000000001\"}";Response resp = PirateEngine.invoke(DSL, params);

最后得到的數據即為調用場景真正需要的數據:

{"orderStatus":1,"payStatus":2 }

開發(fā)流程變化

因為獲取數據的架構產生了變化,開發(fā)流程也隨之發(fā)生改變。

如圖所示,因為減少了客服側RD不斷去向業(yè)務方RD確認返回的數據含義和邏輯,雙方RD各自專注各自熟悉的領域,開發(fā)效率和最終結果準確性都有顯著提升。

總結和展望

最后總結一下使用海盜之后的優(yōu)勢

  • 去中心化的設計,可用性得到保證。
  • 服務復用性高,領域劃分更加清晰,讓RD專注在自己熟悉的領域,降低研發(fā)成本。
  • 因為流程變化后,業(yè)務方可以提前驗證提供的數據,高質量交付。
  • 客服側對數據獲取進行統一收口,可以對所有調用服務統一監(jiān)控并對數據統一處理。

展望

海盜的技術規(guī)劃:

  • 豐富內部函數和運算表達式:目前海盜提供了一部分簡單的內部函數用來對取到的值進行簡單處理,同時正在實現支持調用方自定義運算表達式來支持復雜場景的數據處理,這部分需要持續(xù)完善。
  • 屏蔽遠程調用協議異構性:目前海盜只支持對美團Pigeon和MTThrift服務進行編排,這里要對協議進行擴展,支持類似HTTP等通用協議,同時支持調用方自定義協議和調用實現。
  • 運營工具完善:提供一個比較完整的運營工具,調用方可以自行配置DSL并進行校驗,然后一鍵調用查詢最終結果。同時調用方可以通過該工具進行日志、報表等相關數據查詢。
  • 自動生成單元測試:能夠把經過驗證的DSL生成相應的單元測試用例給到數據提供方,持續(xù)保障提供的DSL的可用性和正確性。

作者簡介

  • 王彬,美團資深研發(fā)工程師,畢業(yè)于南京大學,2017年2月加入美團。目前主要專注于智能客服領域,從事后端工作。
  • 陳勝,海盜項目負責人,智能客服技術負責人,2013年加入大眾點評。在未來智能客服組會持續(xù)在平臺化和垂直領域方向深入下去,為消費者、商家、企業(yè)提供更加智能的客戶服務體驗。

招聘廣告

服務體驗平臺可以深入接觸到公司的所有業(yè)務,推進業(yè)務改善產品。提升客戶的服務體驗。打造一個客戶貼身的智能服務助手。通過技術的手段更快地解決客戶的問題,并且最大程度地節(jié)省客服的人力成本。歡迎有意向的同學加入服務體驗平臺,上海、北京都有需求。簡歷請投遞至:sheng.chen#dianping.com

總結

以上是生活随笔為你收集整理的美团服务体验平台对接业务数据的最佳实践-海盗中间件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 开心激情网站 | 亚洲一区二区三区在线视频 | 成人黄色免费网址 | 中文字幕久久熟女蜜桃 | 涩涩网站在线 | 天堂国产 | 国产精品久久久久久久午夜 | 日本午夜视频在线观看 | 日韩欧美无 | 特黄aaaaaaaaa毛片免费视频 | 日韩大片免费观看 | 久久久这里有精品 | 国产麻豆剧传媒精品国产av | 亚洲国产精品一区二区三区 | 男女无遮挡免费视频 | 99产精品成人啪免费网站 | 中文字幕有码在线 | 在线精品国产 | 亚洲一区美女 | 国产成人精品123区免费视频 | 成人av入口 | 91精品系列 | 拍摄av现场失控高潮数次 | 91国产大片| 噼里啪啦免费看 | 福利在线看 | 中文字幕av不卡 | 色妞网| 久久人人草| 国产一级黄色电影 | 波多野结衣一级 | 免费人成网 | 狠狠干狠狠操 | 999超碰 | 欧美一线高本道 | 国产嫩草影院久久久久 | 神马国产 | 欧美国产日韩在线 | 在线免费观看日韩av | 久久五月天av | 香蕉国产精品视频 | 黄片毛片| 最新黄色网页 | 午夜黄色小视频 | 国产第20页| 亚洲精选一区二区三区 | 爱操影院 | 日本少妇大战黑人 | 国产精品中文字幕在线 | av资源站最新av| 久久亚洲AV成人无码国产人妖 | 成人av片在线观看 | 国产视频精选 | 免费播放毛片 | 红桃视频一区二区三区免费 | 桃色一区 | 99re这里 | 国产精品电影院 | 在线观看欧美 | 成人看片 | 亚洲91久久 | 精品久久久中文字幕 | 2025韩国大尺度电影 | 一卡二卡三卡四卡 | 色偷偷五月天 | 久久久久久久偷拍 | 精品91av| 久久99精品久久只有精品 | 久久99色 | 欧美人与性动交α欧美精品 | 天天看片中文字幕 | 女裸全身无奶罩内裤内衣内裤 | 91久久精品一区二区三 | 亚洲最新在线观看 | 操操操av| 在线免费观看a视频 | 特淫毛片 | 91视频毛片 | 一区二区三区欧美在线 | 国产欧美日本 | 免费色网 | 色综合久久五月 | 国产精品熟女一区二区不卡 | 国产一区二区在线免费观看 | 国产女主播喷水视频在线观看 | 啪啪av| 蜜桃av成人 | 国产精品无码午夜福利 | 欧美性视频播放 | 成人短视频在线观看 | 亚洲av色区一区二区三区 | 国产精品久久久久蜜臀 | 男女午夜激情视频 | 国内黄色一级片 | 欧洲亚洲一区二区 | 日韩黄色在线观看 | 国产一区二区波多野结衣 | 日本丰满少妇做爰爽爽 | 黑人满足娇妻6699xx |