一、存在的問題
- 客戶端會請求多個不同的服務,需要維護不同的請求地址,增加開發難度 (各個消費者ip不同)
-
在某些場景下存在跨域請求的問題
-
加大身份認證的難度,每個微服務需要獨立認證(關於微服務認證,可以看我之前的文章,深入的講解了分佈式的授權與認證)
二、網關的概念
-
Kong:基於Nginx+Lua開發,性能高,穩定,有多個可用的插件(限流、鑑權等等)可以開箱即用。問題:只支持Http協議;二次開發,自由擴展困難;提供管理API,缺乏更易用的管控、配置方式。
-
Zuul:Netflflix開源,功能豐富,使用JAVA開發,易於二次開發;需要運行在web容器中,如Tomcat。 問題:缺乏管控,無法動態配置;依賴組件較多;處理Http請求依賴的是Web容器,性能不如Nginx;
-
-
-
三、zuul實現網關
1、Zuul簡介
- 動態路由:動態將請求路由到不同後端集羣
- 壓力測試:逐漸增加指向集羣的流量,以瞭解性能
- 負載分配:爲每一種負載類型分配對應容量,並棄用超出限定值的請求
- 靜態響應處理:邊緣位置進行響應,避免轉發到內部集羣
- 身份認證和安全: 識別每一個資源的驗證要求,並拒絕那些不符的請求。Spring Cloud對Zuul進行了整合和增強。
2、搭建一個Zuul網關服務器
(1)一個基礎工程
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringCloudDemo</artifactId>
<groupId>com.springcloud.demo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>zuul_server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
</project>
server:
port: 8080 #端口
spring:
application:
name: api-zuul-server
package com.springcloud.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class,args);
}
}
其他服務目錄:
person-sevice是9002端口,order-service是9001端口,這兩個是對外提供的接口。product-service是9010端口,是微服務。
(2)路由配置
# 路由選擇配置
zuul:
routes:
service-order:
path: /order-service/**
url: http://127.0.0.1:9001
service-person:
path: /person-service/**
url: http://127.0.0.1:9002
- product-service:配置路由id,可以隨意取名
- url:映射路徑對應的實際url地址
- path:配置映射路徑,這裏將所有請求前綴爲/product-service/的請求,轉發到http://127.0.0.1:9002處理
都是可以的,他們都調用了一個微服務。
(3)面向服務的路由配置(從註冊中心拿到服務)
添加註冊中心依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/
instance:
prefer-ip-address: true #使用ip地址註冊
# 路由選擇配置
zuul:
routes:
service-order:
path: /order-service/**
# url: http://127.0.0.1:9001
serviceId: service-order
service-person:
path: /person-service/**
# url: http://127.0.0.1:9002
serviceId: service-person
zuul:
routes:
service-order: /service-order/**
3、過濾器
zuul有兩個核心功能:請求和過濾
-
PRE:這種過濾器在請求被路由之前調用。我們可利用這種過濾器實現身份驗證、在集羣中選擇請求的微服務、記錄調試信息等。
-
ROUTING:這種過濾器將請求路由到微服務。這種過濾器用於構建發送給微服務的請求,並使用Apache HttpClient或Netfifilx Ribbon請求微服務。
-
POST:這種過濾器在路由到微服務以後執行。這種過濾器可用來爲響應添加標準的HTTPHeader、收集統計信息和指標、將響應從微服務發送給客戶端等。
-
public abstract ZuulFilter implements IZuulFilter{
abstract public String filterType();
abstract public int filterOrder();
boolean shouldFilter();// 來自IZuulFilter
Object run() throws ZuulException;// IZuulFilter
}
-
shouldFilter :返回一個 Boolean 值,判斷該過濾器是否需要執行。返回true執行,返回false不執行。
-
-
-
-
- post :在routing和errror過濾器之後調用
- error :處理請求時發生錯誤調用
-
- filterOrder :通過返回的int值來定義過濾器的執行順序,數字越小優先級越高。
生命週期:
4、自定義過濾器
package com.springcloud.demo.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* @ClassName LoginFilter
* @Description
* @Author 戴書博
* @Date 2020/5/28 16:24
* @Version 1.0
**/
@Component
public class LoginFilter extends ZuulFilter {
/**
* 類型:
* pre
* routing
* post
* error
*/
@Override
public String filterType() {
return "pre";
}
/**
* 指定過濾器的執行順序
* 返回值越小,執行順序越靠前
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 當前過濾器是否生效
* true:使用此過濾器
* false:不使用此過濾器
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 執行過濾器的方法
*/
@Override
public Object run() throws ZuulException {
System.out.println("================進入過濾器=================");
//獲取上下文對象
RequestContext ctx = RequestContext.getCurrentContext();
//獲取request對象
HttpServletRequest req = ctx.getRequest();
//從請求中獲取token
String token = req.getParameter("access-token");
//判斷
if(token == null || token.equals("")){
// 沒有token,登錄校驗失敗,攔截
ctx.setSendZuulResponse(false);
// 返回401狀態碼。也可以考慮重定向到登錄頁。
ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
// 校驗通過,可以考慮把用戶信息放入上下文,繼續向後執行
return null;
}
}
在我們之前寫的授權與認證中,使用了一個微服務認證。這裏簡單寫一下。
zuul出現的問題:
- 性能問題 :Zuul1x版本本質上就是一個同步Servlet,採用多線程阻塞模型進行請求轉發。簡單講,每一個請求,Servlet容器要爲該請求分配一個線程專門負責處理這個請求,直到響應返回客戶端這個線程纔會被釋放返回容器線程池。如果後臺服務調用比較耗時,那麼這個線程就會被阻塞,阻塞期間線程資源被佔用,不能幹其它事情。我們知道Servlet容器線程池的大小是有限制的,當前端請求量大,而後臺慢服務比較多時,很容易耗盡容器線程池內的線程,造成容器無法接受新的請求。
- 不支持任何長連接,如websocket
源碼:[email protected]:Zesystem/springclouddedemowangguan.git