為什么要做代理平台
微服務架構越來越流行,在一個上百號人開發的項目中,使用微服務的方式,大量模塊之間通過接口調用,隨之也帶來了許多問題:
- 接口不能及時提供造成阻塞:往往客戶端需要等待后台接口進入測試階段,才能開始進行開發。一些剛入門的客戶端開發(如web前端開發),並沒有自行偽造接口數據的能力。
- 通信數據格式混亂:json、xml、protobuf等各種方式都有,方式相同而數據結構又不統一,主調和被調方都需要自行封裝和解析不同格式的數據
- 日志未收斂匯集 : 日志分散在各個模塊,未跟請求鏈路綁定,異常發生時的故障現場不好還原
- 各模塊重復造輪子:各接口需要自己實現鑒權、限頻、驗證調用者等通用能力
為解決上述問題,我們約定一套調用規范,並將所有調用收歸一處進行代理中轉。因此,需要實現一套高可用的代理平台。
代理平台特性
先說一下幾個角色
- 第三方(服務) -- 接口提供方,被調方
- 調用方(應用) -- 主調方 ,它可以是一個客戶端如瀏覽器、手機APP,也可以是另一個接口提供方(第三方、服務)。
- 代理平台 -- 請求轉發平台。
- 代理管理平台 -- 可視化配置及查詢調用方、第三方、請求日志等數據,
- 鑒權平台 -- 基於 cookie、token等方式的含登錄、權限控制的用戶中心
代理平台主要有以下特性
松耦合、消除客戶端開發等待。
代理平台除可以正常轉發請求外,還可以偽裝響應,即代理平台直接按預定規則隨機生成響應給調用方,並不請求第三方。
統一輸入輸出格式
嚴格控制輸入格式、標准化輸出結構。第三方可以不按結構響應,但是需要在代理管理平台定義轉換規則。如果很多事情按照約定來,可以少很多工作。這也是許多框架所倡導的約定優於配置。
規范CGI文檔
通過統一的頁面,統一錄入接口說明、參數說明、響應頭及字段說明等等。客戶端開發甚至不需要跟后台開發溝通,即可完成開發任務。同時也提高接口的復用性。可以提供相應的注解和注釋包,開發者在代碼中引入注解或者注釋,可以自動完成接口數據在平台上的錄入、更新等操作。
輸入初步驗證
在代理平台定義好入參規則,代理平台在收到請求時,統一對輸入參數進行格式驗證、必填驗證等等。對惡意輸入請求進行攔截並記錄。
頻率控制
代理平台對每個接口提供基於分鍾頻次或者超頻驗證碼的調用頻率控制能力
接口性能統計
統計從平台向第三方發起請求,到平台完全收到第三方的響應的時間,做為第三方接口的性能。
請求日志
目標請求接口,來源ip、請求報文、響應報文、成功狀態、耗時、所屬的調用樹等等整個請求完整的上下文數據,都記錄在案。並且,請求到達接口提供方之后,如果第三方處理出現異常,可以將異常日志反向上報到代理平台,由代理平台來關聯這次請求的日志。
還原調用樹(調用鏈路)
一個調用方請求到達第三方后,有可能級聯發起更多的請求。如果這些請求全部經過代理平台。那么代理平台可以記錄鏈路數據,后續在代理管理平台上可視化的還原、呈現整個調用鏈路,清楚標識每個被調節點的耗時、是否成功等數據,有助於排查故障、性能瓶頸等問題
統一鑒權
登錄態檢查和接口權限控制可以全部收歸代理平台。如果請求轉發到了第三方接口,說明用戶已登錄並對此接口有權限,第三方開發者只需要從頭部取封裝好的userkey,到統一鑒權中心換取用戶信息即可.
協議頭規范化及過濾
為防止后台響應一些不規范的頭,或者一些危險的頭進行過濾。並且平台可以統一處理OPTIONS請求,將預定的協商頭響應給客戶端,可以靈活配置跨域需求。
來源IP過濾
對接口可以提供IP白名單或者黑名單的功能,合法來源ip的請求才能被轉發到后台
多協議支持
需要能夠支持多種接口協議,如HTTP、FTP、SMTP等等應用層協議,也需要能直接支持TCP長連接、UDP數據報等協議。並能做到部分協議轉換,調用方無感知的使用跟第三方接口不同的協議通信。
關聯測試用例
每個接口可以集成測試用例,類似於Advance REST Client或PostMan,定時以用例對接口進行輸入輸出調用測試。這可能需要接口提供方提供專門的測試接口。
服務存活檢查,多server時提供負載均衡
第三方可以提供部署服務的多個server ip,由代理管理平台來進行存活檢查,但server不可用時從緩存中踢掉此server,代理平台對多個server ip實現負載均衡。server故障時向真實接口方發出告警。
對第三方接口壓測
代理平台本身需要具備較強的並發能力。但更重要的是接口本身支持高吞吐量訪問。代理平台可以對第三方接口進行壓測,以推進第三方優化接口性能及並發能力。
實現方式
nginx+lua+confd + etcd
confd + etcd 用來實現實時動態更新nginx配置,當有接口新增或修改時,動態生成server或者location配置。nginx來實現請求轉發。lua腳本來實現一些諸如日志上報、鑒權檢查、協議頭檢查等等邏輯。
這種方式在接口量較小時是個不錯的選擇。但是當接口數量達到成千上萬的級別后,動態生成的nginx配置會非常大,不利於問題排查,且容易生成沖突、錯誤的nginx配置,致使nginx進程異常。並且上面提到的一些復雜的目標,如還原調用鏈路、輸入參數驗證、關聯測試用例等,此方式也很難實現。
camel
apache camel是一個協議轉換的框架,可以很方便實現協議轉換、請求路由轉發。下面是代理平台及代理管理平台的架構及請求處理過程示意。
其中
clinet 即為調用方,使用平台提供的各種語言(js、c、java、php、python等)的sdk,可以對調用方無感知的包裝一些驗證、標識頭部。這也是還原調用鏈路的基礎。如果不使用sdk,同樣可以向代理平台發起請求。SDK主要做提供兩個功能:1、透傳標識頭、來源路徑頭信息等等。2、向代理管理平台上報此次請求處理出現的異常日志。
cgi_proxy 即是基於camel開發的代理平台。主要實現驗證請求合法性(appkey)、登錄態驗證與權限控制、協議轉換、參數驗證、請求轉發、頭部特殊字段處理、格式化響應、請求日志記錄等等。日志由異步線程寫入到消息隊列。轉發請求需要的數據從redis中獲取,redis中存儲了接口提供方真實接口地址、參數規則、合法appkey等信息。因為在client看來,請求的處理時間是平台處理時間+真實接口處理時間,只有平台處理足夠快,才能減少性能損失,所以cgi_proxy 不從任何接口查詢數據,也不直接操作db,只從redis查詢數據,這樣可以很好的減少性能損失。
log_coll收集消息隊列中的請求日志落地存儲,並按時對全平台接口調用情況進行統計,生成運營數據。當每日的調用量達到百萬、千萬級別時,比db分表更好的手段是由此進程定時遷移舊的數據。
manager 即代理管理平台。定義一套接口模型,將各種后台接口按模型規范並存儲至db。將核心的數據緩存到redis。在頁面實現可視的接口編輯、日志查詢等能力