SpringCloud微服務體系中,一種常見的負載均衡的方式是,客戶端的請求先通過負載均衡(Zuul+Ngnix),再達到服務網關(Zuul集羣),然後纔到具體的服務器。
服務統一註冊到服務註冊中心集羣,服務的所有配置文件由配置服務管理。
一、Zuul介紹
Zuul的主要功能是路由轉發和過濾器。路由是微服務的一部分,比如/api/user轉發到user服務,/api/shop轉發到shop服務。
Zuul默認和Ribbon實現了負載均衡。
Zuul有以下功能:
- Authentication(身份驗證)
- Insights
- Stress Testing(壓力測試)
- Canary Testing(最先測試)
- Dynamic Routing(動態路由)
- Service Migration(服務遷移)
- Load Shedding(甩負荷)
- Security(安全性)
- Static Response handling(靜態響應處理)
- Active/Active traffic management
二、創建zuul工程,服務路由
1.創建SpringBoot工程,引入eureka、zuul、web依賴。
2. 在啓動類開啓@EnableEurekaClient註解和@EnableZuulProxy註解
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
3. 修改配置
配置註冊中心地址;設置zuul服務端口、服務名;配置網關,這裏將所有/api-ribbon/開頭的請求都轉發給service-ribbon服務,將所有/api-feign/開頭的請求都轉發給service-feign服務。
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8766
spring:
application:
name: service-zuul
zuul:
routes:
api-ribbon:
path: /api-ribbon/**
serviceId: service-ribbon
api-feign:
path: /api-feign/**
serviceId: service-feign
4. 訪問zuul服務
http://localhost:8766/api-ribbon/say?name=longtian
http://localhost:8766/api-feign/hello?name=longtian
三、服務過濾
創建Zuul服務過濾器需要繼承抽象類com.netflix.zuul.ZuulFileter,該類實現了com.netflix.zuul.IZuulFilter,有兩個抽象方法:
public abstract String filterType(); public abstract int filterOrder();
以及IZuulFilter接口的兩個方法:
boolean shouldFilter(); Object run() throws ZuulException;
1. filterType()返回一個字符串代表過濾器的類型。zuul定義了四種不同生命週期的過濾器:
pre:路由之前
routing:路由時
post:路由之後
error:發送錯誤時調用
2. filterOrder(),過濾的順序
3. shouldFileter(),這裏可以寫邏輯判斷,是否要過濾。true,永遠過濾。
4. run(),過濾器的具體邏輯。可能很複雜,包括查sql、緩存等去判斷到底有沒有訪問權限。
@Component
public class MyFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(MyFilter.class);
public String filterType(){
return "pre";
}
public int filterOrder(){
return 0;
}
public boolean shouldFilter(){
return true;
}
public Object run(){
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String token = request.getParameter("token");
if(StringUtils.isEmpty(token)) {
log.error("accepted token is null");
context.setSendZuulResponse(false);
context.setResponseStatusCode(401);
try {
context.getResponse().getWriter().write("token error");
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
log.info("ok");
return null;
}
}
訪問 http://localhost:8766/api-ribbon/say?name=longtian
訪問 http://localhost:8766/api-ribbon/say?name=longtian&token=1