AMQ在Servlet3.0下出现的问题
来源:互联网 发布:红色警戒3起义时刻mac 编辑:程序博客网 时间:2024/05/16 23:40
问题一:http status 500
描述:
在项目切换tomcat7的时候,原来通过使用amq实现的消息推送出现了问题,amq.js发送的大部分请求都是500,只有少部分才是200。
分析:
在Servlet2.5容器下, servlet组件默认支持异步通信, 但是到Servlet3.0的时候需要手动进行开启支持。经过排查发现, 配置参数[async-supported]来开启这个异步支持。
解决:
1.刚开始只在amq的后端Servlet组件[AjaxServlet]中配置,发现依然会出现500错误。原来只要请求经过的Filter、Servlet都需要增加配置才行。
2.简单粗暴点:在web.xml中所有Filter、Servlet都增加[async-supported]支持。或者找到该请求的过滤器链,增加相应的也行【比较麻烦】
<servlet><servlet-name>AjaxServlet</servlet-name><servlet-class>org.apache.activemq.web.AjaxServlet</servlet-class><load-on-startup>1</load-on-startup><async-supported>true</async-supported></servlet>
问题二:Amq请求超时
描述:
在解决了第一个问题后,实际使用中又出现了amq【版本5.8.0】请求经常会超时,js报错【Serverconnection dropped.】导致后台推送的消息不能实时更新,但偶尔又很正常。
分析:
看到问题后的第一反应会不会是Apache的请求超时时间太短造成的,但是查看Apache的timeout参数及amq的超时参数,明显前者大于后者。按理说请求不至于达到Apache的超时时间而被拒绝。带着这个问题,先看下amq的前端组件的实现,发现它是在请求之前先建立,如下代码所示:
var sendPoll = function(reCon) {if (reCon) {reConnect = reCon;}// Workaround IE6 bug where it caches the response// Generate a unique query string with date and randomvar now = new Date();var timeoutArg = sessionInitialized ? timeout : 0.001;var data = 'timeout=' + timeoutArg * 1000 + '&d=' + now.getTime() + '&r=' + Math.random();var successCallback = sessionInitialized ? pollHandler : initHandler;var options = { method: 'get',data: addClientId( data ),success: successCallback,error: pollErrorHandler};adapter.ajax(uri, options);};通过调试工具拦截请求发现,参数timeout的值都是1,这就说明初次建立连接就是失败,后面的请求更不用说了。
这个时候我们需要看一下AjaxServlet的实现,这里先说一个Continuation机制,它是建立在NIO基础上,允许被"suspend"(挂起)和"rsueme"(继续、恢复)。在suspend之前一般需要设置timeout来设置阻塞时间, 同时“Continuation”对象会提供对应的监听对象来处理事件是否“超时”或者“完成”。而在Servlet3.0的环境下,MessageServletSupport中的Continuation使用的是Servlet3Continuation,而这个Continuation只有addContinuationListener方法会设置超时,我们可以看下代码:
代码2.1:MessageServletSupport中的doMessages方法
if (message == null && client.getListener().getUndeliveredMessages().size() == 0) { Continuation continuation = ContinuationSupport.getContinuation(request); if (continuation.isExpired()) { response.setStatus(HttpServletResponse.SC_OK); StringWriter swriter = new StringWriter(); PrintWriter writer = new PrintWriter(swriter); writer.println("<ajax-response>"); writer.print("</ajax-response>"); writer.flush(); String m = swriter.toString(); response.getWriter().println(m); return; } continuation.setTimeout(timeout); continuation.suspend(); LOG.debug( "Suspending continuation " + continuation ); // Fetch the listeners AjaxListener listener = client.getListener(); listener.access(); // register this continuation with our listener. listener.setContinuation(continuation); return; }这里当没有消息时,并不会调用Servlet3Continuation的设置超时方法,也就是无法从“suspend”状态恢复。导致请求一直闲置到Apache的请求超时时间, 同时造成amq客户端无法完成初始化标识。
从中可以看出amq客户端的初始化只不过是发出一个请求, 设置一个超级短的时间, 但后台的流程跟正常的实时信息获取一致。 这就可以解释一个现象: 如果刚初始化的时候,ActiveMq对应的队列刚好有对应信息, 则会正确返回初始化标志被正确设置。 但是随后如果无法获取到队列数据, 则一直处于等待直到apache拒绝。
通过上述的排查发现, 我们有理由怀疑是不是当前ActiveMq组件包的“Continuation”实现有问题。
解决:
通过查找资料,发现这个是amq的一个AMQ-3447,该bug在5.9.0中修复,所以升级MQ版本即可。在5.9.0的MessageServletSupport中的doMessages方法中我们可以看下代码:if (message == null && client.getListener().getUndeliveredMessages().size() == 0) { Continuation continuation = ContinuationSupport.getContinuation(request); // Add a listener to the continuation to make sure it actually // will expire (seems like a bug in Jetty Servlet 3 continuations, // see https://issues.apache.org/jira/browse/AMQ-3447 continuation.addContinuationListener(new ContinuationListener() { @Override public void onTimeout(Continuation cont) { if (LOG.isDebugEnabled()) { LOG.debug("Continuation " + cont.toString() + " expired."); } } @Override public void onComplete(Continuation cont) { if (LOG.isDebugEnabled()) { LOG.debug("Continuation " + cont.toString() + " completed."); } } }); if (continuation.isExpired()) { response.setStatus(HttpServletResponse.SC_OK); StringWriter swriter = new StringWriter(); PrintWriter writer = new PrintWriter(swriter); writer.println("<ajax-response>"); writer.print("</ajax-response>"); writer.flush(); String m = swriter.toString(); response.getWriter().println(m); return; } continuation.setTimeout(timeout); continuation.suspend(); LOG.debug( "Suspending continuation " + continuation ); // Fetch the listeners AjaxListener listener = client.getListener(); listener.access(); // register this continuation with our listener. listener.setContinuation(continuation); return; }这里通过设置ContinuationListener来保证当超时或者完成时能够返回给前台一个空的Ajax报文,不至于出现超时情况。
阅读全文
0 0
- AMQ在Servlet3.0下出现的问题
- servlet3.0下监听器的使用
- Servlet3.0的创建 &tomcat63342的问题
- Servlet3的问题
- Servlet3.0的特性
- AMQ
- Servlet3.0包依赖问题
- 关于servlet3.0中配置@WebInitParam的问题
- oracle在linux下的安装出现的小问题
- 解决:AMQ应用部署到weblogic服务器上出现“找不到匹配的方法setLifo"
- Servlet3异步asyncContext在IE(789)/chrome/ff下的差别表现(1)
- 在Solaris下编译socket出现的问题
- codeMatic 在win7 下出现的签名问题
- FCKeditor在ASP.NET下出现的问题及解决方案
- 在carbite c++下项目编译出现的问题
- 在Ubuntu下安装飞鸽传输出现的问题。
- 在命令提示符下导入包出现的问题
- java程序在linux下出现的乱码问题
- java操作sqlite
- SQLClr 切分中英文
- HTTP 协议详解
- 高效学习办公
- STL的string的基本操作
- AMQ在Servlet3.0下出现的问题
- 美团codeM资格赛 数码
- IP高精度街道级定位问题研究
- AirSim- 相关软件安装及创建新的unreal工程
- Field 'id' doesn't have a default value
- spring
- java获取资源库下面配置文件的地址
- citusdb数据库的使用
- 数据库 表的连接操作