Производительность - Spring Boot - время ответа сервера

У меня странное поведение в нашем весеннем загрузочном приложении:

  • Frontend/Client - угловой 6
  • Backend - весенний ботинок - весна MVC - встроенный tomcat - Linux

После перезапуска бэкэнд первым вызовам контроллера требуется около 5 секунд, следующий запрос будет занимать только 50 мс. Это воспроизводится в 90% случаев, иногда даже первый вызов выполняется быстро.

Я уверен, проблема на сервере не на клиенте. В браузере я вижу, что время TTFB (время до первого байта) увеличивается до 5 секунд. Следующие запросы требуют только 10 мс для TTFB.

С инструментами мониторинга на сервере (динамика приложений) я могу собирать такие медленные вызовы сервера, а на графике вызовов я вижу, что:

org.apache.catalina.webresources.JarWarResourceSet:getArchiveEntries:117

требуется 4916 мс. Так вот, вот мое узкое место, я думаю. Но я не знаю, как это исправить.

Что я уже пробовал:

  • Переключено с hikaricp в пул соединений apache tomcat jdbc
  • Ugraded spring boot от 2.0.0 до 2.0.5
  • Обновлен java до 1.8.0_181
  • Propertie spring.jpa.tomcat.testOnBorrow = true
  • Propertie spring.jpa.tomcat.validationQuery = выберите 1

Все без влияния на задержку сервера.

Обновить

Время утеряно, потому что файл войны сканируется несколько раз.

org.apache.catalina.webresources.CachedResource.validateResource проверяет, есть ли у нас файл войны (isPackedWarFile), и эта проверка возвращает false. Хотя это военный файл. Для этого плохого поведения у меня есть обходное решение. Я установил tomcat.resource.cache-tt в большое значение.

Но теперь org.apache.catalina.webresources.Cache.getResource имеет метод noCache. И в этом методе класс и файлы jar исключаются из кеширования. И вот почему файл войны снова проверяется.

Сканирование всего файла войны занимает примерно 5 секунд. И этот перерыв - это остановка мировой паузы. И это сканирование абсолютно бесполезно, потому что файл войны не взорван и поэтому его содержимое не может быть изменено.

Обновить

Если я поместил файл войны в установку tomcat, все будет быстро. Проблема с встроенным tomcat.

Ответ 1

Я полагаю, вы уже это сделали, но если вы этого не сделали, взгляните на https://wiki.apache.org/tomcat/HowTo/FasterStartUp и внесите исправления, предлагаемые там.

Для отключения сканирования со встроенным tomcat в комментариях есть предложение: https://github.com/spring-projects/spring-boot/issues/1610

Если ни одно из приведенных выше рекомендаций не поможет вам исправить задержку, возможно, это будет первый запрос при запуске сервера (и запуск задержки оттуда).

@SpringBootApplication
public class Application implements CommandLineRunner {

    @Autowired
    private RestTemplate template;

    public static void main (String args[]){
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... strings) throws Exception {
        // do an initial request from here to trigger scanning the war
        template.exchange(...);
    }

}

Таким образом, ваш клиент больше не будет испытывать задержку 5 с. Я знаю, что это взломать, поэтому, если вы найдете более чистый способ сделать это, используйте это вместо этого.

Ответ 2

Я столкнулся с аналогичной проблемой высокой загрузки процессора и задержки в ответе. org.apache.catalina.webresources.JarWarResourceSet:getArchiveEntries занимала около 5 секунд во время сканирования файла войны. Во время сканирования запросы не подавались.

Я обновил Spring boot version с 1.4.2.RELEASE до 1.5.12.RELEASE, которая разрешила эту проблему. Действительно, похоже, проблема связана со встроенным Tomcat который исправлен в более поздних версиях.

Ответ 3

То, что вы описываете, является типичным эффектом перезагрузки в инфраструктуре, которая использует большой пул соединений с БД.

  • первый запрос: откройте физическое соединение (от 100 мс до 2-3 секунд), выполните некоторую инициализацию (зависит от БД), выполните SQL (измените для каждого запроса), вернитесь в пул (<1 мс)
  • второй запрос: извлечение из пула (<1 мс), выполнение SQL (для каждого запроса), возврат в пул (<1 мс)

основанный на ваших данных, я думаю, что первые два шага медленны и неспособны разогреть пул БД, вы будете испытывать очень медленные запросы. Потенциальные улучшения:

  • настройте период разминки, в течение которого пул выполняет self-init, а Tomcat еще не отвечает
  • проверьте на стороне БД, что делается при создании соединения и на стороне приложения, если/в какой конфигурации вы должны настроить соединение

Ответ 4

Использование исполняемого файла JAR (вместо WAR) для запуска со встроенным Tomcat решило проблему для меня. Это рекомендуемый способ для ускорения загрузки ресурсов из исполняемых архивов.

  1. вы можете иметь один проект Spring Boot и развертывать его как в JAR, так и в WAR,
  2. Мне пришлось переключиться с WAR на JAR, чтобы иметь лучшую производительность и возникла проблема при использовании JSP taglibs во freemarker. Это способ решить эту проблему при использовании JSP taglibs.

Ответ 5

Я думаю, вы должны добавить эти вещи для правильной работы весеннего сапога с помощью Angular 6:

  1. Добавление зависимостей в ваш pom.xml ниже:

=>

<dependencies>
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-undertow</artifactId>
     </dependency>
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
       <exclusions>
          <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
          </exclusion>
       </exclusions>
     </dependency>
</dependencies>
  1. Создайте файл application.yml в папке resources проекта spring-boot и добавьте эти строки для настройки сервера tomcat:

=>

server:
       port: 8082
       undertow: 
          ioThreads: 15
          workerThreads: 150
          accesslog: 
             enabled: true
       compression: 
          enabled: true
          mimeTypes: text/xml, text/css, text/html, application/json
          minResponseSize: 4096
spring:
  application: 
    name: give the name of the spring boot project here

Примечание. Вы должны изменить minResponseSize, iothreads и workthreads в application.yml. Значение по умолчанию для minResponseSize составляет 2048 байт. Здесь я изменил его на 4096 байт. Измените его соответствующим образом.

Спасибо :)

Это может вам помочь.