一、微服務(wù)網(wǎng)關(guān)層的整體架構(gòu)思考
先回顧下網(wǎng)關(guān)層的功能:
1.請求鑒權(quán)
發(fā)布商品,登錄鑒權(quán)。
2. 數(shù)據(jù)完整性檢查
數(shù)據(jù)定長Header,變長body
3. 協(xié)議轉(zhuǎn)換
JSON-> HashMap(string,obj)
如果value不支持json嵌套的話,就string就可以。hashmap(string,string)
4. 路由轉(zhuǎn)發(fā)
根據(jù)CMD轉(zhuǎn)發(fā)到不同業(yè)務(wù)邏輯層
5. 服務(wù)治理
限流,降級,熔斷等。
其中最核心的是1和4.
1涉及到session存到哪,
4涉及到如何把眾多的HTTP請求路由到邏輯層的RPC接口。新上一個業(yè)務(wù)(邏輯層),網(wǎng)關(guān)不需要的重啟的情況下如何發(fā)現(xiàn)它。
二、自研網(wǎng)關(guān)的各個關(guān)鍵點
2.1 自研網(wǎng)關(guān)需求剖析
打造一個高性能的分布式網(wǎng)關(guān)(SaaS),實現(xiàn)HTTP請求轉(zhuǎn)發(fā)到RPC服務(wù)、接口請求鑒權(quán)、反作弊(風(fēng)控、antispam)等相關(guān)功能。
要實現(xiàn)如下功能:
- 高性能分布式模塊(這里模塊指的Process)
- 鑒權(quán)功能
- 路由能力
- 簡單實用的反作弊
落實到技術(shù)層面,解決方案如下:
- 無狀態(tài)設(shè)計
- 過濾器責(zé)任鏈設(shè)計(攔截器)
- 反作弊設(shè)計(攔截器)
可以理解為責(zé)任鏈的一部分 - 路由方案設(shè)計
架構(gòu)參考
整體架構(gòu)基于Spring boot框架。

網(wǎng)關(guān)本質(zhì)上是一個websever。
注意上面的Filter責(zé)任鏈模式。 跨域問題
比如,訪問www.baidu.com,調(diào)用的js中有www.iqiyi.com。那么到了iqiyi的網(wǎng)關(guān)層,它發(fā)現(xiàn)主域名是來自于其他網(wǎng)站,就會考慮讓不讓它訪問iqiyi,這就是一個跨域問題。網(wǎng)關(guān)屬于高并發(fā)模塊
所以要邏輯簡單,業(yè)務(wù)邏輯剝離到logic層緩存設(shè)計、異步線程設(shè)計
反作弊模塊,希望有一個黑名單緩存,比如map或set。(因為和外部交互影響性能)。黑名單應(yīng)該是由數(shù)據(jù)分析得到的,比如放到redis里。那么我如何在進(jìn)程內(nèi)緩存呢?
這時就要一個異步加載機(jī)制,比如每隔5s從redis里讀出來覆蓋set。(最終一致性),即進(jìn)程內(nèi)和進(jìn)程外通訊。進(jìn)程外緩存,配置平臺
進(jìn)程外緩存就指的redis集群
配置平臺是路由邏輯用的,后面詳解。

上面的圖不對,需要換一下
2.2 跨域問題
從一個源(www.baidu.com)加載的文檔或腳本(js),不能訪問另一個源(www.iqiyi.com)的資源。

Access-Control-Allow-Origin
栗子:
比如baidu的網(wǎng)頁想嵌入iqiyi的一個url資源,那么它會先去iqiyi的網(wǎng)關(guān)層探測我能不能訪問你的資源,如果iqiyi允許的話,會在網(wǎng)關(guān)層建立一個豁免清單(允許哪些第三方的域名訪問)。跨cookie Access-control-allow-credentials
cokie是種在url里的,比如種在api1.baidu.com里的,那么api2.baidu.com就不行了。如果設(shè)置為允許跨cokie,那么cokie在任何一個二級域名里都可以(*.baidu.com).允許哪些方法進(jìn)行跨域訪問
2.3 Session設(shè)計

2.3.1 session綁定
本質(zhì)就是將uid hash到固定的節(jié)點。
問題是高可用怎么保證呢? session一般是沒必要持久化的。
思路是網(wǎng)關(guān)冗余,模仿數(shù)據(jù)庫主從復(fù)制。

但是,網(wǎng)關(guān)間的數(shù)據(jù)復(fù)制如何設(shè)計呢?(要考慮vip、主從復(fù)制等,簡單問題復(fù)制化了)。所以session綁定在工業(yè)界很少用。
所以一般用session綁定
2.3.2 session 復(fù)制

而且是最終一致性的,存在session重寫。這種方案也是不合理的。
2.3.3 session共享

這里的redis是redis cluster。
使用緩存服務(wù)Redis,統(tǒng)一存儲Session。
優(yōu)點
- 網(wǎng)關(guān)層無狀態(tài)
- 緩存服務(wù)本身高可用
缺點
- 多一次服務(wù)調(diào)用IO
思考如果減少IO調(diào)用,且網(wǎng)關(guān)是無狀態(tài)化的。很自然的想到session存在客戶端。
2.3.4 Session 客戶端緩存

可以存在app的sqlite里
優(yōu)點:
- 簡單高性能
- 網(wǎng)關(guān)層無狀態(tài)
缺點: - 依賴客戶端Cookie(session)存儲
每次帶cookie,消耗一些app端的流量。
這個用的比較多,因為響應(yīng)延遲低,且高可用。
2.3.5 session 生成算法

session=AES(uid + TTL + checksum)
用戶第一次登錄時,網(wǎng)關(guān)生成session,然后返回給客戶端,之后每次登錄時帶著這個session。
本地算法,AES解密看TTL是否過期,checksum是否正確。
遠(yuǎn)程校驗,是因為session在很多公司是在業(yè)務(wù)邏輯層生成的(因為更多的是業(yè)務(wù)邏輯的判斷),而不在網(wǎng)關(guān)層生成。TTL過期后要到業(yè)務(wù)邏輯層去校驗,業(yè)務(wù)邏輯層返回給GW一個新的session,GW返回給APP。這個可能很少概率。
2.3.6 session 攔截器

攔截器中會生成logid,logid是app請求的唯一標(biāo)識。
以上主要兩部分功能,1 是session校驗,2是生成logid。
2.4 網(wǎng)關(guān)層反作弊需求
- 針對惡意流量,從網(wǎng)關(guān)層面進(jìn)行攔截,防止對后端服務(wù)造成高并發(fā)壓力
-
為了防止誤傷,對于黑名單數(shù)據(jù)定期釋放能力
image.png
分析:
初期階段
數(shù)據(jù)量小的時候,可以內(nèi)存中l(wèi)ocal cache。高可用設(shè)計
進(jìn)程內(nèi)緩存解決不了高可用黑名單
持久化怎么做

上面是數(shù)據(jù)量比較小的時候,那么數(shù)據(jù)量大的時候怎么做,幾十G的話進(jìn)程內(nèi)緩存不了。
風(fēng)控挖掘的時候可以存在redis里,但是為了這種小概率的事讀redis會導(dǎo)致耗時增加。
所以可以用布隆過濾器。
思考
- 數(shù)據(jù)量大怎么做(布隆過濾器)
如果每次讀redis,為了這小概率事件開銷太大
但是布隆過濾器具體怎么做?后面詳解 - 實時性怎么破?
如果5s拉一次可能不夠?qū)崟r,如果實時性要求高,可以改成redis有更新然后push的方式。
2.5 自研網(wǎng)關(guān)各個擊破:之路由

RPC客戶端比如Dubbo,用來和網(wǎng)關(guān)后面的業(yè)務(wù)邏輯層的RPC services通信。
架構(gòu)設(shè)計原則
初期階段約定大于配置:
url什么規(guī)范,接口的約定。服務(wù)端簡潔化設(shè)計
- 功能夠簡單
- 使用用夠方便
負(fù)載均衡和服務(wù)發(fā)現(xiàn)
- RPC框架實現(xiàn)
熔斷設(shè)計
Hystrix
協(xié)議約定
- 網(wǎng)關(guān)和APP間的數(shù)據(jù)協(xié)議是JSON
- 網(wǎng)關(guān)層調(diào)用業(yè)務(wù)邏輯層入?yún)⒔y(tǒng)一為Map<string,string>
- 業(yè)務(wù)邏輯層返回統(tǒng)一的Result對象{code,data,msg}
code:0, data:xxx, msg: success
網(wǎng)關(guān)層拿到后再轉(zhuǎn)化成json,然后返回給APP。
2.5.1 路由設(shè)計

上圖其中Sevrice比如分別對應(yīng)用戶、商品、交易的logic。
其中RPC框架比如是Dubbo的RPC客戶端,調(diào)用Dubbo的RPC服務(wù)端(即后端的logic)。
uri->Service(比如User logic),Method對應(yīng)User logic中的get user方法。
這塊主要做兩件事:
- 建立url和服務(wù)間的映射關(guān)系(服務(wù)啟動初始化,內(nèi)存里建立映射)
- RPC通過反射實現(xiàn)遠(yuǎn)程調(diào)用。(反射生成對應(yīng)的對象供調(diào)用)
25.2 具體實現(xiàn):



上面講的其實網(wǎng)關(guān)1.0的路由實現(xiàn),有如下幾個問題:
啟動耗時大
比如有幾百個業(yè)務(wù)邏輯,都去網(wǎng)關(guān)建立路由映射關(guān)系,那么服務(wù)啟動初始化的時候就會非常耗時。業(yè)務(wù)升級需要重啟,耦合嚴(yán)重,降低開發(fā)效率。
比如新加個服務(wù),需要重新到網(wǎng)關(guān)層注冊(建立路由映射),那么網(wǎng)關(guān)就需要重啟進(jìn)程。
那么2.0就需要解決這兩個問題。
2.6 網(wǎng)關(guān)2.0


- 路由到通用接口。接口再去路由到具體的服務(wù)。
這樣就不需要引入service,不需要重啟?;诮涌诰幊?。
proxy每增加一個服務(wù)的時候,需要上報CLASS和Method給存儲層(Mysql),網(wǎng)關(guān)層每隔5s掃描存儲層加載到內(nèi)存里。這樣網(wǎng)關(guān)層根據(jù)CMD對應(yīng)的Class和Method拿到Service IP,然后調(diào)用固定的接口。


思考 網(wǎng)關(guān)3.0的演進(jìn)
- 進(jìn)一步解耦如何做?
一定需要mysql作為存儲層嗎? 可否用注冊中心或配置中心來做? - 泛化調(diào)用的邏輯?
三、開源框架推薦


