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 服務,只需要將有效能瓶頸的介面改造下即可。
本文轉自 王清培 51CTO部落格,原文連結:http://blog.51cto.com/wangqingpei557/2044336,如需轉載請自行聯絡原作者
相關文章
- 被忽視的開發安全問題
- 那些容易被忽視的 JavaScript 細節總結JavaScript
- 專案開發中容易被忽視的部分
- 杜絕安全隱患 容易忽視的Oracle安全問題(轉)Oracle
- Beego 中容易被我們忽視的問題之 Memory 快取篇Go快取
- sql 一個說起來都知道,工作中容易忽視的問題SQL
- Web開發和設計上容易被忽視的8個錯誤Web
- 工業服務被忽視的銷售力量:他們的技術人員
- 三星手機問題根源:忽視軟體服務不再重視創新
- Android效能優化之被忽視的優化點Android優化
- 教你使用rest雲服務介面,自己完成前後端開發REST後端
- SAS服務效能問題專案
- 安卓效能優化之被忽視的記憶體洩露安卓優化記憶體洩露
- Pandas切片操作:很容易忽視的SettingWithCopyWarning
- 使用多執行緒提高rest服務效能執行緒REST
- MySQL 你可能忽視的選擇問題MySql
- Rest Post示例(java服務端、python客戶端)RESTJava服務端Python客戶端
- Android 效能優化之被忽視的記憶體洩漏Android優化記憶體
- spring 的遠端服務是?Spring
- 建立 UIWindow 被忽視的一個坑UI
- 我在開發中常忽視的安全問題
- 解碼Redis最易被忽視的CPU和記憶體佔用高問題Redis記憶體
- 虛擬機器中的活動目錄:可能被忽視很久的問題和答案(1)虛擬機
- 容易忽視的十大SQL最佳化方案!SQL
- Spring Boot 參考指南(使用RestTemplate呼叫REST服務)Spring BootREST
- dubbox rest服務REST
- 不可忽視的前端安全問題——XSS攻擊前端
- 一點被忽視的模型使用方法模型
- 使用SpringBoot構建REST服務-什麼是REST服務Spring BootREST
- Spring Cloud(三) 服務提供者 Eureka + 服務消費者(rest + Ribbon)SpringCloudREST
- SpringCloud 實戰:禁止直接訪問後端服務SpringGCCloud後端
- 全球50家知名企業原始碼批次外洩,只因一個問題被忽視?原始碼
- 遠端服務不能啟動問題的解決方法
- 那些年,我們見過的 Java 服務端“問題”Java服務端
- 服務端經典的C10k問題(譯)服務端
- 從服務端視角看高併發難題服務端
- Java後端微服務架構下的服務依賴注入:Spring Cloud ContextJava後端微服務架構依賴注入SpringCloudContext
- 高效能服務端漫談服務端