Restlet:怪异的HTTP Status = 200 但是 Content-Length=0

上周五遇到一个很怪异的问题,实习生在做网站性能测试的时候,通过JMeter往服务器发送大量并发请求的时候,不管是post和get,有部分请求的返回的结果status code是200, 但是content-length却是0。非并发请求(顺序请求)的时候一切都正常。问题的分析思路以及解决方案如下所述。

  1. 通过抓包分析,断定这个现象跟客户端JMeter没有任何关系,完全是由服务端引起的。
  2. 通过分析Nginx的日志,断定Nginx每次都做了正常的request/response转发,断定问题是由Tomcat里面的应用程序引起的。
  3. 最先被怀疑的是Restlet框架有类似于“maxConnection”这样的参数,应用程序没有配置但默认值偏小而引起的。通过阅读源代码发现在org.restlet.engine.connector.ConnectionHelper中果然存在这些配置,但是默认值都还合理,初始连接池大小就是100,请见下图,这个原因也被排除了。ConnectionHelper
  4. 回想这个网站的架构,对外的接口是通过Spring+Restlet搭建起来的。具体的功能接口是基于Restlet的ServerResource来写的,Spring提供的扩展SpringBeanRouter负责将HttpRequest根据url pattern匹配到不同的ServerResource类,每一次请求过来,由Spring 容器负责初始化一个具体对象来handle这个request。仔细看看这些ServerResource的配置,发觉每个bean的配置并没有设置scope。这个时候就大致知道问题的原因了,Spring对bean的管理,如果不显式的配置scope=”prototype”,则默认是singleton模式的。这样会导致Spring容器对每个ServerResource的类总是缓存一个instance,那样每次request到达的时候,都是由这同一个instance来服务。这样就会导致并发请求的时候,总是只有少数几次请求总是成功,其他的请求会“伪成功”。   <bean name=”/noti/to/{toId}/unread” id=”countUnRead” autowire=”byName”  class=”net.*.*.restlet.CountUnReadNotiResource” scope=”prototype”/>
  5. 加上scope设置以后,应用程序在单个tomcat里面顺利抗住500个并发没有任何问题。事实上在org.restlet.ext.spring.SpringBeanRouter的javadoc上已经实例需要配置这个scope属性,只是当时在demo阶段没有仔细留意。

PS:选择Restlet当作REST API的开发框架挺好的,它与具体应用程序之间的关系就像Nginx和tomcat之间的关系一样,restlet能非常方便的做接口封装、分发,在后端有多个应用程序的环境下用起来非常方便。只是目前有一些已知的坑需要注意一下,比如不能用它自带的ClientResource来发起client http request(最好用Apache commons下面的HttpClient来做),因为它不能做到在每次请求结束以后顺利的关闭连接、释放资源,容易引起操作系统“最大打开文件数”的问题。

发表评论?

0 条评论。

发表评论


注意 - 你可以用以下 HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>