微服務架構閘道器介面設計

weixin_34075551發表於2018-01-01

近年來微服務架構盛行,我司也利用spring cloud實踐微服務。使用的也是spring cloud很經典的架構,zuul充當閘道器路由,configserver作為靜態配置中心,feign作為遠端呼叫http client 等,反正都是官網文件能找到的元件,我們都在用。使用基礎的功能自然是沒有問題,但是我們也會針對進行深度定製,完成我們特有的功能,例如我們定製zuul閘道器,路由時針對部分request中的資料,這個在通用模式下是做不到,因為zuul基礎的功能是路由,通過連結將請求分發給哪個微服務的哪個方法進行處理,下面我們就以一個介面限流的案例,來一步步的教大家閘道器介面的設計方案與深度定製zuul閘道器的過程。

背景

  1. 微服務需要暴露介面給第三方使用,但是此介面是二次封裝的產物,封裝了一個按次付費的介面,所有不能隨便呼叫,需要限制呼叫方呼叫的次數。
  2. 基礎的應用框架正如前言所說使用spring cloud 全家桶。

基礎設計

  1. 為了更好的相容性和擴充套件性,我們決定在後臺配置需要被閘道器特殊處理的介面。例如此介面名稱叫做介面A,他的訪問連結是什麼。都需要被記錄。
  2. 閘道器介面需要被怎樣的處理?驗籤(1)?解密(2)?限流(3)?都可以。我們將這些被閘道器允許的特殊操作,做成一個個原子,然後隨意組合成某一類介面的具體的功能。比如說我們的某一類的介面的功能是限流+驗籤,那麼我們原子組合就是(1,3),我們稱這種方案為方案A,具體要怎麼處理這個組合可以根據大家自己的設計,我這邊建議是與或操作,利用計算機擅長的二進位制來處理。
  3. 我們通過第一步有了介面A,我們通過第二部有了方案A,然後將他們融合在一起,拼成的語義就是:當閘道器發現了被訪問的連結是特殊介面A所描述的,那麼就要找到這個介面的特殊配置,也就是方案A,在閘道器進行特殊處理就行了。
  4. 閘道器改怎麼進行特殊處理呢?屬性zuul的朋友應該都知道他是怎麼執行的,不熟悉的同學可以看一下我的另外一篇文章Zuul 原始碼分析,zuul分為諸多型別的filter,他們都是ZuulFilter的例項,所以你只要寫一個ZuulFilter的,並且把它做成Bean(@Component註解註釋或者通過配置檔案配置等),就能被Zuul察覺到,但是能不能執行,還得看ZuulFilter中的shouldFilter方法結果是否返回true,這種設計也給我們很大的靈活性和擴充套件性,也給我們通過程式碼操作我們寫的這個filter是否執行成為可能,並且這種設計和我之前提到的與或操作是天然的結合在一起,無縫銜接,特別好用!我們可以通過自定義pre型別的filter,將一些前置的邏輯,比如方案A是驗籤和限流的功能做掉。
  5. 功能驗證完了,我們就剩下路由了。也就是我們的route型別的過濾器。因為我們要實現驗籤和介面限流等功能,所有避免不了就是多一些非業務的引數,但是業務系統不需要這些,所以我們就要通過閘道器層面就要過濾掉。Zuul閘道器有兩個主要的route型別的過濾器,如果通過服務名稱路由,會從consul或者eureka中獲取到這個服務名稱對應的服務的資訊,然後通過軟負載均衡robbin,路由到具體的服務發起請求,這個filter叫做RibbonRoutingFilter,如果你指定了訪問服務的URL,那麼久不會走到這個RibbonRoutingFilter,你走的就是SimpleHostRoutingFilter,它裡面就是直接通過apache http client 發起來請求。這兩個預設的route型別的過濾器都不能滿足我們傳遞部分資料到後端微服務的場景,所以我們就得自定義一個route型別的過濾器,我們要做的就是兩點,第一點,將後端微服務真真需要的資料傳給他們,第二點就是在執行時不要訪問到其他的route型別的過濾器,防止被介面被執行兩次。

結語

基本上實現跟著上面的步驟來就沒啥特別大的問題了,自己寫一個route型別的filter也不是特別難的事情,基本上把SimpleHostRoutingFilter重寫一些就行,大部分程式碼不需要改動,只要在傳遞request時,訊息體換成服務端真正需要的資料,並且注意content-length的設定就可以。另外怎麼防止不會有其他的route型別的filter訪問到,這就得看其他的route型別的filter的shouldFilter方法是怎麼樣的,想方設法把他們變成false就行了。我們再解決問題的同時也要思考框架級程式碼的設計,擴充套件性如此只好,即使沒有現成的解決方案,但是我們自己稍作改動就會支援。不得不說,這些大神們寫的程式碼,真的值得我們好好學習啊。

相關文章