My teammates are developing a REST API using Spring Boot + PostgreSQL + Redis + Kafka, etc., while I'm making a monitoring tool using Prometheus, Grafana, and so on, to monitor that API.
This API provides four endpoints. Let's call them A,B,C and D.
I wanted to collect metrices of "approximate response time of each API endpoint". So I wrote simple scripts(Bash and Perl) that measure elapsed time taken to call each endpoint using curl. And then I registered the scripts using crontab to execute them once every minutes.
# get response time
curl -XGET -s -w "\\n%{http_code}\\n%{time_total}\\n" "http://for.example/A" | tail -n 1 >> log_A
curl -XGET -s -w "\\n%{http_code}\\n%{time_total}\\n" "http://for.example/B" | tail -n 1 >> log_B
...
The result is, as you see below, somewhat strange:
It took about 100ms to call one endpoint and took just a few milliseconds to call the others.
I looked into it and found that the first call of each cron job took much longer. That is, if I measured A,B,C,then D, A took 100ms. If I measured B,C,D, then A, B took 100ms. Next three endpoints response very soon. In the figure, I modified the sequence and I could see it affected the result immediately.
I am suspecting connection between Spring boot application and database(or redis, or kafka?) is disconnected due to expiration, so it takes time to reconnect first. But I think one minute is too short for any configuration to expire any connection. Anyway, from what point do I have to start?
Any advice would be appreciated.
Edit:
After writing this post, I launched a very simple Spring Boot REST API app, whose code came from Spring boot guide doc( https://spring.io/guides/gs/rest-service ), not using DB nor any external things. It takes only 4ms to curl this API always. So I suspect the external things more.
If you need to see configurations about Spring boot application. Here is pom.xml and application.yaml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.company</groupId>
<artifactId>sylphid</artifactId>
<version>0.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>personal</artifactId>
<version>0.3.0</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- kafka -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>${spring-kafka.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-spi -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-spi</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-spring-web -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-spring-web</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
</resources>
<finalName>personal</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.21.0</version>
<configuration>
<images>
<image>
<name>sylphid/${project.build.finalName}</name>
<build>
<from>openjdk:8u162-jdk</from>
<entryPoint>java -Dspring.profiles.active=docker -jar /application/${project.build.finalName}.jar</entryPoint>
<assembly>
<basedir>/application</basedir>
<descriptorRef>artifact</descriptorRef>
<inline>
<id>assembly</id>
<files>
<file>
<source>target/${project.build.finalName}.jar</source>
</file>
</files>
</inline>
</assembly>
<tags>
<tag>latest</tag>
<tag>${project.version}</tag>
</tags>
<ports>
<port>8080</port>
</ports>
</build>
<run>
<namingStrategy>alias</namingStrategy>
</run>
<alias>${project.build.finalName}</alias>
</image>
</images>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
</project>
spring:
profiles: allnative
application:
name: personal
jpa:
database-platform: org.hibernate.dialect.PostgreSQL9Dialect
properties:
hibernate:
temp.use_jdbc_metadata_defaults: false
show_sql: false
format_sql: false
use_sql_comments: false
hibernate:
ddl-auto: update
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://127.0.0.1:5432/sylphid
username: postgres
batch:
initialize-schema: always
cache:
type: redis
redis:
key-prefix: sylphid_
time-to-live: 60m
redis:
host: 127.0.0.1
port: 6379
kafka:
bootstrap-servers: 127.0.0.1:9092
consumer:
auto-offset-reset: earliest
group-id: bookclub
server:
port: 13480
app:
topic:
selection: bookclub.selection
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
logging:
file: allnative.log
Edit(2):
I was calling curl for each endpoint without any delay:
curl endpointA; curl endpointB; curl endpointC; curl endpointD
( almost 60 seconds interval before next cronjob )
curl endpointA; curl endpointB; curl endpointC; curl endpointD
...
Yesterday I tried to insert some delay between each curl executions, guessing "the interval between the last request and current request affects the response time of current request". (like... a human worker may fall asleep if nobody asks him to do something for a long time. When someone calls for him, he needs some more time to wake up. If someone else calls for him while he is awake, he can do the second job faster.)
When I inserted more than 2 seconds delay, I could see another endpoint began to be slow. When I inserted 10 seconds delay:
curl endpointA; sleep 10; curl endpointB; sleep 10;...
( about 20 seconds interval, because crontab still executes every minutes )
curl endpointA; sleep 10; curl endpointB; sleep 10;...
Here is the result. Every endpoints began to response after around 100ms.
Edit(3)
As a new attempt, I tried to use Jetty as embedded server instead of Tomcat. The result was somewhat impressive. Application using Jetty showed very stable response times for almost every measurement. Even Jetty showed long response time(about 300ms or so) sometimes, but they were very rare cases.
I have been observing two testsets(Tomcat and Jetty) for a few hours, and I'm going to observe one or more days. If this result goes on, I'll plan to tell my teammates about this and suggest to change the embedded server to Jetty.
However, if Tomcat is the cause of trouble, I have no idea why the simple Spring Boot app from the official guide does not show such a symptom.


