前言
開放平臺設計系列第一篇主要寫了開放平臺功能方面的設計,原計劃寫3篇,一篇介紹功能,一篇介紹架構,一篇介紹使用的技術。寫了第一篇功能后,發現架構和技術可以合并寫,這樣看起來更方便些,所以本篇就把架構和技術合并了。合并起來還有一方面是因為涉及到公司實施細節不能把架構的細節寫出來,只能簡化的描述下架構,這樣架構的概述就太少了沒辦法撐起一篇文章,在后面技術實現會講解下各個功能模塊的實現方式。
1. 總架構概述
下面直接上架構圖來描述下通用版開放平臺的架構,這里已經刪掉了所有涉及到公司隱私的信息。架構上總體上分為以下幾部分:
互聯網接入web server(web server):負責互聯網外部請求的接入,webserver一般使用nginx負責負載和反代,一般都是將webserver部署在兩層防火墻包圍的DMZ區用來內外網的安全隔離;
開放平臺接入網關(openapi gateway):負責接收互聯網接入轉發的交易請求,網關是線型集群部署在內網,負責請求的限流、熔斷、計費等功能;
開放平臺門戶(openapi portal):門戶主要負責提供給開發者使用的門戶頁面和服務申請、應用管理等功能。門戶也是采用了集群部署的應用服務;
開放平臺內管(openapi management):內管主要提供給管理員進行內部服務、應用審核、基本維護使用,也是集群部署的應用服務;
服務注冊發現中心(service center):服務注冊中心是整個服務化的核心,這里服務發現中心主要實現了服務路由和內部服務注冊、發現的功能,這里也是采用了集群部署;
安全服務:安全服務因為是基礎服務,所以將所有服務都注冊到了service center供所有系統使用;
oauth服務:oauth因為也屬于開放平臺基礎服務,所以這里將oauth所有服務都注冊到了service center;
開放平臺服務組合(BIM):服務組合對原子基礎服務進行組合后再發布到service center,也是一個比較核心的模塊,有的公司將服務組合從開放平臺中剝離出來單獨作為一個服務組合系統。BIM也是采取了線性集群部署的方式。
開放平臺內部服務管理(openapi server):內部服務管理主要實現了所有開放平臺服務元數據的管理、服務接口的配置、應用元數據管理等。
2. 服務接入網關
服務網關的實現比較簡單,主要有幾個關鍵點,下面介紹下:
- 外部服務接入:服務接入功能其實比較簡單,一般都是使用Spring MVC或者SpringBoot直接定義Controller來實現服務接入,但是這樣會導致,如果有多少服務對外開放就要定義多少個Controller,如果使用springcloud的話可以使用類似zuul這樣的透傳網關來實現,當然也可以自己實現一個通用的接入controller,然后根據請求uri來實現其他的接入路由、限流等功能。
- 服務限流、熔斷:作為一個開放平臺的接入網關,還需要有限流和熔斷的功能,目前比較成熟的方案就是Hystrix,通過Hystrix可以很方便的實現服務限流和熔斷,具體實現可以參考我之前寫的關于Hystrix的文章。當然如果不使用Hystrix的話,也可以自己實現,限流主要分兩個緯度一個是并發限流,一個是指定時間內總調用次數限流,實現并發限流可以通過線程池方案,對于每個商戶每個服務創建一個線程池,通過線程池機制來實現并發控制,看過Hystrix源碼的同學應該知道Hystrix實現并發限流也是通過線程池方案進行隔離。對于并發限流還可以通過Token池方案進行控制,其實原理和線程池類似,但是token池方案更加輕量級,為每個商戶每個服務創建一個token池,如果有服務請求則從token池中拿一個token占用,服務調用完成后歸還token,如果所有token被占用則不能再調用服務。實現了限流實現熔斷其實就比較簡單了,當判斷出來觸發服務熔斷后會自動進行降級處理,如果接口定義了降級策略則固定返回降級報文即可。
- 服務計費:服務計費其實是基于服務次數限流實現的,通過對服務次數的統計實現即可,服務次數統計為了保證性能一般都是通過內存計數或者redis計數,用內存計數存在一個問題就是如何保證HA,所以推薦使用redis集群來進行服務計數;
- 服務分布式擴展:服務接入網關的壓力是非常大的,所以要支持分布式線性擴展,要實現線性擴展就要求所有的交易都是無狀態的短連接,使用訪問令牌的方式來保證登陸有效性檢查;
3. 服務組合
服務組合是開放平臺中比較常見的功能模塊,服務組合一般有兩類,服務接口順序、并行組合,自定義邏輯接口組合。
- 順序接口組合:這里說的順序接口組合其實指的是狹義的順序接口組合就是先調用接口1然后將接口1的返回報文中的部分字段作為接口2的請求字段,再繼續調用接口2以此類推,順序接口組合在實際使用中其實遇到的不多,大部分的接口組合要么是并發調用結果聚合返回,要么是存在很多自定義邏輯,需要對每個接口的返回報文加工后再調用下一個接口的場景。順序接口組合實現起來其實也比較簡單,其實就是在接口配置表中配置好接口依賴關系和輸入輸出字段對應,在收到組合接口請求后由一個線程根據接口配置表的元數據串型依次調用接口;
- 并行接口組合:并行接口組合其實使用場景比較多,尤其是在移動端場景,經常在移動端的頁面存在多個重復的接口調用,這時服務組合其實可以進行并行組合后將結果聚合返回,這樣就可以避免前端多次發起網絡連接請求數據,前端只需要發送一次請求,由服務組合模塊根據請求并發發起服務調用,服務端調用都是內網調用速度比無線調用要快好幾個數量級,服務端并發調用有結果返回后再將結果進行聚合返回給前端。這里并行接口調用可以使用java.concurrent庫中的fork/join來實現,但是要注意處理并發組合接口某個接口調用異常的處理;
- 自定義邏輯接口組合:自定義邏輯接口組合目前主流的有兩種方式,一種是純編碼實現所有的組合邏輯,還有一種是定義一個服務組合接口,開發者只需要實現接口并實現代碼片段就可以了,這其實和目前流行的serverless一樣。
4. oauth
oauth是開放平臺一個不可或缺模塊,oauth具體有什么功能這里我就不介紹了,可以參考之前轉發的一篇關于oauth的文章,這里主要說下oauth的實現方式,如果是實現標準的oauth的3種模式,可以基于spring security和Apache的Shrio這兩套框架來實現,但是目前我了解下來還是有很多公司實現的oauth協議其實加了很多自己的定制化需求,如果有很多定制化需求的建議還是自己實現一套,實現難度其實不大,主要就是實現token發放、token校驗、token有效期處理、token更換等基礎功能,純自研的話功能肯定沒有用框架那么豐富,但是所有代碼可控自主性更高。
5. 服務注冊管理
服務注冊管理的實現其實沒什么好說的,用的技術其實就是傳統的java web,服務注冊管理其實就是對開放平臺所有的應用、服務、接口配置等元數據進行統一管理的模塊,只要需求功能清晰,按需求實現就可以了。
6. 服務注冊發現中心
服務注冊發現中心不是簡單的服務路由分發、服務注冊、服務發現,其實還涉及到服務的可用性管理、服務監控等等內容,這里推薦使用現成的,不要重復造輪子,可以使用zookeeper或者eureka,筆者之前所在的項目分別使用過dubbo+zk的組合和springboot+eureka的組合,兩種各有優缺點,這里更加推薦使用后者,目前springcloud有一統微服務江湖的趨勢,而且更新越來越快,雖然阿里又對dubbo重新進行維護,但是擔心阿里開源的尿性,小東西用用沒問題,像服務治理框架這樣的還是算了,萬一出問題想死的心都有了。
7. 安全
上一篇文章里說過開放平臺的核心其實不是開放接口而是如何保證安全,開放平臺的安全其實涉及到以下幾方面需要考慮的地方:
- 服務報文加解密:服務報文加解密主要思路就是秘鑰通過非對稱加密來保證安全,業務報文或者關鍵字段使用對稱加密來保證安全,還可以通過白盒加密等技術來加強安全,因為安全這塊內容涉及到很多方案和實現方式,后續單獨寫一篇關于加解密的文章,詳細說說里面的東東;
- 交易簽名:通過交易簽名來防交易被篡改,交易簽名一般使用非對稱加密+散列算法來實現;
- 應用秘鑰管理:對于使用到的對稱秘鑰或者非對稱公私鑰都要進行管理,如果已經有了CA系統,可以直接復用CA中心的秘鑰管理,也可以自建密鑰管理,自建一般安全性方面會存在很多安全問題,但是可以實現基本功能;
- 應用接口權限控制:對于每個開發者調用接口的權限控制,其實就是一個1對N的關系映射,實現方面沒有什么可說的;
- oauth令牌機制:上文已經說了;
- 黑白名單:黑白名單也是安全防護的基礎功能,其實核心就是在交易調用的時候進行黑白名單的判斷,這里要保證的就是性能問題,可以通過將黑白名單保存在內存或者redis中來緩存保證讀取性能;
- 字段脫敏還原:對于一些敏感字段需要進行脫敏后返回給前端,脫敏簡單,難的是還原,對于內部系統存儲的數據一定是還原后的數據,所以只有在請求進來的時候要對報文解密后對脫敏字段進行還原后再進行持久化或者發給源系統;
- 交易反欺詐:以前做的開放平臺一般都沒有反欺詐模塊,最近兩年大數據火了以后,基于大數據的交易反欺詐也火了起來,很多開放平臺也做起了交易反欺詐,交易反欺詐目前大部分都是事后黑名單機制,每筆交易關鍵要素都會送反欺詐系統,反欺詐系統會通過storm這類實時計算出可疑交易名單,并將名單和黑名單聯動,后續再有黑名單中交易發起時就會觸發反欺詐動態安全策略。
8. 沙箱
沙箱主要實現的功能就是服務模擬,沙箱實現要注意以下幾點:
- 報文模擬:報文模擬可以使用類似MockServer這樣的報文模擬工具,其實有很多類似的報文模擬工具,甚至可以自己實現一個簡單的報文模擬工具;
- 測試數據初始化:對于一些智能沙箱,需要對測試數據進行初始化,初始化后可以進行重新的測試,這樣可以保證臟數據的及時清理;
- 測試帳號管理:對于使用沙箱的開發者也需要有一個測試帳號的管理功能,可以方便開發者自己創建一些測試帳號;
- docker:如果使用了docker的公司可以考慮使用docker來實現測試環境數據的清理,目前我也在測試使用容器化技術來快速創建測試環境。
9. 門戶、內管
門戶和內管其實沒什么好說的其實都是一些portal,只是針對的用戶不一樣,實現的技術也就是傳統的java web技術,如果前端要顯示的酷炫一些就使用一些H5的技術。因為在門戶和內管中還會涉及到一些監控的功能,監控模塊這里就不單獨弄一節描述了,其實監控可以借助于一些三方組件來實現,目前主流的實現方案主要是將各個系統的服務接口調用都推送到一個監控平臺,由監控平臺根據推送過來的數據進行實時數據展示。
總結
本文對于開放平臺一些核心內容如何實現做了簡要介紹,每部分其實都可以單寫一篇文章,開放平臺中其實涉及到的技術還是很多的,希望大家慢慢體會。