內容來源:2017年5月13日,一條架構師管凱強在“Java開發者大會 | Java之美【上海站】”進行《API閘道器的設計思路及落地》演講分享。IT大咖說作為獨家視訊合作方,經主辦方和講者審閱授權釋出。
閱讀字數:2640 | 4分鐘閱讀
摘要
API閘道器是一個伺服器,是系統的唯一入口。從物件導向設計的角度看,它與外觀模式類似。API閘道器封裝了系統內部架構,為每個客戶端提供一個定製的API。
嘉賓演講視訊和PPT地址:t.cn/R9DZZ0h
背景
移動網際網路時代的挑戰
移動互聯時代迭代速率對於後端開發帶來了一些挑戰。
在我們公司的商品詳情頁上,包含了商品資訊、價格資訊、促銷資訊和推薦列表四個部分。
在開發過程中,我們想要把這四個資訊在一個介面訪問中全部吐出來,嘗試給出一個萬能介面。
事實上,我們在第一次這樣做的時候或許是靠譜的,但是當產品發生變更的時候,比如產品想把推薦列表換成熱銷榜,那麼之前做的萬能介面就已經不滿足這個業務場景了,只能新開一個V2版本。
這樣重複必然會導致介面的膨脹以及維護成本越來越高。
所以雖然我們都在追求一個萬能的解,但這個“解”也許並不存在。
微服務時代的挑戰
我們商品詳情頁的資料來自於商品系統、價格系統、推薦系統和營銷系統。而對於客戶端或使用者而言,其實沒有必要知道每個介面由哪個微服務提供的,只需得到資料即可。
所以我們面臨的問題就是怎樣避免讓客戶端感知微服務邊界的存在,不同的後端、前端團隊需要統一的介面設計、接入規範。
需求
使用API閘道器構建微服務
API閘道器是擋在所有微服務之前的一個透明層,是請求進入系統的唯一節點。基於這一點,一方面解決了對呼叫方隱藏微服務的系統邊界問題,另一方面負責服務請求路由及協議轉換。它可能還具有其它職責,如身份驗證、許可權控制、負載均衡、“請求整形”與管理。
實踐落地
從HTTP到RPC
在我們的APP和WEB上,所有請求都基於HTTP,RPC服務是基於DUBBO的RPC框架來做。
API閘道器做的最簡單的一件事就是能夠讓使用者發起的請求通過API閘道器轉成對RPC服務的呼叫,再回到使用者的APP上。
主要解決了HTTP請求到RPC呼叫例項的對映,以及把無型別的引數轉換為帶型別的引數。
實現了一個輕量級的MVC框架,將請求轉換為對RPC例項的呼叫。
從HTTP到RPC——定義好一個介面
我認為一個設計良好的介面一定包含了明確的異常編碼,以及這個異常編碼在什麼業務場景上出現,這個異常編碼怎樣在客戶端得到合適的處理。
還需要有一個明確的呼叫許可權說明,和清晰的引數列表、返回結果。
示例
如圖,這上面有一個ApiGroup,來描述業務模組的屬性。
這是我們某個特定的方法,和control有些相似。包含了API的方案名、SecurityType是許可權認證的level。
Designed ErrorCode是用來對客戶端介面明確報出異常。
入參描述有ApiAutowired和ApiParameter兩種型別。
從HTTP到RPC——API註冊
在API註冊流程中,我們首先做了ApiParser,用於解析API資訊,解析完之後會得到介面的完備資訊,包含了介面的描述及整個業務異常編碼的描述。
第二步是要建立一個RPC呼叫例項,也就是RpcInvoker。
接下來需要建立一個服務的動態代理,來解決無型別引數到RPC介面上的有型別引數的轉換。
最後是把proxy做一個快取。
從HTTP到RPC——proxy例項
這是一個動態生成proxy的例子。
我們用ASM位元組碼框架在執行期動態生成proxy。圖中函式是把string型別引數轉換為強型別引數。
從HTTP到RPC——處理請求
第一步解析請求,在URL中需要描述清楚HTTP呼叫哪些介面,解析請求就是要pass出這些資訊。
然後要做安全驗證,以保證什麼樣的請求才可以被路由到微服務的請求。
第三步構建API呼叫的上下文。上下文裡包含了使用者ID等資訊,這些資訊來自於使用者訪問令牌解密之後。
接下來就是做代理的執行,最後對結果做序列化。
從HTTP到RPC——安全策略
做安全策略的大體上的處理方法就是裝置識別、數字簽名,也包括HTTPS。
裝置識別主要是用於確認身份,依賴於一個叫token的訪問令牌來做。
在APP上使用者如果發起了登入,首先經過閘道器,然後到使用者服務,登入完成後下發appSecret和token。
APP在呼叫API之前要做數字簽名,需要一個簽名的金鑰,也就是下發的appSecret。
API到了閘道器,閘道器可以解析出使用者身份對應的appSecret,所以它可以驗證這個請求是不是正常的請求。驗證通過後就到了業務系統。
中間人攻擊是在APP發起請求離開裝置以後,在網路傳輸過程中如果被第三方竊聽,它會去嘗試篡改請求。
中間人竊取到網路傳輸中的請求報文,雖然獲得了token等關鍵資訊,但由於簽名金鑰appSecret無法通過監聽網路請求獲得,所以中間人篡改請求卻無法得到一個正確的數字簽名。
組合式呼叫
雖然萬能介面是不存在的,但我們嘗試實現減輕一個介面中同時返回來自於不同微服務的資訊的需求。基於這個需求,我們在API閘道器擴充套件出一個組合式呼叫的協議。
簡單來說,這個協議是在一次HTTP請求中對RPC服務發起多次呼叫,在API閘道器做響應報文的整合,最後做返回。
組合式呼叫——Façade設計
用Façade設計模式為多個RPC服務的介面做了Façade,在Façade上把API做組裝,統一暴露給客戶端,讓API閘道器成為API的Façade。
但我們之前嘗試做的萬能介面跟不上需求的變化,最終它帶來的惡果就是程式碼難以維護。如果在API閘道器上去不停地為介面做Façade,API閘道器的程式碼必然也是很難維護的。
為了解決這個問題,我們讓客戶端去定義Façade,API閘道器只負責組裝。
組合式呼叫——並行處理
使用非同步並行方式,將組合式呼叫序列變並行。
首先是請求前置處理,實際呼叫則採用了dubbo async呼叫,是dubbo原生的呼叫方式。最後做請求後置處理。
但是Dubbo非同步呼叫標識會通過attachment向下傳遞,汙染呼叫鏈,導致後續呼叫鏈路都變成了非同步方式。而且dubbo filter鏈機制在非同步呼叫中具有侷限性。
這兩個問題都是最後改了dubbo的原始碼來解決的。
降低接入門檻
提供線上API文件和接入SDK。
但是變化總是存在,我們該如何解放生產力呢?
擴大API的影響力,基於API資訊生成敏捷開發工具;強型別約束的SDK,及時暴露違背“契約”的行為。
這是我們做的一些敏捷開發的工具。
這是線上文件工具和除錯工具。
定位請求
Dubbo attachment是一種隱式傳參機制,具有傳遞性。
基於這個機制可以把請求標識在呼叫鏈路上一直做傳遞,呼叫鏈路上增加AOP、向日志上下文中傳遞traceid。
請求定位——elk+zabbix
在API閘道器落下的所有請求日誌都會有相應的錯誤編碼,可以做zabbix基於這個服務的遠端報錯。
我理解的API閘道器
從技術設計的角度上來說,API是一種抽象,它隔離了我們的使用以及實現;從開發管理的角度上來說,API是一種契約。
API閘道器是一種微服務的架構解決方案,服務於API“契約”精神,並儘可能的擴大這種契約的影響力,構建一種圍繞API開發的“生態”。
展望
API閘道器前面是HTTP的傳輸,在這過程中不一定需要中心化的儲存,可以嘗試用CDN來做邊界快取。
熱釋出服務於所有微服務,微服務介面的變更怎樣做到熱重啟,是一個比較有挑戰性的事情。
我們之前做的事情只是日誌定位,談不上呼叫鏈路跟蹤,呼叫鏈路跟蹤有更專業的解決方案。
API閘道器目前做的只是許可權驗證,還沒有和風控系統結合起來。
限流降級也還沒有做。
在閘道器上做ab測試會是比較有意義的。
我今天的分享就到這裡,感謝聆聽!
推薦文章
近期活動