知识大全 Web请求异步处理降低应用依赖风险

Posted 事件

篇首语:饭可以一日不吃,觉可以一日不睡,书不可以一日不读本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Web请求异步处理降低应用依赖风险相关的知识,希望对你有一定的参考价值。

Web请求异步处理降低应用依赖风险  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  问题凸现        年关到了 商家忙着促销 网站忙着推广 阿里软件的服务集成平台也面临第一次多方大规模的压力考验 根据该平台 版本的压力测试结果 我们估算了一下现有的推广会带来的压力 基本上确定了服务集成平台年底不需要扩容 SA(System Administrator 系统管理员)为了保险起见还是通过请求方式来做定时的心跳检测 保证服务集成平台的可靠性 结果阿里旺旺推广开始的第一天 SA的报警短信就在几个忙时段不停地发告警 但是查看生产环境的服务器状况以及应用状况后看不出有什么问题 于是开始怀疑是否告警机制不是很合理 几日的访问记录统计报告看过以后 发现了几个问题 首先由于推广是在IM登录时段集中式的推广 因此高峰期比较集中 压力也很大 而告警发生的时刻也是那些时候 另外发现那些推广使用的API的处理时间比较长 同时还有些出现了问题 这几天除了服务集成平台告警以外 那些API服务器也在告警 因此可以看出问题应该是由于API提供商响应速度慢而拖累了服务集成平台的处理能力 监控机制在高峰情况下没有得到及时的响应 就认为是服务器已经处于无效状态         其实这类问题在我们现在的应用体系架构中常常出现 原因是现在很少再有纯粹 封闭式 应用 对数据库的依赖 对存储的依赖 对第三方系统的依赖等等 这也让我回忆到在前一阵子参加的安全会议中 腾迅的安全技术团队的负责人说安全现在最大的问题就在于合作的第三方的安全不受控而引发的安全潜在影响 Web应用未尝不是 从最基本的事务处理要小粒度 不要在事务中包含第三方依赖 到心跳检测 容错方案的制定等 都已经让我们对这方面的问题有所注意 但是往往这类问题不是局部设计可以看到的 如果没有一个总体架构设计者对于全局的把握 协调和防范 那么问题出现并且带来的影响将会很大         从前对于服务集成平台的压力测试主要是在ISP服务 基本正常 的情况下做的 但是这次问题的暴露就要求我们在第三方依赖出现边界问题时 及时做出一些措施或者改进设计         问题分析以及解决方案        问题原因         Http请求处理的阻塞方式 后端服务处理时间过长 服务质量不稳定 Web Container接受请求线程资源有限         解决方案         改阻塞方式为非阻塞方式来处理请求 设置后端超时时间 主动断开连接 回收资源 修改容器配置 增加线程池大小以及等待队列长度         解决方案一是最难做到的 后面的篇幅将描述对于这方面技术的探索         解决方案二比较容易 允许各个ISP设置自己API容许的最大超时时间         解决方案三Tomcat和JBoss在Connector中有两个参数配置(maxThreads和acceptCount)可以做调整         第一个方案其实和JDK 支持的NIO是一种想法 只是我们在Socket中都已经采用过了 而在Http请求处理中因为要依赖于Web Container开发商的实现 所以至今还没有被广泛应用 不过在开源社区已经有用Mina实现的Http协议处理的框架 需要注意的是 现在Web应用对于Web请求高效处理的需求仅仅是很小的一方面 其实还有很多类似于安全 缓存 监控等等附加功能也占据着很重要的地位         Servlet 规范经过快一年的推广 已经被各大Web Container厂商所接受 Tomcat JBoss Jetty 都宣称自己对Servlet 作了较好的支持 而在Servlet 中最广为关注的一个特性就是异步服务处理Servlet(Async Servlet) 这点也是解决我目前面临问题的最好手段

        Servlet 与服务异步处理        Servlet 主要的新特性分成四部分 内嵌式的使用模式 Annotation的支持 Async Servlet的支持和安全提升 内嵌式的使用很早就在Jetty中被实现 也成为Jetty的优势之一 Annotation也只能说是锦上添花的部分 而安全暂时没有怎么用到 所以最关心的还是Async Servlet部分 Async Servlet到底是什么样的概念 这里就大致描述一下在Servlet 规范中对它的介绍         支持 Comet(彗星) 最早期的Http请求就是无状态的请求和响应 所有的数据一次性在请求后返回给客户端由客户端渲染 后来发展到AJAX 页面的请求和渲染由全局变成了局部 而Comet适合事件驱动的Web应用和对交互性和实时性要求很强的应用 通过建立客户端和服务端的长连接通道 在一次请求后可以主动推送服务端数据的变更情况到客户端 长连接建立的策略有两种 Http Streaming和Http Long Polling 前者客户端打开一个单一的与服务器端的 HTTP 持久连接 服务器通过此连接把数据发送过来 客户端对它们进行增量处理 后者由客户端向服务器端发出请求并打开一个连接 这个连接只有在收到服务器端的数据之后才会关闭 服务器端发送完数据之后 就立即关闭连接 客户端则马上再打开一个新的连接 等待下一次的数据 支持Suspending a request 通过在ServletRequest中增加suspend resume plete等 其将Http请求处理的block模式转变成为not block模式 同时支持对于状态的查询(suspend resume timeout) 请求处理过程中支持事件机制 响应也支持状态查询         图 异步服务请求基本流程        现实中的异步服务处理 Tomcat 的异步服务处理        这里使用的是Tomcat 版本 在Tomcat中对于异步处理描述在Advanced IO中作了说明 主要分成两部分 Comet的支持和异步输出         Comet的支持作用分成两部分 请求读数据的非阻塞 响应处理的异步执行 前者可以防止在大流量数据上传过程中 信道空闲等待的资源浪费 后者用于在处理请求时 依赖于第三方或者本身处理比较耗时的情况下 悬挂起请求处理线程 提高请求处理能力 完成处理后异步输出结果         Servlet不再是原来对于几个标准的Http请求类型的方法实现 而是对于事件响应的处理 Comet定义了 个基础的事件         EventType BEGIN:客户端建立起连接时激发的事件 可以用于资源初始化 EventType READ:有数据可以被读入的事件 (熟悉NIO的事件模式应该可以了解) EventType END:请求处理结束时激发的事件 可以用于资源清理 EventType ERROR:当请求处理出现问题时激发的事件 (IO异常 超时等)        还有一些子事件类型 例如超时就属于ERROR的子事件类型 可以在事件处理中更加精确地定位事件类型         必需的配置 在server xml中配置如下(红色部分)         <Connector port= protocol= yote         connectionTimeout=         redirectPort= />        实际代码范例如下         //CometProcessor接口必需被实现 一旦实现以后 则该Servlet在配置好以后不会再调用service get post等方法的实现         public class SIPCometTomcatServlet extends HttpServlet implements CometProcessor                @Override        //事件处理响应方法实现        public void event(CometEvent event) throws IOException ServletException                if (event getEventType() == CometEvent EventType BEGIN)                //设置事件超时时间        event setTimeout( * )         //另起线程处理后台工作 异步返回结果 事件响应将不等待后台处理直接返回        new Handler(event getHttpServletRequest() event getHttpServletResponse()) start()                 else if (event getEventType() == CometEvent EventType ERROR)                //结束事件 回收request response资源        event close()                 else if (event getEventType() == CometEvent EventType END)                event close()                         //另起一个线程异步处理请求         class Handler extends java lang Thread                private HttpServletResponse response;        private HttpServletRequest request;        public Handler(HttpServletRequest request HttpServletResponse response)                this response = response;        this request = request;                @Override        public void run()                try                String id;        id = request getParameter( id )         if (id == null)        id = no id ;        Thread sleep( )         PrintWriter pw = response getWriter()         pw write(id)         pw flush()         catch (Exception e)                e printStackTrace()                                         使用过程中的一些总结         事件响应框架将服务的请求由完整的一次服务处理切割成为细粒度的多事件处理 为请求多阶段并行处理提供了框架基础 Event对象在事件处理方法结束后就被回收了 但是request和response在事件处理完以后还可以继续使用 因此可以看出原来的阻塞式的方式已经可以通过事件的切分成为非阻塞的方式 没有提供Servlet 中描述的suspend resume plete方法 无法主动控制request的异步处理 上面的代码可以看出我只使用了Begin方法启动了一个线程 但是由于无法主动地结束请求 因此在向客户端返回数据以后还要等到超时才会结束这次会话 (看了Tomcat的代码 也想模仿close的动作但是由于它使用了protected无法获取封装的request对象 因此无法释放资源) 当然也可以通过客户端配合 由客户端主动发起再次的数据传输激发READ事件来结束会话 这么做对客户端的依赖比较强 同时也增加了客户端的处理复杂度 Tomcat支持异步输出 在APR或者NIO的模式下 Tomcat支持在系统压力增大的时候 支持异步回写大文件数据         总体上来说实现了部分对于Comet的支持 但是没有对异步服务流程作很好的支持 无法在开发中使用(简单顺畅的使用)         JBoss的异步服务处理        JBoss 版本配置和使用与Tomcat 类似 没有什么差异         JBoss 刚刚发布了RC版本 对于异步服务处理作了很大的改动 与Tomcat配置很不同 这里具体的说一下JBoss 中的异步服务使用         JBoss 已经将Tomcat中的Http NioProtocol给删除了 取而代之的是JBoss自己servlet包内增加的一个HttpEventServlet接口 这个接口和Tomcat的CometProcessor类似         首先 必须配置JBoss内置的Web容器为APR模式 也就是配置jbossweb sar下面的server xml中Connector 如下         <Connector protocol= yote port= address= $jboss bind address         connectionTimeout= redirectPort= />        其次异步服务处理的Servlet必须实现HttpEventServlet接口 接口只有一个方法 就是事件处理方法 public void event(HttpEvent event) 事件定义与Tomcat稍有不同 在BEGIN ERROR READ END基础上增加了TIMEOUT EOF EVENT WRITE四个事件 同时去掉了SubType         TIMEOUT其实是从原来的Error的SubType分离出来的 这个方法是在最后一次处理事件到当前时间超过设定的超时时间而被激发的 同时TIMEOUT被激发并不会关闭请求处理流程 必须显示调用事件的close方法才会结束会话 EOF事件将会在客户端主动断连的情况下被触发 就好比IE窗口在请求过程中被关闭就会被触发 EVENT事件在事件对象被调用resume的时候被激发 按照原意应该最好可以附带上一些自定义信息来做一些工作 但是我自己使用过程中还没有发现有什么好的办法可以在事件中附带信息到事件处理中 WRITE方法在调用isWriteReady方法时被激发 可以在网络出现问题或者繁忙的时候异步等待输出         再则 JBoss的事件对象还支持几个方法来实现异步处理以及Comet机制 方法如下         close方法 表示一次请求处理的结束 会告知客户端没有数据返回了 同时也会激发END事件 setTimeout方法 设置连接超时时间(单位毫秒) 计算超时是从最近的事件处理时间开始记录的 如果发生超时 则会激发TIMEOUT事件 isReadReady方法 如果连接有数据可以读取则返回true 如果这个方法返回false servlet还试图去读去数据 则会阻塞 isWriteReady方法 如果返回true 则连接可以无阻塞的写出数据 如果返回false servlet必须停止写数据 如果强制写出 则可能会发生IO错误或者会采用异步输出 当客户端的输出通道可用以后 则会激发write事件 suspend方法 suspend连接处理线程直到timeout发生或者resume被调用 实际上意味着servlet在suspend以后不再收到READ事件 READ事件将会在后台被不断的激发 除非被suspend resume方法 会激发event事件 可以利用这个方法来结束异步处理 同时也可以激活因为suspend停止的read事件 同时也可以在resume以后再调用suspend方法 注意 这里未必是要求必须先suspend以后再resume event request response在事件响应过程中都可以被使用 但是线程不安全 同时在调用了close以后 request response资源会被释放 可以通过对event对象做同步来保证线程安全的问题 当READ事件和END事件都发生的时候 首先会完成READ事件 然后再去完成END         具体的实现代码如下         public class SIPCometJBossServlet extends HttpServlet implements HttpEventServlet                @Override        public void event(HttpEvent event) throws IOException ServletException                switch (event getType())                //will be called at the beginning of the processing of the connection        case BEGIN:                event setTimeout( * ) //设置超时时间        //event suspend() //resume之前不必要一定使用suspend        new Handler(event) start()         break;                //Error will be called by the container in the case        //where an IO exception or a similar unrecoverable error occurs        case ERROR:                event close()         break;                //End may be called to end the processing of the request        case END:                //event close() //可以写也可以不写 因为进入这个方法也就是调用了close方法 起码暂时还不知道有其他什么入口        break;                //This indicates that input data is available         //and that at least one read call can be made without blocking        case READ:                break;                //The connection timed out according to the timeout value which has been set        // but the connection will not be closed unless the servlet uses the close method of the event        case TIMEOUT:                event close() //如果不主动关闭 Timeout方法会被循环调用 会话不会结束        break;                //The end of file of the input has been reached and no further data is available        case EOF:                event close()         break;                //Event will be called by the container after the resume() method is called         //during which any operation can be performed including closing the connection using the close() method         case EVENT:                event close() //作为resume方法调用后主动释放连接资源的一种手段        break;                //Write is sent if the servlet is using the isWriteReady method        case WRITE:                break;                                class Handler extends java lang Thread                private HttpEvent event;//event的生命周期已经不限制于事件处理方法 因此随时可以关闭请求处理        private HttpServletResponse response;        private HttpServletRequest request;        public Handler(HttpEvent event)                this event = event;        this response = event getHttpServletResponse()         this request = event getHttpServletRequest()                 @Override        public void run()                try                String id;        id = request getParameter( id )         if (id == null)        id = no id ;        Thread sleep( )         //危险!!!其实event response request都是线程不安全的 因此此时可能response已经被释放 需要同步住event的对象来操作 效率可能会降低        PrintWriter pw = response getWriter()         pw write(id)         pw flush()         event resume() //发送结束调用resume方法 进入event方法 结束请求处理        catch (Exception e)                e printStackTrace()                                         使用总结         对于Servlet描述的异步服务处理有了较好的支持 事件方法比较丰富 但是对于可定义事件支持不够完善 对象并发控制需要开发者自己设计 权衡多线程处理的高效以及资源争夺的消耗         下面对异步服务处理Servlet和普通Servlet做了一下简单的性能测试         首先我原本想用ab来做一下简单的压力测试即可 但是ab好像对于apr模式下的测试支持的不好 一压就报错(apr_poll: The timeout specified has expired ( )) 也可能是自己不会用吧 因此就自己写了一段测试代码来做测试         测试场景如下         两类Servlet都可以设置处理时Hold的时间 来达到消耗连接数的目的 测试客户端可以设置并发多少用户 每个用户发起多少次请求 下表就是测试的结果         这里设置的是Servlet都hold 秒钟 APR启动时配置的最大连接数为默认的 个         客户端设置 普通Servlet总耗时(ms) 异步Servlet总耗时(ms) 普通Servlet单个线程耗时(ms) 异步Servlet单个线程耗时(ms)        并发线程 每个线程执行 次请求         并发线程 每个线程执行 次请求         并发线程 每个线程执行 次请求         并发线程 每个线程执行 次请求 retrying request connect reject retrying request connect reject         从上表可以看出 就纯粹从处理效率来说 采用事件处理方式在线程切换过程中存在着一定的损失 但是就我们使用异步请求处理的本意来看 对于在高并发下对后端依赖无法避免的性能损耗情况下 异步请求解决了连接耗尽的问题         最后再来看我在测试过程中用JProfiler来截取的一些线程创建和使用状况         上图是最初的线程创建情况 还没有任何请求被发送到服务端 因此线程池也没有开任何一个连接         这是普通的Servlet在压力测试下的线程状况 线程就开到了 最大值 图中由于程序来Hold请求处理线程出现了红色阻塞和黄色等待 同时客户端已经开始出现拒绝连接的错误 下图就是错误的截图         上图是异步服务处理Servlet在压力测试开始的情况 可以发现它的线程还是 但是其他事件处理线程在不断增长 下图已经增长到了 多个线程 (这里需要注意的就是这种异步处理资源申请没有设置上限 因此对于资源消耗来说也是比较大的 同时要防范攻击性请求造成服务端垮掉)         结语        多线程 分布式计算 Erlang等这些编程方式 框架设计 语言其实都在实现这一个理论 那就是分而治之 多线程是站在单应用的角度去考虑解决方案 分布式计算是在多机协作考虑解决方案 Erlang在单机多处理器的角度去考虑解决方案 但彼此的理念都是一样 将能够分割的不相关联的独立任务并行处理 最终实现最优化的处理效果         对于服务集成平台是否采用这种技术 我自己还没有最终的决定 首先就如上面的测试结果来看 有得还是有失的 其次这种并发异步处理带来的多线程维护控制复杂度 也需要考虑到成本中 Jetty的开发者对于是否将异步服务处理Servlet来交由开发者控制而不是容器本身来控制表示出了反对意见 的确 这样复杂的控制交给开发者来处理会增加开发者的学习成本以及维护成本 cha138/Article/program/Java/hx/201311/26410

相关参考

知识大全 一种标记是否为AJAX异步请求的思路

一种标记是否为AJAX异步请求的思路  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  有时候对于同

知识大全 实现异步调用Web Service,防止页面超时

实现异步调用WebService,防止页面超时  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  普

知识大全 struts分发请求的过程与相关配置

    /_struts分发请求的过程与相关配置  按照mvc模式设计出的web层框架其实就是一个大大的servlet  我们可以在webxml文件中将符合某种特征所有请求交给这个Servlet处理 

知识大全 Asp.net中处理一个站点不同Web应用共享Session的问题

Asp.net中处理一个站点不同Web应用共享Session的问题  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一

何谓同步?何谓异步?异步电动机为什么得到广泛地应用?

  当转子的旋转速度与定子旋转磁场的旋转速度相同时,叫同步;不相同时叫异步。  因为异步电动机具有结构简单,价格低廉工作可靠,维修方便的优点,所以在发电厂和工农业生产中得到最广泛的应用。

何谓同步?何谓异步?异步电动机为什么得到广泛地应用?

  当转子的旋转速度与定子旋转磁场的旋转速度相同时,叫同步;不相同时叫异步。  因为异步电动机具有结构简单,价格低廉工作可靠,维修方便的优点,所以在发电厂和工农业生产中得到最广泛的应用。

三相异步电动机如何降压起动?

降压起动主要有热自藕降压起动和星三角降压起动。热自藕降压起动是指通过自藕变压器在起动时降低电机电压,同时降低起动电流。一般降低为额定电压的55%-75%左右。优点是可以通过改变自藕变压器的抽头圈数方便

三相异步电动机如何降压起动?

降压起动主要有热自藕降压起动和星三角降压起动。热自藕降压起动是指通过自藕变压器在起动时降低电机电压,同时降低起动电流。一般降低为额定电压的55%-75%左右。优点是可以通过改变自藕变压器的抽头圈数方便

知识大全 ASP.NET 2.0 中的异步页功能应用

ASP.NET2.0中的异步页功能应用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!ASPNET提

氟硝西泮的给药说明

氟硝西泮的给药说明1.本药有产生依赖性的可能,宜使用能控制症状的最低剂量做短程治疗。间歇用药可降低产生依赖性的风险。2.静脉注射宜缓慢,以免引起呼吸抑制和低血压。3.溶液配制:建议注射用的本药在注射前