四时宝库

程序员的知识宝库

Spring Boot和Micronaut之间的性能比较

Spring Boot和Micronaut之间的性能比较



今天,我们将比较用于在JVM上构建微服务的两个框架:Spring BootMicronaut。首先,Spring Boot当前是JVM世界中最流行,最受关注的框架。另一面是Micronaut,它也是流行的框架,特别是为构建无服务器功能或低内存占用的微服务而设计的。我们将比较Spring Boot的2.1.4版本和Micronaut的1.0.0.RC1版本。比较标准为:

· 内存使用情况(堆和非堆)

· 生成的JAR文件的大小(MB)

· 应用程序启动时间

· 应用程序的性能,即样本负载测试期间来自REST端点的平均响应时间

为了使我们的测试具有相关性,我们将收集两个几乎相同的应用程序的统计信息。当然,两者之间的唯一区别将是我们用于构建它的框架。我们的示例应用程序非常简单。它通过单个实体的内存CRUD操作公开了一些终结点。它还公开info和health端点,以及带有所有端点自动生成的文档的Swagger API。

示例应用程序性能将在JDK 11上进行测试。在启动后和负载测试期间,我们将使用Yourkit来分析和监视内存使用情况,在构建性能API测试时将使用Gatling。首先,让我们对示例应用程序进行简短概述。

源代码

我实现了非常简单的内存存储库bean,该存储库bean将新对象添加到列表中,并提供了find方法,用于通过add方法期间生成的id搜索对象。

public class PersonRepository {
 
    List<Person> persons = new ArrayList<>();
 
    public Person add(Person person) {
        person.setId(persons.size()+1);
        persons.add(person);
        return person;
    }
 
    public Person findById(Long id) {
        Optional<Person> person = persons.stream().filter(a -> a.getId().equals(id)).findFirst();
        if (person.isPresent())
            return person.get();
        else
            return null;
    }
 
    public List<Person> findAll() {
        return persons;
    }
 
}

仓库Bean被注入到控制器中。控制器公开了两个HTTP方法。其中第一个(POST)用于添加新对象,第二个(GET)用于按ID搜索对象。这是Spring Boot应用程序内部的控制器实现:

@RestController
@RequestMapping("/persons")
public class PersonsController {
 
    private static final Logger LOGGER = LoggerFactory.getLogger(PersonsController.class);
 
    @Autowired
    PersonRepository repository;
 
    @PostMapping
    public Person add(@RequestBody Person person) {
        LOGGER.info("Person add: {}", person);
        return repository.add(person);
    }
 
    @GetMapping("/{id}")
    public Person findById(@PathVariable("id") Long id) {
        LOGGER.info("Person find: id={}", id);
        return repository.findById(id);
    }
 
    @GetMapping
    public List<Person> findAll() {
        LOGGER.info("Person find");
        return repository.findAll();
    }
 
}

这是Micronaut的类似实现:

要实现REST端点,运行状况检查和Swagger API,我们需要包括一些依赖项。这是Spring Boot的依赖项列表:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.4.RELEASE</version>
</parent>
<groupId>pl.piomin.services</groupId>
<artifactId>sample-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
    <java.version>11</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
    </dependency>
</dependencies>
这是Micronaut所需的类似依赖项列表:
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-http-server-netty</artifactId>
</dependency>
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-inject</artifactId>
</dependency>
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-runtime</artifactId>
</dependency>
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-management</artifactId>
</dependency>
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-inject-java</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>io.swagger.core.v3</groupId>
    <artifactId>swagger-annotations</artifactId>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
    <scope>runtime</scope>
</dependency>

我还必须提供一些其他配置application.yml以启用Swagger和运行状况检查:

micronaut:
  router:
    static-resources:
      swagger:
        paths: classpath:META-INF/swagger
        mapping: /swagger/**
endpoints:
  info:
    enabled: true
    sensitive: false

开始测试

首先,让我们开始我们的应用程序。我为此使用Intellij。基于Spring Boot构建的示例应用程序的启动时间约为6-7秒。以下启动正好占用6.344

建立在Micronaut之上的类似应用程序的启动时间约为3-4秒。以下启动正好占用3.463,如下所示。但是,当我通过设置VM option在公司代理后面启动应用程序时,必须禁用环境扣除-Dmicronaut.cloud.platform=BARE_METAL。我认为两个应用程序的启动时间都还不错。

这是说明Spring Boot和Micronaut之间启动时间差异的图表。

build应用

我们还将检查应用程序JAR的大小。为此,您应该使用构建应用程序mvn clean install command。对于Spring Boot,我们使用了两个标准启动器:Web,Actuator和库Swagger SpringFox。因此,其中包含了50多个库。当然,我们可以做一些排除或不使用入门程序,但是我选择了构建应用程序的最简单方法。胖JAR的大小为24.2 MB。基于Micronaut的类似应用程序要小得多。胖JAR的大小为12.1 MB。我在中包含了更多库pom.xml,最后包含了37个库。Spring Boot在标准配置中包含更多的库,但另一方面,它比Micronaut具有更多的功能和自动配置。

以下图表说明了Spring Boot和Micronaut之间目标JAR大小的差异。

内存管理

刚启动后,Spring Boot应用程序已为堆分配305 MB,为非堆分配81 MB。我没有使用Xmx或任何其他选项设置任何内存限制。在堆中,旧一代消耗了8 MB,伊甸园空间消耗了60 MB,幸存者消耗了15 MB。大多数非堆都由元空间消耗-52 MB。运行性能负载测试后,堆分配增加到369 MB,非堆增加到87 MB。这是说明性能测试之前和期间的CPU和RAM使用情况的屏幕。

刚启动后,Micronaut应用程序已为堆分配254 MB,为非堆分配51 MB。我没有使用Xmx或任何其他选项设置任何内存限制-与Spring Boot应用程序相同。在堆中,旧一代消耗了2.5 MB,伊甸园空间消耗了20 MB,幸存者消耗了7 MB。大多数非堆空间都由元空间消耗-35 MB。运行性能负载测试后,堆分配没有更改,并且非堆增加到63 MB。这是说明性能测试之前和期间的CPU和RAM使用情况的屏幕。

这是刚启动后Spring Boot和Micronaut之间的堆内存使用情况比较。


性能测试

我将加特林(Gatling)用于构建性能负载测试。该工具允许您在Scala中创建测试方案。我们正在生成由20个线程同时发送的40k个样本请求。这是为POST方法实现的测试。

class SimpleTest extends Simulation {
 
  val scn = scenario("AddPerson").repeat(2000, "n") {
    exec(http("Persons-POST")
      .post("")
      .header("Content-Type", "application/json")
      .body(StringBody("""{"name":"Test${n}","gender":"MALE","age":100}"""))
      .check(status.is(200)))
  }
 
  setUp(scn.inject(atOnceUsers(20))).maxDuration(FiniteDuration.apply(10, TimeUnit.MINUTES))
 
}

这是为GET方法实现的测试。

class SimpleTest2 extends Simulation {
 
  val scn = scenario("GetPerson").repeat(2000, "n") {
    exec(http("Persons-GET")
      .get("${n}")
      .check(status.is(200)))
  }
 
  setUp(scn.inject(atOnceUsers(20))).maxDuration(FiniteDuration.apply(10, TimeUnit.MINUTES))
 
}

POST /persons方法的性能测试结果如下图所示。一秒钟内处理的平均请求数为1176

以下屏幕显示了随时间变化的响应时间百分比的直方图。

GET /persons/{id}方法的性能测试结果如下图所示。一秒钟内处理的平均请求数为1428

以下屏幕显示了随时间变化的响应时间百分比的直方图。

现在,我们正在为Micronaut应用程序运行相同的加特林负载测试。POST /persons方法的性能测试结果如下图所示。一秒钟内处理的平均请求数为1290

以下屏幕显示了随时间变化的响应时间百分比的直方图。

GET /persons/{id}方法的性能测试结果如下图所示。一秒钟内处理的平均请求数为1538

以下屏幕显示了随时间变化的响应时间百分比的直方图。

Spring Boot和Micronaut之间的处理时间没有太大差异。时间上的微小差异可能与框架无关,而与基础服务器有关。默认情况下,Spring Boot使用Tomcat,而Micronaut使用Netty。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接