Springboot 性能优化(亲测)——SpringBoot学习
SpringBoot 是一个快速开发框架,能够快速的整合第三方框架,简化XML配置,全部采用注解形式,内置Tomcat容器,帮助开发者能够实现快速开发,SpringBoot的Web组件 默认集成的是SpringMVC框架。 尽管 SpringBoot 拥有这么多的优点,但也存在性能问题,这并不和它拥有如此多的优点相冲突,应用程序性能只有更优,没有最优。 对于 SpringBoot 性能..
SpringBoot 是一个快速开发框架,能够快速的整合第三方框架,简化XML配置,全部采用注解形式,内置Tomcat容器,帮助开发者能够实现快速开发,SpringBoot的Web组件 默认集成的是SpringMVC框架。
尽管 SpringBoot 拥有这么多的优点,但也存在性能问题,这并不和它拥有如此多的优点相冲突,应用程序性能只有更优,没有最优。
对于 SpringBoot 性能优化可以从注解 @SpringBootApplication
上优化,Servlet 容器上优化, JVM 上优化等等。我们分别从这三方面进行优化。
测试机器信息:
OS :Windows 10 专业版
CPU :Intel® Core™ i5-3230M @2.6GHz
RAM :8 GB
ROM :120G SSD + 500G HDD
JDK :Java version “1.8.0_171”
Eclipse :Eclipse Java EE IDE for Web Developers 4.7.3a
MySQL :MySQL Version 5.6.15
一、优化注解 @SpringBootApplication
@SpringBootApplication
是Springboot 整合的一个复合注解,作用相当于 @Configuration
+ @EnableAutoConfiguration
+ @ComponentScan
,这个可以查看 @SpringBootApplication
源码得知,其中有一句 This is a convenience annotation that is equivalent to declaring {@code @Configuration},{@code @EnableAutoConfiguration} and {@code @ComponentScan}
说的就是这个意思。
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;
/**
* Indicates a {@link Configuration configuration} class that declares one or more
* {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration
* auto-configuration} and {@link ComponentScan component scanning}. This is a convenience
* annotation that is equivalent to declaring {@code @Configuration},
* {@code @EnableAutoConfiguration} and {@code @ComponentScan}.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 1.2.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
/**
* Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
* for a type-safe alternative to String-based package names.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
/**
* Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
* scan for annotated components. The package of each class specified will be scanned.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return base packages to scan
* @since 1.3.0
*/
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
}
由于其中包括有包扫描的注解 @ComponentScan
,这会导致项目启动时间变长(启动一个大的应用程序或做大量的集成测试启动应用程序时,影响会特别明显),会加载一些多余的实例(Beans),也会增加 CPU 消耗。
所以可以将 @SpringBootApplication
注解改为 @EnableAutoConfiguration
+ @Configuration
+ 在我们需要的 bean 上进行显式配置注解。
通过实际使用 @SpringBootApplication
注解 和 使用 @EnableAutoConfiguration
+ @Configuration
注解分别各测试启动 5 次 记录实际启动时间,最后取 5 次的平均时间来比较性能的变化,JVM 各参数默认,测试的详细数据见下。
测试项目 | 使用 @SpringBootApplication 注解 | 使用 @EnableAutoConfiguration + @Configuration 注解 |
---|---|---|
第一次测试耗时 | 19.742s/20.867s | 18.160s/19.291s |
第二次测试耗时 | 19.407s/20.563s | 18.388s/19.496s |
第三次测试耗时 | 21.734s/22.903 | 18.308s/19.721s |
第四次测试耗时 | 19.908s/21.090s | 18.576s/19.708s |
第五次测试耗时 | 19.456s/20.650s | 18.418s/19.699s |
平均耗时 | 20.049s/21.215s | 18.370s/19.583s |
表格说明:此表基于上述环境测试的真实值,平均耗时取有效小数5位。19.742s/20.867s :表示 应用启动耗时19.742秒,JVM启动耗时20.867秒。
通过上述测试数据发现使用 @EnableAutoConfiguration + @Configuration 注解 可以提高应用程序启动的性能。
二、将 Servlet 容器由 Tomcat 变成 Undertow
默认情况下 Spring Boot 使用 Tomcat 来作为内嵌的 Servlet 容器,我们可以将 Web 服务器切换到 Undertow 来提高应用性能。Undertow 是一个采用 Java 开发的灵活的高性能 Web 服务器,提供包括阻塞和基于 NIO 的非堵塞机制。接下来我们使用 Jmeter
分别测试使用 Tomcat 容器 和 Undertow 容器在同一个查询数据库信息的接口下的各自的并发量。设置 JVM 参数:-server -XX:+PrintGCDetails -Xms2048m -Xmx2048m
,测试数据如下。
测试项目 | Tomcat 容器 | Undertow 容器 |
---|---|---|
第一次吞吐量测试 | 315.3/sec | 395.0/sec |
第二次吞吐量测试 | 421.6/sec | 453.2/sec |
第三次吞吐量测试 | 327.8/sec | 448.8/sec |
第四次吞吐量测试 | 351.4/sec | 340.0/sec |
第五次吞吐量测试 | 431.1/sec | 433.2/sec |
平均吞吐量 | 369.44/sec | 414.04/sec |
表格说明:此表基于上述环境测试的真实值,平均吞吐量取有效小数5位。
由上表数据可以看出将 Tomcat 容器换为 Undertow 容器将会提高应用性能。
三、JVM 调优
关于 JVM 调优需要了解服务器基本参数配置,JVM 基本组成结构,垃圾回收算法,垃圾回收机制,JVM 调优工具,调优经验等等等,这里不详细列举。
这里就以 JVM 参数 -server -XX:+PrintGCDetails -Xms512m -Xmx512m
和 -server -XX:+PrintGCDetails -Xms2048m -Xmx2048m
为例,还是测试吞吐量,对于参数 -server -XX:+PrintGCDetails -Xms2048m -Xmx2048m
的数据从Tomcat 容器下吞吐量的测试得来,就不做重复测试了,然后测试参数 -server -XX:+PrintGCDetails -Xms512m -Xmx512m
在 Tomcat 容器下的吞吐量,测试数据见下表。
测试项目 | Tomcat 512M | Tomcat 2048M |
---|---|---|
第一次吞吐量测试 | 300.5/sec | 315.3/sec |
第二次吞吐量测试 | 293.5/sec | 421.6/sec |
第三次吞吐量测试 | 282.6/sec | 327.8/sec |
第四次吞吐量测试 | 302.8/sec | 351.4/sec |
第五次吞吐量测试 | 309.5/sec | 431.1/sec |
平均吞吐量 | 297.78/sec | 369.44/sec |
表格说明:此表基于上述环境测试的真实值,平均吞吐量取有效小数5位。
数据说明JVM 参数 `-server -XX:+PrintGCDetails -Xms2048m -Xmx2048m` 比 `-server -XX:+PrintGCDetails -Xms512m -Xmx512m` 要优。进行 JVM 调优是一个谨慎细致的过程,需要慢慢的试,直到当前最优为止。
更多推荐
所有评论(0)