spring rest 容易被忽视的后端服务 chunked 性能问题
spring boot 容易被忽视的后端服务 chunked 性能问题
标签(空格分隔): springboot springmvc chunked
- 背景
- spring boot 创建的默认 spring mvc 项目
- 集成 JAX-RS 规范框架 Jersey
背景
在之前的一次性能压测的时候我们发现一个细节问题,我们使用 spring boot 创建的 web rest 项目,使用默认 spring mvc 作为 web rest 框架。
这在使用上没有太大问题,但是有一个影响性能的细节问题被发现了,说实话这个问题很难被发现。
spring boot 创建的默认 spring mvc 项目
我们来看一个简单的 demo,我使用 IDEA 创建一个 spring boot 项目,创建过程中没有什么特别的选项需要调整,一路 next 。然后我们创建一个简单的 controller 。
package springboot.demo.controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import springboot.demo.model.User; /** * Created by plen on 2017/11/25. */ @RestController public class SpringMvcController { @RequestMapping("/user/{id}") public User hello(@PathVariable Long id) { User user = new User(); user.setID(id); user.setUserName("mvc."); return user; } }
再创建一个简单的 model 。
package springboot.demo.model; import lombok.Data; import lombok.EqualsAndHashCode; /** * Created by plen on 2017/11/25. */ @Data @EqualsAndHashCode public class User { private Long ID; private String userName; }
然后启动访问这个 controller ,注意看下返回的 http 信息里多了一个 Transfer-Encoding:chunked 。Transfer-Encoding:chunked 在 HTTP 协议里的意思是无法计算 Content-Length 长度,需要分块传输。
这是 spring mvc 的默认 complex object 传输方式,如果我们返回的是一个简单的对象就不会有这个问题。
Transfer-Encoding:chunked 带来的性能问题就是访问一次数据在 http层面看确实是一次 http 请求,而通过 tcp 抓包工具查看会发现多了一次 tcp 传输。
集成 JAX-RS 规范框架 Jersey
解决这个问题两个层面都可以,一种是采用比较粗暴的方式在 servlet 容器层面解决,但是这个会带来一个后果就是当我们计算 complex object 大小的时候会比较复杂而且容易出错,也会影响项目未来的分块传输功能,效果不太好。
还有一种就是在应用层面解决,比较柔性也易于扩展,我们可以集成一个 rest 框架,最好是符合 JAX-RS 规范,本文我们集成 Jersey 框架。
jersey 集成如果通过 @Component 方式那么 jersey 会默认接管所有的 web servlet 请求处理,所以就需要我们手动的配置专门用来处理 jersey servlet 的容器。
spring boot 解决了以前 spring 繁重的配置,提供了 auto config 功能,原来通过 web.xml 配置 servlet 的,现在需要用代码来配置。spring boot 提供了让我们手动注册 servlet bean 的方式。
org.springframework.boot.web.servlet.ServletRegistrationBean
ServletRegistrationBean 可以让我们注册servlet,我们来看下完整代码。
package springboot.demo.config; import org.glassfish.jersey.servlet.ServletContainer; import org.glassfish.jersey.servlet.ServletProperties; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * Created by plen on 2017/11/25. */ @Component public class JerseyServletBeanConfig { @Bean public ServletRegistrationBean jerseyServlet() { ServletRegistrationBean registrationBean = new ServletRegistrationBean(new ServletContainer(), "/rest/v1/*"); registrationBean.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, JerseyResourceConfig.class.getName()); return registrationBean; } }
这和原来在 web.xml 配置的是一样的,设置 routing 地址,设置 Init 初始化参数,对应的 servlet class name 。
所有的 "rest/v1/*" 请求都将被 ServletContainer jersey servlet 容器接管。
package springboot.demo.config; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.spring.scope.RequestContextFilter; import springboot.demo.controller.JerseyController; /** * Created by plen on 2017/11/25. */ public class JerseyResourceConfig extends ResourceConfig { public JerseyResourceConfig() { register(JerseyController.class); register(RequestContextFilter.class); } }
ResourceConfig 其实是一个 jersey Application 类型。这是 jersey 注册 servlet__ 时规定的。
package springboot.demo.controller; import springboot.demo.model.User; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; /** * Created by plen on 2017/11/25. */ @Path("/user/") public class JerseyController { @Path("{id}") @GET @Produces(MediaType.APPLICATION_JSON) public User hello(@PathParam("id") Long id) { User user = new User(); user.setID(id); user.setUserName("jersey."); return user; } }
这是我们应用代码 Controller ,使用 JAX-RS 规范的注解进行设置即可。
这样就解决了 sprng mvc 和 jersey rest 共同存在的问题,我们也不需要将所有的返回 chunked 的接口都改成 JAX-RS 的 rest 服务,只需要将有性能瓶颈的接口改造下即可。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
企业实战(3)-主从实现基于Keepalived高可用集群网站架构
企业实战:逐步实现企业各种情景下的需求 企业情景三:网站的访问量越来越大,网站访问量已经从原来的1000QPS,变为3000QPS,目前业务已经通过集群LVS架构可做到随时拓展,后端节点已经通过集群技术保障了可用性,但对于前端负载均衡器来说,是个比较大的安全隐患,因为当前端负载均衡器出现故障时,整个集群就处于瘫痪状态,因此,负载均衡器的可用性也显得至关重要,那么怎么来解决负载均衡器的可用性问题呢? 项目三:主从实现基于Keepalived高可用集群网站架构 实现keepalived企业级高可用基于LVS-DR模式的应用实战: 一、环境准备:两台centos系统做DR、一主一从,两台实现过基于LNMP的电子商务网站 二、安装步骤:1、两台服务器都使用yum 方式安装keepalived服务2、iptables -F && setenforing 清空防火墙策略,关闭selinux 实现前分配各个角色 机器名称 IP配置 服务角色 备注 lvs-server-master VIP:172.17.252.110 DIP:172.17.250.223 主负载均衡器 开启路由功能...
- 下一篇
Docker镜像的内部结构(四)
一、base镜像 base 镜像简单来说就是不依赖其他任何镜像,完全从0开始建起,其他镜像都是建立在他的之上,可以比喻为大楼的地基,docker镜像的鼻祖。 base 镜像有两层含义:(1)不依赖其他镜像,从 scratch 构建;(2)其他镜像可以之为基础进行扩展。 所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。 我们以 CentOS 为例查看 base 镜像包含哪些内容。 下载及查看镜像: root@ubuntu:~# docker pull centos Using default tag: latest latest: Pulling from library/centos d9aaf4d82f24: Pull complete Digest: sha256:4565fe2dd7f4770e825d4bd9c761a81b26e49cc9e3c9631c58cfc3188be9505a Status: Downloaded newer image for centos:latest ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Mario游戏-低调大师作品
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2整合Thymeleaf,官方推荐html解决方案