您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

京东资深工程师分享:微服务架构之网关层Zuul剖析

时间:2021-04-21 09:44:03  来源:今日头条  作者:IT技术分享

 

一、Zuul简介

Zuul相当于是第三方调用和服务提供方之间的防护门,其中最大的亮点就是可动态发布过滤器

二、Zuul可以为我们提供什么

1、权限控制

2、预警和监控

3、红绿部署、(粘性)金丝雀部署,流量调度支持

4、流量复制转发,方便分支测试、埋点测试、压力测试

5、跨区域高可用,异常感知

6、防爬防攻击

7、负载均衡、健康检查和屏蔽坏节点

8、静态资源处理

9、重试容错服务

三、Zuul网关架构

京东资深工程师分享:微服务架构之网关层Zuul剖析

 

可以看到其架构主要分为发布模块、控制管理加载模块、运行时模块、线程安全的请求上下文模块。在Spring Cloud中,Zuul每个后端都称为一个Route,为了避免资源抢占,整合了Hystrix进行隔离和限流,基于线程的隔离机制,另外一种机制是信号量,后面文章会提到。Zuul默认使用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);
 }
 }
};
京东资深工程师分享:微服务架构之网关层Zuul剖析

 

请求处理生命周期,”pre” filters(认证、路由、请求日记)->”routing filters”(将请求发送到后端)->”post” filters(增加HTTP头、收集统计和度量、客户端响应)

四、过滤器

一些概念

1、类型Type,定义被运行的阶段,也就是preroutingposterror阶段

2、顺序Execution Order,定义同类型链执行中顺序

3、条件Criteria,定义过滤器执行的前提条件

4、动作Action,定义过滤器执行的业务

下面是一个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接口,它能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期。接口中定义了两个方法

/**
 * 当Servlet 容器启动Web 应用时调用该方法。在调用完该方法之后,容器再对Filter 初始化,
 * 并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。
 */
contextInitialized(ServletContextEvent sce) 
/**
 * 当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet 和Filter 过滤器。
 */
contextDestroyed(ServletContextEvent sce)

在Zuul网关中

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中,FilterFileManager主要是做文件管理,起一个poll Thread,定期把FilterDirectory中file放到FilterLoader中,在FilterLoad中会进行编译再放到filterRegistry中。而startZuulFilterPoller主要是判断DB中有是否变化或者新增的Filer,然后写到FilterDirectory中

public boolean putFilter(File file) throws Exception {
 Class clazz = COMPILER.compile(file);
 if (!Modifier.isAbstract(clazz.getModifiers())) {
 //通过反射创建对象,可以对此类一无所知
 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
 }
 }
 }

过滤器对应DB的字段如下filter_id,revision,create_time,is_active,is_canary,filter_code,filter_type,filter_name,disable_property_name,filter_order,Application_name

我们再回到主流程看ZuulServlet,每当一个客户请求一个HttpServlet对象,该对象的service()方法就要被调用,而且传递给这个方法一个”请求”(ServletRequest)对象和一个”响应”(ServletResponse)对象作为参数

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根据type取出过滤器依次执行

六、Zuul2.x版本解读

Zuul2.x的核心功能特性

服务器协议

HTTP/2——完整的入站(inbound)HTTP/2连接服务器支持

双向TLS(Mutual TLS)——支持在更安全的场景下运行

弹性特性

自适应重试——Netflix用于增强弹性和可用性的核心重试逻辑

源并发保护——可配置的并发限制,避免源过载,隔离Zuul背后的各个源

运营特性

请求Passport——跟踪每个请求的所有生命周期事件,这对调试异步请求非常有用

状态分类——请求成功和失败的可能状态枚举,比HTTP状态码更精细

请求尝试——跟踪每个代理的尝试和状态,对调试重试和路由特别有用

实际上Zuul2.x是将ZuulFilter变换成Netty Handler,在Netty中,一系列的Handler会聚合在一起并使用Pipline执行,拿Netty的Sample来说明下

//EventLoopGroup线程组,包含一组NIO线程
 //bossGroupworkerGroup,一个用于连接管理,另外一个进行SocketChannel的网络读写
 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中默认注册了这些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端实际发送的数据的

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的调用关系。ChannelFuture是为了解决如何获取异步结果的问题而声音设计的接口,有未完成和完成这两种状态,不过通过CannelFuture的get()方法获取结果可能导致线程长时间被阻塞,一般使用非阻塞的GenericFutureListener

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

点击查阅关于NIO和BIO的深度解析,Netty相关资料感兴趣的朋友可以网上了解。



Tags:微服务架构   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
前言要理解微服务,首先要先理解不是微服务的那些。通常跟微服务相对的是单体应用,即将所有功能都打包成在一个独立单元的应用程序。从单体应用到微服务并不是一蹴而就的,这是一...【详细内容】
2021-07-09  Tags: 微服务架构  点击:(112)  评论:(0)  加入收藏
一、Zuul简介Zuul相当于是第三方调用和服务提供方之间的防护门,其中最大的亮点就是可动态发布过滤器二、Zuul可以为我们提供什么1、权限控制2、预警和监控3、红绿部署、(粘...【详细内容】
2021-04-21  Tags: 微服务架构  点击:(229)  评论:(0)  加入收藏
前不久作为架构师完成了某知名快消企业的一个业务中台建设。系统上线后,经历了双十一活动的流量高峰,整体运行稳定。最近有空,便将此次架构的思路,心得稍作整理在这篇博客中分享...【详细内容】
2021-02-07  Tags: 微服务架构  点击:(181)  评论:(0)  加入收藏
文章简介:作者结合自身微服务架构研发经验进行回顾、总结,本文将介绍微服务架构中,在技术选型时需要注意哪些选型原则,会遇到哪些开源框架,又该如何选择, 进行了全面的归纳、对比,希望能够为大家提供一些思路、方向,少走一些...【详细内容】
2021-02-05  Tags: 微服务架构  点击:(160)  评论:(0)  加入收藏
思维导图 文章已收录Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary一、前言伴随着Eurka2.0版本已停止维护,开始要考虑使用微服务新一代的开源的注册中心...【详细内容】
2020-11-13  Tags: 微服务架构  点击:(159)  评论:(0)  加入收藏
消息总线的定义前面在1.4.2节中强调过,在微服务架构中,经常会使用REST 服务或基于消息的通信机制。在3.6节中也详细介绍了消息通信的实现方式。消息总线就是一种基于消息的通...【详细内容】
2020-09-29  Tags: 微服务架构  点击:(140)  评论:(0)  加入收藏
微服务的高级主题一自动扩展Spring Cloud 提供了大规模部署微服务所必需的支持。为了获得像云服务环境一样的能力, 微服务实例也应该能够根据流量的规模来自动扩展,也称自动缩...【详细内容】
2020-09-23  Tags: 微服务架构  点击:(96)  评论:(0)  加入收藏
Spring Cloud 微服务总体架构图Spring cloud作为当下主流的微服务框架,让我们实现微服务架构简单快捷,Spring cloud中各个组件在微服务架构中扮演的角色如图所示。spring-cl...【详细内容】
2020-09-20  Tags: 微服务架构  点击:(133)  评论:(0)  加入收藏
常见微服务的消费者本节就常见的微服务的消费者进行介绍。在Java领域比较常用的消费者框架主要有HttpClient、Ribbon、Feign 等。 Apache HttpClientApache HttpClient是Apa...【详细内容】
2020-09-11  Tags: 微服务架构  点击:(129)  评论:(0)  加入收藏
什么是微服务模式随着网络基础设施的高速发展,以及越来越多的个体接入互联网,在考虑构建支持海量请求以及多变业务的软件平台时,微服务架构成为多数人的首选。微服务架构的出现...【详细内容】
2020-09-09  Tags: 微服务架构  点击:(95)  评论:(0)  加入收藏
▌简易百科推荐
为了构建高并发、高可用的系统架构,压测、容量预估必不可少,在发现系统瓶颈后,需要有针对性地扩容、优化。结合楼主的经验和知识,本文做一个简单的总结,欢迎探讨。1、QPS保障目标...【详细内容】
2021-12-27  大数据架构师    Tags:架构   点击:(3)  评论:(0)  加入收藏
前言 单片机开发中,我们往往首先接触裸机系统,然后到RTOS,那么它们的软件架构是什么?这是我们开发人员必须认真考虑的问题。在实际项目中,首先选择软件架构是非常重要的,接下来我...【详细内容】
2021-12-23  正点原子原子哥    Tags:架构   点击:(7)  评论:(0)  加入收藏
现有数据架构难以支撑现代化应用的实现。 随着云计算产业的快速崛起,带动着各行各业开始自己的基于云的业务创新和信息架构现代化,云计算的可靠性、灵活性、按需计费的高性价...【详细内容】
2021-12-22    CSDN  Tags:数据架构   点击:(10)  评论:(0)  加入收藏
▶ 企业级项目结构封装释义 如果你刚毕业,作为Java新手程序员进入一家企业,拿到代码之后,你有什么感觉呢?如果你没有听过多模块、分布式这类的概念,那么多半会傻眼。为什么一个项...【详细内容】
2021-12-20  蜗牛学苑    Tags:微服务   点击:(8)  评论:(0)  加入收藏
我是一名程序员关注我们吧,我们会多多分享技术和资源。进来的朋友,可以多了解下青锋的产品,已开源多个产品的架构版本。Thymeleaf版(开源)1、采用技术: springboot、layui、Thymel...【详细内容】
2021-12-14  青锋爱编程    Tags:后台架构   点击:(20)  评论:(0)  加入收藏
在了解连接池之前,我们需要对长、短链接建立初步认识。我们都知道,网络通信大部分都是基于TCP/IP协议,数据传输之前,双方通过“三次握手”建立连接,当数据传输完成之后,又通过“四次挥手”释放连接,以下是“三次握手”与“四...【详细内容】
2021-12-14  架构即人生    Tags:连接池   点击:(16)  评论:(0)  加入收藏
随着移动互联网技术的快速发展,在新业务、新领域、新场景的驱动下,基于传统大型机的服务部署方式,不仅难以适应快速增长的业务需求,而且持续耗费高昂的成本,从而使得各大生产厂商...【详细内容】
2021-12-08  架构驿站    Tags:分布式系统   点击:(23)  评论:(0)  加入收藏
本系列为 Netty 学习笔记,本篇介绍总结Java NIO 网络编程。Netty 作为一个异步的、事件驱动的网络应用程序框架,也是基于NIO的客户、服务器端的编程框架。其对 Java NIO 底层...【详细内容】
2021-12-07  大数据架构师    Tags:Netty   点击:(16)  评论:(0)  加入收藏
前面谈过很多关于数字化转型,云原生,微服务方面的文章。虽然自己一直做大集团的SOA集成平台咨询规划和建设项目,但是当前传统企业数字化转型,国产化和自主可控,云原生,微服务是不...【详细内容】
2021-12-06  人月聊IT    Tags:架构   点击:(23)  评论:(0)  加入收藏
微服务看似是完美的解决方案。从理论上来说,微服务提高了开发速度,而且还可以单独扩展应用的某个部分。但实际上,微服务带有一定的隐形成本。我认为,没有亲自动手构建微服务的经历,就无法真正了解其复杂性。...【详细内容】
2021-11-26  GreekDataGuy  CSDN  Tags:单体应用   点击:(35)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条