Моя установка для теста производительности следующая:
Примеры приложений предоставляют конечную точку (/ passthrough / message), которая, в свою очередь, вызывает нисходящую службу. Сообщение запроса к конечной точке выглядит примерно так:
1
2
3
4
5
|
{ "id" : "1" , "payload" : "sample payload" , "delay" : 3000 } |
Нисходящая служба будет задерживать на основе атрибута «delay» в сообщении (в миллисекундах).
Приложение Spring Boot 1
Я использовал Spring Boot 1.5.8.RELEASE для версии приложения Boot 1. Конечной точкой является простой контроллер Spring MVC, который, в свою очередь, использует RestTemplate Spring для выполнения нисходящего вызова. Все происходит синхронно и блокируется, и я использовал встроенный контейнер Tomcat по умолчанию в качестве среды выполнения. Это необработанный код для последующего вызова:
1
2
3
4
5
|
public MessageAck handlePassthrough(Message message) { ResponseEntity<MessageAck> responseEntity = this .restTemplate.postForEntity(targetHost + "/messages" , message, MessageAck. class ); return responseEntity.getBody(); } |
Приложение Spring Boot 2
Версия приложения Spring Boot 2 предоставляет конечную точку на основе Spring Webflux и использует WebClient , новую неблокирующую реактивную альтернативу RestTemplate для выполнения нисходящего вызова — я также использовал Kotlin для реализации, которая не влияет на производительность. Сервер выполнения Netty :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
import org.springframework.http.HttpHeaders import org.springframework.http.MediaType import org.springframework.web.reactive.function.BodyInserters.fromObject import org.springframework.web.reactive.function.client.ClientResponse import org.springframework.web.reactive.function.client.WebClient import org.springframework.web.reactive.function.client.bodyToMono import org.springframework.web.reactive.function.server.ServerRequest import org.springframework.web.reactive.function.server.ServerResponse import org.springframework.web.reactive.function.server.bodyToMono import reactor.core.publisher.Mono class PassThroughHandler( private val webClient: WebClient) { fun handle(serverRequest: ServerRequest): Mono<ServerResponse> { val messageMono = serverRequest.bodyToMono<Message>() return messageMono.flatMap { message -> passThrough(message) .flatMap { messageAck -> ServerResponse.ok().body(fromObject(messageAck)) } } } fun passThrough(message: Message): Mono<MessageAck> { return webClient.post() .uri( "/messages" ) .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) .body(fromObject<Message>(message)) .exchange() .flatMap { response: ClientResponse -> response.bodyToMono<MessageAck>() } } } |
Детали теста производительности
Тест прост, для разных наборов одновременных пользователей (300, 1000, 1500, 3000, 5000) я отправляю сообщение с атрибутом задержки, установленным на 300 мс, каждый пользователь повторяет сценарий 30 раз с задержкой от 1 до 2 секунд между запросами. Я использую отличный инструмент Гатлинга для генерации этой нагрузки.
Полученные результаты
Вот результаты, полученные Гатлингом:
300 одновременных пользователей:
Ботинок 1 | Boot 2 |
---|---|
1000 одновременных пользователей:
Ботинок 1 | Boot 2 |
---|---|
1500 одновременных пользователей:
Ботинок 1 | Boot 2 |
---|---|
3000 одновременных пользователей:
Ботинок 1 | Boot 2 |
---|---|
5000 одновременных пользователей:
Ботинок 1 | Boot 2 |
---|---|
Как и ожидалось, когда число одновременно работающих пользователей остается низким (скажем, менее 1000), Spring Boot 1 и Spring Boot 2 хорошо справляются с нагрузкой, а время отклика в 95 процентилей остается на миллисекунды выше ожидаемой задержки в 300 мс.
При более высоких уровнях параллелизма асинхронный неблокирующий ввод-вывод и реактивная поддержка в Spring Boot 2 начинают показывать свои цвета — время 95-го процентиля даже при очень большой нагрузке в 5000 пользователей остается на уровне около 312 мс! Spring Boot 1 регистрирует множество сбоев и большое время отклика на этих уровнях параллелизма.
У меня есть все примеры и скрипты загрузки, доступные в моем репозитории github — https://github.com/bijukunjummen/boot2-load-demo.
См. Оригинальную статью здесь: Необработанные показатели производительности — Spring Boot 2 Webflux против Spring Boot 1
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |