容易被忽视的后端服务 chunked 性能问题

容易被忽视的后端服务 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:chunkedTransfer-Encoding:chunkedHTTP 协议里的意思是无法计算 Content-Length 长度,需要分块传输。

这是 spring mvc 的默认 complex object 传输方式,如果我们返回的是一个简单的对象就不会有这个问题。

Transfer-Encoding:chunked 带来的性能问题就是访问一次数据需要不止一次的 http 请求,而一次 http 请求的成本也是比较大的。

(我没有通过抓包工具来测试具体哪种对象大小需要访问几次,感兴趣的可以自己试下。)

集成 JAX-RS 规范框架 Jersey

解决这个问题两个层面都可以,一种是采用比较粗暴的方式在 servlet 容器层面解决,但是这个会带来一个后果就是当我们计算 complex object 大小的时候会比较复杂而且容易出错,也会影响项目未来的分块传输功能,效果不太好。

还有一种就是在应用层面解决,比较柔性也易于扩展,我们可以集成一个 rest 框架,最好是符合 JAX-RS 规范,本文我们集成 Jersey 框架。

jersey 集成如果通过 [email protected]__ 方式那么 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 mvcjersey rest 共同存在的问题,我们也不需要将所有的返回 chunked 的接口都改成 JAX-RSrest 服务,只需要将有性能瓶颈的接口改造下即可。

时间: 2024-10-16 00:55:08

容易被忽视的后端服务 chunked 性能问题的相关文章

后端服务性能压测实践

转自:https://mp.weixin.qq.com/s/XW9geHZ9odHdI7srDiKBIg 目录 背景 环境检测 压力机及压力工具检测 Linux openfiles limit 设置 排查周边依赖 空接口压测检测 聚合报告中 throughput 计算 压测及性能排查方法 关注各纬度 log Linux 常规命令 性能排查两种方式(从上往下.从下往上) 总结 背景 最近大半年内有过两次负责性能压测的一些工作.一件事情做了一次可能还无法总结出一些东西,两次过后还是能发现一些共性问题

(转)后端服务性能压测实践

作者:王清培(Plen wang) 传送门:https://www.cnblogs.com/wangiqngpei557/p/7953453.html ---------------------------------------------------------------------分割线------------------------------------------------------ 入职新公司,没人理我,负责的需求开发一直很忙,要么环境有问题,要么Bug卡住我找开发,回了一句

后端服务性能优化实战篇

本文简单介绍下后端服务开发中常用的一些性能优化策略. 1.代码 优化代码实现是第一位的,特别是一些不合理的复杂实现.如果结合需求能从代码实现的角度,使用更高效的算法或方案实现,进而解决问题,那是最简单有效的. 2.数据库 数据库的优化,总体上有3个方面: 1)  SQL调优:除了掌握SQL基本的优化手段,使用慢日志定位到具体问题SQL,使用explain.profile等工具来逐步调优. 2)  连接池调优:选择高效适用的连接池,结合当前使用连接池的原理.具体的连接池监控数据和当前的业务量作一个

PHPer都应该关注的服务端性能问题--听云Server试用笔记

很早就在用国外的NewRelic(http://www.newrelic.com/)的APM产品来监测自己网站的PHP应用性能了.无奈国外的服务从国内访问起来实在是太慢了,虽然New Relic已经上市了,但是这访问慢的问题却是一直没见好转,反而越来越严重.可能是GFW时不时抽风所致,有时候还得翻墙才能访问New Relic的报表.虽说翻墙是码农们必备的技能,但是为了看个报表查个故障都要翻墙的话实在太麻烦了.   最近非常意外地发现国内也有提供和New Relic类似服务的厂商了.听云(http

maven+SpringMVC搭建RESTful后端服务框架

今天来尝试一下搭建基于SpringMVC的RESTful标准的后端服务. 首先,什么是MVC?M-model,模型,指业务数据层,具体一点就是业务逻辑与数据库的交互:V-view,视图,用来展示数据,传统SpringMVC中控制器有返回类型ModelAndView,即返回含有数据模型与页面视图的jsp文件:C-controller,控制器,通常负责处理与用户间的交互,控制从数据库取数与返回结果到用户等. 那么,什么是REST风格的服务呢?REST(Representational State T

Jersey后端服务接收ajax前端的图片上传

近期的项目里需要在前端上传图片后端接收处理.前端JSP页面使用Ajax上传图片后端使用Jersey框架提供restful接口接收处理图片. 一.前端的处理 jsp页面中图片上传没有使用form表单而是直接使用file类型的input控件 <input type="file" name="file" class="inpTxtA" value="" id="appLogo"/> <input

Apple使用Apache Mesos重建Siri后端服务

苹果公司宣布,将使用开源的集群管理软件Apache Mesos,作为该公司广受欢迎的.基于iOS的智能个人助理软件Siri的后端服务.Mesosphere的博客指出,苹果已经创建了一个命名为J.A.R.V.I.S.,类似PaaS的专有调度Framework,由此,开发者可以部署可伸缩和高可用的的Siri服务. 集群管理软件Apache Mesos将CPU.内存.存储介质以及其它计算机资源从物理机或者虚拟机中抽象出来,构建支持容错和弹性的分布式系统,并提供高效的运行能力.Mesos使用与Linux

iOS开发者必备:四款后端服务工具

本文转载至 http://mobile.51cto.com/iphone-411917.htm 对于开发者来说,连接后端数据或许是一件特别痛苦的事情.但后端服务却能够帮助开发人员以更快的速度构建移动应用程序而不牺牲后端功能. AD:2014WOT全球软件技术峰会北京站 课程视频发布 后端服务加速了移动应用的开发,改进了可扩展性并减少了开发者对服务器端编码的需求.对于开发者来说,连接后端数据到前端或许是一件特别痛苦的事情.但后端服务却能够帮助开发者以更快的速度构建移动应用,不仅如此,它还能减少着移

利用tengine的nginx_upstream_check_module来检测后端服务状态

nginx_upstream_check_module 是专门提供负载均衡器内节点的健康检查的外部模块,由淘宝的姚伟斌大神开发,通过它可以用来检测后端 realserver 的健康状态.如果后端 realserver 不可用,则后面的请求就不会转发到该节点上,并持续检查几点的状态.在淘宝自己的 tengine 上是自带了该模块.项目地址:https://github.com/yaoweibin/nginx_upstream_check_module 参考文档:https://www.cnblog