亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

京東資深工程師分享:微服務(wù)架構(gòu)之網(wǎng)關(guān)層Zuul剖析

 

一、Zuul簡介

Zuul相當(dāng)于是第三方調(diào)用和服務(wù)提供方之間的防護門,其中最大的亮點就是可動態(tài)發(fā)布過濾器

二、Zuul可以為我們提供什么

1、權(quán)限控制

2、預(yù)警和監(jiān)控

3、紅綠部署、(粘性)金絲雀部署,流量調(diào)度支持

4、流量復(fù)制轉(zhuǎn)發(fā),方便分支測試、埋點測試、壓力測試

5、跨區(qū)域高可用,異常感知

6、防爬防攻擊

7、負(fù)載均衡、健康檢查和屏蔽壞節(jié)點

8、靜態(tài)資源處理

9、重試容錯服務(wù)

三、Zuul網(wǎng)關(guān)架構(gòu)

京東資深工程師分享:微服務(wù)架構(gòu)之網(wǎng)關(guān)層Zuul剖析

 

可以看到其架構(gòu)主要分為發(fā)布模塊、控制管理加載模塊、運行時模塊、線程安全的請求上下文模塊。在Spring Cloud中,Zuul每個后端都稱為一個Route,為了避免資源搶占,整合了Hystrix進(jìn)行隔離和限流,基于線程的隔離機制,另外一種機制是信號量,后面文章會提到。Zuul默認(rèn)使用ThreadLocal

protected static final ThreadLocal<? extends RequestContext> threadLocal = new ThreadLocal<RequestContext>() {
 @Override
 protected RequestContext initialValue() {
 try {
 return contextClass.newInstance();
 } catch (Throwable e) {
 e.printStackTrace();
 throw new RuntimeException(e);
 }
 }
};
京東資深工程師分享:微服務(wù)架構(gòu)之網(wǎng)關(guān)層Zuul剖析

 

請求處理生命周期,”pre” filters(認(rèn)證、路由、請求日記)->”routing filters”(將請求發(fā)送到后端)->”post” filters(增加HTTP頭、收集統(tǒng)計和度量、客戶端響應(yīng))

四、過濾器

一些概念

1、類型Type,定義被運行的階段,也就是preroutingposterror階段

2、順序Execution Order,定義同類型鏈執(zhí)行中順序

3、條件Criteria,定義過濾器執(zhí)行的前提條件

4、動作Action,定義過濾器執(zhí)行的業(yè)務(wù)

下面是一個DEMO

class DebugFilter extends ZuulFilter {
 static final DynamicBooleanProperty routingDebug = DynamicPropertyFactory.getInstance().getBooleanProperty(ZuulConstants.ZUUL_DEBUG_REQUEST, true)
 static final DynamicStringProperty debugParameter = DynamicPropertyFactory.getInstance().getStringProperty(ZuulConstants.ZUUL_DEBUG_PARAMETER, "d")
 @Override
 String filterType() {
 return 'pre'
 }
 @Override
 int filterOrder() {
 return 1
 }
 boolean shouldFilter() {
 if ("true".equals(RequestContext.getCurrentContext().getRequest().getParameter(debugParameter.get()))) {
 return true
 }
 return routingDebug.get();
 }
 Object run() {
 RequestContext ctx = RequestContext.getCurrentContext()
 ctx.setDebugRouting(true)
 ctx.setDebugRequest(true)
 ctx.setChunkedRequestBody()
 return null;
 }

五、代碼剖析

在Servlet API 中有一個ServletContextListener接口,它能夠監(jiān)聽 ServletContext 對象的生命周期,實際上就是監(jiān)聽 Web 應(yīng)用的生命周期。接口中定義了兩個方法

/**
 * 當(dāng)Servlet 容器啟動Web 應(yīng)用時調(diào)用該方法。在調(diào)用完該方法之后,容器再對Filter 初始化,
 * 并且對那些在Web 應(yīng)用啟動時就需要被初始化的Servlet 進(jìn)行初始化。
 */
contextInitialized(ServletContextEvent sce) 
/**
 * 當(dāng)Servlet 容器終止Web 應(yīng)用時調(diào)用該方法。在調(diào)用該方法之前,容器會先銷毀所有的Servlet 和Filter 過濾器。
 */
contextDestroyed(ServletContextEvent sce)

在Zuul網(wǎng)關(guān)中

public class InitializeServletListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent arg0) {
 try {
 //實例化
 initZuul();
 
 } catch (Exception e) {
 LOGGER.error("Error while initializing zuul gateway.", e);
 throw new RuntimeException(e);
 }
} 
 private void initZuul() throws Exception {
 //文件管理
 FilterFileManager.init(5, preFiltersPath, postFiltersPath, routeFiltersPath, errorFiltersPath);
 //從DB中加載Filter
 startZuulFilterPoller();
 }
}

在initZuul中,F(xiàn)ilterFileManager主要是做文件管理,起一個poll Thread,定期把FilterDirectory中file放到FilterLoader中,在FilterLoad中會進(jìn)行編譯再放到filterRegistry中。而startZuulFilterPoller主要是判斷DB中有是否變化或者新增的Filer,然后寫到FilterDirectory中

public boolean putFilter(File file) throws Exception {
 Class clazz = COMPILER.compile(file);
 if (!Modifier.isAbstract(clazz.getModifiers())) {
 //通過反射創(chuàng)建對象,可以對此類一無所知
 filter = (ZuulFilter) FILTER_FACTORY.newInstance(clazz);
 filterRegistry.put(file.getAbsolutePath() + file.getName(), filter);
 filterClassLastModified.put(sName, file.lastModified());
 //二次hash檢查
 List<ZuulFilter> list = hashFiltersByType.get(filter.filterType());
 if (list != null) {
 hashFiltersByType.remove(filter.filterType()); //rebuild this list
 }
 }
 }

過濾器對應(yīng)DB的字段如下filter_id,revision,create_time,is_active,is_canary,filter_code,filter_type,filter_name,disable_property_name,filter_order,Application_name

我們再回到主流程看ZuulServlet,每當(dāng)一個客戶請求一個HttpServlet對象,該對象的service()方法就要被調(diào)用,而且傳遞給這個方法一個”請求”(ServletRequest)對象和一個”響應(yīng)”(ServletResponse)對象作為參數(shù)

public class ZuulServlet extends HttpServlet {
private ZuulRunner zuulRunner = new ZuulRunner();
@Override
public void service(JAVAx.servlet.ServletRequest req, javax.servlet.ServletResponse res) throws javax.servlet.ServletException, java.io.IOException {
 try {
 init((HttpServletRequest) req, (HttpServletResponse) res);
RequestContext.getCurrentContext().setZuulEngineRan();
 try {
 preRoute();
 } catch (ZuulException e) {
 error(e);
 postRoute();
 return;
 }
 try {
 route();
 } catch (ZuulException e) {
 error(e);
 postRoute();
 return;
 }
 try {
 postRoute();
 } catch (ZuulException e) {
 error(e);
 return;
 }
 } catch (Throwable e) {
 } finally {
 RequestContext.getCurrentContext().unset();
 }
}

運行時主要從filterRegistry根據(jù)type取出過濾器依次執(zhí)行

六、Zuul2.x版本解讀

Zuul2.x的核心功能特性

服務(wù)器協(xié)議

HTTP/2——完整的入站(inbound)HTTP/2連接服務(wù)器支持

雙向TLS(Mutual TLS)——支持在更安全的場景下運行

彈性特性

自適應(yīng)重試——Netflix用于增強彈性和可用性的核心重試邏輯

源并發(fā)保護——可配置的并發(fā)限制,避免源過載,隔離Zuul背后的各個源

運營特性

請求Passport——跟蹤每個請求的所有生命周期事件,這對調(diào)試異步請求非常有用

狀態(tài)分類——請求成功和失敗的可能狀態(tài)枚舉,比HTTP狀態(tài)碼更精細(xì)

請求嘗試——跟蹤每個代理的嘗試和狀態(tài),對調(diào)試重試和路由特別有用

實際上Zuul2.x是將ZuulFilter變換成Netty Handler,在Netty中,一系列的Handler會聚合在一起并使用Pipline執(zhí)行,拿Netty的Sample來說明下

//EventLoopGroup線程組,包含一組NIO線程
 //bossGroupworkerGroup,一個用于連接管理,另外一個進(jìn)行SocketChannel的網(wǎng)絡(luò)讀寫
 EventLoopGroup bossGroup = new NioEventLoopGroup();
 EventLoopGroup workerGroup = new NioEventLoopGroup();
 ServerBootstrap bootstrap = new ServerBootstrap(); 
 bootstrap.group(bossGroup,workerGroup) 
 .channel(NIOServerSocketChannel.class) 
 .childHandler(new ChannelInitializer<SocketChannel>() { 
 @Override 
 protected void initChannel(SocketChannel ch) throws Exception { 
 ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(10240, 0, 2, 0, 2)) 
 .addLast(new StringDecoder(UTF_8)) 
 .addLast(new LengthFieldPrepender(2)) 
 .addLast(new StringEncoder(UTF_8)) 
 .addLast(new ServerHandler()); 
 } 
 }).childOption(ChannelOption.TCP_NODELAY, true); 
 ChannelFuture future = bootstrap.bind(18080).sync();

在Zuul2.x中默認(rèn)注冊了這些Handler

@Override
protected void initChannel(Channel ch) throws Exception
{
 // Configure our pipeline of ChannelHandlerS.
 ChannelPipeline pipeline = ch.pipeline();
 storeChannel(ch);
 addTimeoutHandlers(pipeline);
 addPassportHandler(pipeline);
 addTcpRelatedHandlers(pipeline);
 addHttp1Handlers(pipeline);
 addHttpRelatedHandlers(pipeline);
 addZuulHandlers(pipeline);
}

我們在上面的pipeline中注冊了一個ServerHandler,這個handler就是用來處理Client端實際發(fā)送的數(shù)據(jù)的

public class ServerHandler extends SimpleChannelInboundHandler<String> { 
@Override 
public void channelRead0(ChannelHandlerContext ctx, String message) throws Exception { 
 System.out.println("from client:" + message); 
 JSONObject json = JSONObject.fromObject(message); 
 String source = json.getString("source"); 
 String md5 = DigestUtils.md5Hex(source); 
 json.put("md5Hex",md5); 
 ctx.writeAndFlush(json.toString());//write bytes to socket,and flush(clear) the buffer cache. 
} 
@Override 
public void channelReadComplete(ChannelHandlerContext ctx) { 
 ctx.flush(); 
} 
@Override 
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 
 cause.printStackTrace(); 
 ctx.close(); 
} 
}

Zuul2.x相比1.x最大的變化就是異步化,最大的功臣莫過于Netty,上面涉及到的很重要的就是ChannelPipleline和ChannelFuture

ChannelPipleline實際上是一個雙向鏈表,提供了addBeforeaddAfteraddFirstaddLastremove等方法,鏈表操作會影響Handler的調(diào)用關(guān)系。ChannelFuture是為了解決如何獲取異步結(jié)果的問題而聲音設(shè)計的接口,有未完成和完成這兩種狀態(tài),不過通過CannelFuture的get()方法獲取結(jié)果可能導(dǎo)致線程長時間被阻塞,一般使用非阻塞的GenericFutureListener

@Override
 public void channelRead(ChannelHandlerContext ctx, Object msg) {
 ChannelFuture future = ctx.channel().close();
 future.addListener(new ChannelFutureListener() {
 public void operationComplete(ChannelFuture future) {
 }
 });
 }

點擊查閱關(guān)于NIO和BIO的深度解析,Netty相關(guān)資料感興趣的朋友可以網(wǎng)上了解。

分享到:
標(biāo)簽:微服 架構(gòu)
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達(dá)人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定