商丘做网站,商丘网站优化,商丘网络推广,商丘网络公司
当前位置:首页 > 新闻资讯 > 建站经验 >

HTTP服务异步化改造实践

发表日期:2018-01-19 21:46聚圣源浏览次数: 本文关键词:HTTP,服务,异步,化,改造,实践,背景,我们,在,

 

  背景

  我们在入口层有一个提供HTTP服务的应用。随着业务的复杂,一个用户请求的处理过程,涉及多个对后端远程服务的调用。为了实现的简单,目前都是使用同步方式完成的,也就是在一个请求的处理过程中,会占用一个容器线程进行逻辑运算和同步远程调用。这种开发方式的好处是直观,开发成本低,但也带来了一些稳定性和资源浪费的问题。对于我们的HTTP服务来说,同步化的实现带来下面这3个问题。

  下游服务超时带来的服务可用性问题。一部分的请求超时会导致HTTP服务线程池被占满,从而导致其它的请求无法获取到线程资源而失败。

  性能问题,多个对远程服务的调用串行执行,导致服务响应时间长。

  容量问题,服务吞吐量受限。每个请求长时间占用线程,导致线程得不到充分利用。

  为了解决这些问题,结合目前使用的技术栈以及适应成本,我们对HTTP服务进行了一次异步化改造。

  

HTTP服务异步化改造实践

 

  解决方案

  异步化编程中闻名的Callback Hell,让不少同学望而止步。当业务复杂的时候,各种call back互相嵌套,使代码变得更加容易出错和不易理解。业内也有有不少框架提供了异步化编程支持,有以下三个思路:

  纤程

  纤程可以认为是轻量级的用户线程,脱离了OS的调度机制,在应用级别进行调度管理。由于它只维护了基本的执行栈信息,并不立即分配执行资源,因此,它可以轻松创建成千上万的纤程(受内存大小的限制),通过极少的线程完成对纤程的调度执行。这个方向的代表有微信团队开源的libco,以及在语言层面上支持的Go语言等。libco hook了底层IO相关的系统函数,通过底层IO事件驱动纤程的调度执行。当遇到同步调用网络请求时,libco自动注册回调监听器,并让出CPU。而在IO事件完成或者超时候,自动恢复纤程,然后调度执行。它的实现机制决定了它非常适合依赖耗时IO服务的实现。承载了微信千万级调用的一个基石。不过遗憾的是,libco是一个高效的c/c++协程库,并没有在JVM上实现。

  Quasar是在JVM之上实现了纤程机制,基本可以在Quasar的类库基础上,以同步的模式来编写异步的代码。在真正执行代码前,通过编译或者Instrument Agent的形式织入相关的字节码。从头起步引入纤程还是一个不错的选择。对现有项目的改造,需要对现有的线程类修改成纤程类,这需要改动我们底层非常多的中间件。另外业内公布的使用经验较少,后续可以持续关注它的发展。

  Actor模型

  Actor模型其实不是什么新概念了。近些年有逐渐流行的趋势。Actor模型中一个核心概念就是Actor实体。每个Actor实体负责一个逻辑计算。传统并发编程都是基于共享内存的方式来达到多线程之间的通讯的目的。Actor之间不共享数据,也不直接通讯,而是发送或者接受mailbox/queque中的消息来达到通讯的目的。Actor之间通过消息来驱动。正式由于发送者与接受者的分离,是的Actor具有内在的并发特性,它可以不用考虑actor之间的同步问题,不受限制的调度执行收到消息的Actor,从而优化了IO等待的问题。Scala,Golang等在语言层面支持Actor模型。Scala的新版中,推出Akka来完成Actor模型,并有了Java版本。但是需要引入新的API,对现有业务代码块改造成Actor模型,对现有代码改动较大。

  RX

  Rx也是一种编程模型,它尝试提供统一的异步编程接口封装来操作一个可观察的数据流。其吸收了函数式编程的优秀思想,并将观察者,迭代器模式实现的淋漓精致。当下流行的语言,基本都有相应的实现。 如RxJava类库,即提供了java版本的实现,RxJava在Netflix的Zuul项目中得到成功的应用。Rx看起来更像是一种编程思想的突破。它提供了统一的函数式的风格编程接口来简化异步程序的编写,同时内部也通过callback机制,比Actor能获得更好的响应速度。在调研过程中,我们发现它同样要求对现有代码做较大改动,并将之前的同步模式转换成函数式编程风格。

  综合来看,以上一些优秀的框架并不能立即利用到我们的项目中,引入成本还是很高的。结合现有技术架构上,以及产品正在快速迭代的环境下,我们对HTTP服务进行了一次轻量级的异步化改造。这次改造,引入Graph-Based Execution Engine来解决服务之间复杂的依赖关系,集中管理异步状态。结合Servlet 3.0提供了请求及释放tomcat容器线程的接口,充分利用Servlet容器线程资源。最后,通过spring mvc的异步模块衔接这两种异步机制,达到了全栈异步化的目的。

  原理分析

  Servlet从3.0开始,增加了异步规范。spring mvc从3.2开始也支持异步Servlet 3.0。针对现有技术栈,实现全栈异步化可以通过下面的一段代码来说明:

  

HTTP服务异步化改造实践

 

  可以看到,orderService.createOrderAsync(request) 这个调用在请求发出后,不等待返回结果,而是立即返回。在返回的future对象上注册了一个监听器。最后返回DeferredResult。spring mvc在收到返回结果为DeferredResult(当然也可以是WebAsyncTask和Callable)时,将调用

  AsyncContext context = HttpServletRequest.startAsync(req, response);

  来获取上下文,然后退出容器线程。当createOrderAsync完成得到结果后,注册在future上的监听器被唤起开始执行,此处忽略中间的一些处理,直接将RPC结果设置在DeferredResult上。spring mvc在获得执行结果后,通过调用Servet的上下文

  context.dispatch();

  来通知容器继续执行后续操作,例如重新进入spring mvc 拦截器的complete流程,最终输出结果到客户端。整个流程可以用下图表示:

  

HTTP服务异步化改造实践

 

  图中3个框表示整个请求被打散在3个阶段执行。第一框到第二个框之间表示RPC服务正在执行。洛阳此时处理请求的线程已经释放。它可以继续接受处理其它请求。RPC服务有返回值或者超时的时候,会在单独的一个线程池中唤起注册的监听器。最终通知Servlet容器来继续执行第三个框中的interceptor.complete。通过回调通知的机制,将使CPU得到充分的利用。避免了启动一个宝贵的线程来等待IO的完成。

  Graph-Based Execution Engine

  真实的业务场景要比上面的代码复杂的多。例如下单业务,一般都会依赖用户,报价,支付,优惠等服务。服务之间存在依赖关系,如黑名单服务校验通过才能提交订单。还有一些服务之间处于对等关系,互相之间没有依赖,可以并行调用,以降低服务的整体响应时间。如下图所示,这是一个常见的服务依赖关系:

  

HTTP服务异步化改造实践

 

  图中A、B、C没有依赖关系,实际上可以并行执行。C服务不关心返回结果,因此将调用通知发出后及可结束。D服务需要等待A的结果,E需要等待B、D的执行结果。使用传统的异步编程的话,大概是这个样子:

  

HTTP服务异步化改造实践

 

  可以看到服务的依赖关系隐藏在代码行间,业务逻辑穿插在各个callback中,中间引入了ListeableFuturefutureBT 管理异步状态。不太易于阅读及维护。为此,我们提供了一个Graph-Based Execution Engine(GBEE)。GBEE的主要目标在于解决以下:

  (1)管理服务之间的依赖关系

  将服务之间的依赖关系从业务代码中分离出来,通过一个有向无环图的数据结构来描述服务之间的依赖关系。图中每个节点保存了其前驱(后驱)节点。每个节点可以执行的前提条件是其所有前驱节点都完成。

  (2)统一注册callback

  每个节点可以覆写callback,用来注册自身的监听器。一般用来转换结果,记录监控。callback统一由执行器管理注册。避免在代码嵌套中注册监听器。

  (3)使用异步事件驱动执行

  在GBEE中统一注册异步事件监听器,在事件发生时驱动执行callback,或者在条件成熟时,唤起下一个节点的执行。

  具体做法:

  (1)将业务逻辑分离成多个节点,每个节点负责具体的业务逻辑执行,但没有任何状态,例如发起异步RPC调用,并返回ListenableFuture。

  

HTTP服务异步化改造实践

 

  (2)通过配置文件来定义依赖管理

  每个Node定义了自己的parents,即表示依赖关系。spring本身提供了服务的依赖管理能力。因此其依赖关系定义如下:

  

HTTP服务异步化改造实践

 

  (3)提供了一个执行器Graph-Based Executor 来负责统一注册监听器以及管理异步状态。

  每个请求到达后,通过上面的依赖配置,可以构造出一个Graph-Based执行器:

  

HTTP服务异步化改造实践

 

  Graph会找到根节点,多个根节点可以同时并行。

  

HTTP服务异步化改造实践

 

  apply(node, context) 是一个递归调用,每次执行完当前node,主动探测下是否可以执行父节点为自己的节点:

  

HTTP服务异步化改造实践

 

  Graph-Based Executor 将业务代码与底层的异步机制解耦,使得各个节点更加关注自身业务。

  后记

  在迁移具体业务时,也遇到一些比较常见的问题,供后续的实施者参考。

  (1)公司RPC服务主要送是dubbo,利用公司的基础组件,可以方便使用异步调用。

  (2)线上还有很多应用使用tomcat 6,Servlet 3 从tomcat 7开始支持,应该将相关应用升级到tomcat 7.

  (3)web.xml 配置有几个比较重要的配置。

  为了让spring mvc真正启用异步支持,除了需要将org.springframework.web.servlet.DispatcherServlet的异步选项激活,即:true

  

HTTP服务异步化改造实践

 

  还需要将此servlet之前的所有filter的async-supported设置成true。只要中间有一个filter没有设置,后面的设置都是无效的。并且在后续开发中,如果增加了filter,也一定要配置上。

  (4)ThreadLocal 问题。

  现有系统的一些通用的上下文参数通过ThreadLocal传递。异步化改造后,代码并不是始终在请求线程中执行。这就使得通过ThreadLocal传递的变量失效。我们采用了两种方法来解决,一是一些业务代码的改造,通过参数的形式来传递。另一种是将一些通用变量存入HttpServletRequest的Attribute里。异步上下文中保持了对HttpServletRequest的引用。然后通过工具类直接从HttpServletRequest提取公共变量。

  (5)异常处理

  在同步代码中,一般我们会自定义一些业务异常,这些业务异常被捕获后,根据异常理性及状态码,做一些业务逻辑。ListeableFuture继承的Future接口规定了,在异步计算过程中抛出的所有异常封装在ExecutionException中。此时,同步代码中的catch,就不能捕获ExecutionException了。此时业务代码就需要修改捕获的具体类型,然后通过Exception.getCause()来获取原始异常。这块可以通过Graph-Based Execution Engine统一处理。将原始异常转换后,调用节点的onException.

如没特殊注明,文章均来自网络! 转载请注明来自:http://www.jushengyuan.com.cn/news/jzjy/9872.html

网站设计案例推荐

热门文章

站长工具综合查询里面SSL证书不...

SSL证书不安全是怎么回事?但是点进去这个提示后,显示的是别人的tdk是不是被劫持或者被黑了?...

日期:2018-03-27 浏览次数:1881

简洁而实用的版权信息可增色网...

打开网站,人们自然会从上往下浏览,首先映入眼帘的一定是BANNER主视觉,然后是网站主体内容部分。相比较而言,注意到网站底部版权信息的浏览者确实不多,但这并说明网站版权信...

日期:2018-03-05 浏览次数:1873

网站设计需要注意的3点问题...

对于网站设计来讲会受到很多因素的影响,而且不同类型的网站,在设计时需要体现的元素也不一样,比如说对于一个企业网站更想体现出品牌以及产品的特点,主要是对产品、企业信...

日期:2018-02-12 浏览次数:1803

企业网站为什么要改版 改版选择...

网站改版,是每个建站企业必须面临的工作。相信也有不少站长问,已经做好的企业网站,为何还要大费周章重新进行改版设计呢?下面小编就来给大家说说,企业究竟为什么要改变,并...

日期:2018-03-26 浏览次数:1332

永城网站制作:模板建站不可不...

随着互联网建站尤其是自助建站热潮不断高涨,建站行业涌现出越来越多的自助建站平台,这些平台普遍都提供网站模板可选。...

日期:2018-04-30 浏览次数:931

相关文章

Web服务器、应用程序服务器、...

IIS、Apache、Tomcat、Weblogic、WebSphere都各属于哪种服务器,这些问题困惑了很久,今天终于梳理清楚了: Web服务器的基本功能就是提供Web信息浏览服务。它只需支持HTTP协议、HTML文档格式...

日期:2018-01-19 浏览次数:79

教你把HTTP网站免费转成HTTPS网站...

关于HTTPS和HTTP的区别,以及HTTPS的优势、HTTPS和SSL之间的关系等,本文不做任何讨论,感兴趣的可以自行百度。本文只用来记录作为一个外行人,如何一步步构建自己的HTTPS服务器的过程...

日期:2018-01-14 浏览次数:72

HTTP/2 之服务器推送 (Server Push)...

HTTP/1.X出色地满足互联网的普遍访问需求,但随着互联网的不断发展,其性能越来越成为瓶颈。IETF在2015年发布了HTTP/2标准, 着重于提高HTTP的访问体验, HTTP2优势主要包括: 二进制传输、头...

日期:2018-01-14 浏览次数:66

HTTPS连接过程以及中间人攻击劫...

一 、HTTPS连接过程及中间人攻击原理 https协议就是http+ssl协议,如下图所示为其连接过程: 1.https请求 客户端向服务端发送https请求; 2.生成公钥和私钥 服务端收到请求之后,生成公钥和...

日期:2018-01-14 浏览次数:84

百度发布《移动搜索建站优化白...

《百度移动搜索建站优化白皮书》之《网站常见问题汇总》,包括网站域名更换、网站关闭服务器、HTTPS站点改造等。 一、网站换域名 1、网站换域名的定义 网站换域名,包括从一个二...

日期:2018-01-14 浏览次数:86

随机推荐

百度站长网站logo审核示例以及个...

美国主机和香港主机的对比分析...

企业或者个人自己建网站,需要...

您的网站alt图片标签做对了吗?...

史上最全网站建设备案和不备案...

如何利用情感化元素提升内容传...