Обзор
Как разработчик Java, API RESTful – это мой хлеб с маслом. В большинстве дней я трачу большую часть своего времени на написание кода, который либо составляет конечные точки RESTful, либо взаимодействует с ними, либо нисходящий код, запускаемый конечной точкой.
Несколько лет назад я слышал о некоторых слухах о новом формате RPC, и я сразу же вспомнил о своих днях, когда занимался легким GWT (Google Web Toolkit) разработка. С этими словами я отбросил идею исследования gRPC и продолжил свои стандартные рабочие процессы.
Однако несколько месяцев назад мне была предоставлена возможность заняться новым проектом Golang на работе. Я слышал много хорошего о Голанге, поэтому сразу же нырнул в него.
С тех пор я влюбился в этот язык, хотя Java по-прежнему остается тем местом, где я чувствую себя как дома.
Однако, используя Go, я все чаще и чаще сталкиваюсь с использованием gRPC.
Поэтому в рамках моего дальнейшего обучения я разработал этот простой небольшой тест, чтобы увидеть, как дебаты о производительности rpc против REST на самом деле разворачиваются только в Java.
Это не невероятно научный эксперимент, но я чувствую, что он, по крайней мере, дает несколько четкие результаты относительно того, чего можно ожидать, когда кто-то на вашей работе начнет предлагать новую горячность (в данном случае gRPC) и клянется, что это решит проблему X или Y и даст преимущества в производительности A или B.
Я был таким парнем раньше, и это всегда помогает иметь соответствующие и конкретные результаты, чтобы показать всем, что помогает повлиять на вашу точку зрения.
Итак, с этим покончено, вот мой глупый маленький эксперимент по производительности rpc на основе Java против Rest.
Отдых против rpc tl;dr
Прежде чем мы перейдем к эксперименту и тестированию, вот краткий обзор.
API-интерфейсы RESTful используют HTTP 1.0/1.1 и включают использование глаголов HTTP (например. ПОЛУЧИТЬ/ОПУБЛИКОВАТЬ/УДАЛИТЬ) для передачи сообщений от клиента к серверу. Большинство серверов предоставляют конечные точки, которые ожидают определенных заголовков и команд и используют входящие данные для выполнения операций. Данные обычно представлены в формате JSON, который Java-код десериализует в объекты Java для использования в приложении.
gRPC, с другой стороны, использует HTTP/2 и буферы протоколов, которые могут быть упрощены в двоичный файл по протоколу HTTP. Буферы протокола описывают длину компонентов в двоичном потоке. Поэтому вместо того, чтобы разграничивать данные с помощью токенов JSON (таких как {, и “), потоки данных являются двоичными и анализируются с использованием известных размеров ожидаемых типов данных. Затем это десериализуется в объекты Java.
Хорошо, вот упрощенный обзор деталей теста.
Тестовые данные и макет
Цель этого теста состояла в том, чтобы дать некоторые примеры производительности rpc по сравнению с Rest, в частности. Это одна из наиболее часто приводимых причин для перехода на gRPC, поскольку данные в виде двоичного потока меньше, чем объект json.
Этот тест был реализован с использованием ровно 2 приложений JVM. Одним из них является приложение Spring Boot, которое содержит аннотированные классы RestController для обработки входных данных, а также содержит клиент, который использует WebClient Spring Webflux для выполнения блокирующих вызовов API к RestController.
Второе приложение – это собственное приложение Java, которое использует библиотеки io.grpc для определения клиента и сервера gRPC.
Эти приложения были развернуты в двух местах и запускались как выполняемые jar-файлы. Оба были развернуты на локальном рабочем столе, а также на экземпляре AWS EC2. Подробности для обоих включены в следующий раздел.
Тест заключается в следующем:
Используйте случайно сгенерированные данные в определенном формате, который идентичен в gRPC и Тестирование на отдых
Отправляйте все большее количество запросов, чтобы увидеть, как масштабируется обработка
представьте производительность в полуреальном мире, совершая звонки из локальной системы в центр обработки данных, расположенный на расстоянии не менее 200 миль.
Вот пример макета шаблона Rest JSON:
{ "car": { "make": "toyota", "model": "corolla", "trim": "4DR Sedan", "color": "gray", "year": 2012, "mileage": 120000 }, "driver": { "firstname": "John", "lastname": "Smith", "driverId": "someId" } }
Вот определение прототипа для сообщений gRPC
syntax = "proto3"; option java_multiple_files = true; message Message { message Car { string make = 1; string model = 2; string trim = 3; string color = 4; uint32 year = 5; uint32 mileage = 6; } message Driver { string firstname = 1; string lastname = 2; string driverId = 3; } Car car = 1; Driver driver = 2; }
Они функционально идентичны и могут служить примером того, как может выглядеть переход от существующего Rest API к заменяющему gRPC api.
Испытательные машины
Удаленной машиной, на которой работали серверы gRPC и Rest, были машины экземпляра t2.small EC2. Это были обычные, не спортивные, не выделенные экземпляры t2.small, в которых был открыт весь трафик TCP и UDP. С белым списком для локальной тестовой машины, которая будет попадать в него.
Приложения JVM были запущены локально с использованием Windows 10 x64 OpenJDK версии 11.0.11. Удаленные JVM были запущены с использованием java-11-amazon-corbett на ОС AWS Linux 2.
Локальная тестовая машина была моим личным рабочим столом для разработки. Эта система содержит Ryzen 3700x и 64 ГБ оперативной памяти 3200 ГГц. Более чем излишне для выполнения описанных выше тестов.
Результаты
Каждый тест был проведен (от локального до ec2) 10 раз, и было взято среднее значение. Это было для последовательных запросов через Rest и gRPC, как показано в столбцах ниже.
gRPC (ВРП) | 14478мс | 25239 мс | 37823 мс | 53073мс | 62624 мс |
Отдых | 16451 мс | 30181 мс | 43996 мс | 58221 мс | 71300 мс |
Есть пара вещей, которые мы хотим рассмотреть в рамках этих результатов. Они являются подразделами ниже!
Насколько медленнее отдых при каждой сумме запроса
1000 | на 13,6% медленнее |
2000 | на 19,5% медленнее |
3000 | на 16% медленнее |
4000 | на 9% медленнее |
5000 | на 13% медленнее |
Мы можем с уверенностью сказать, что gRPC всегда будет быстрее, чем вызовы Rest. Это согласуется с деталями реализации gRPC, в частности двоичными потоками через JSON, двоичным анализом и маршалингом и т. Д.
Какова была корреляция между увеличением количества запросов и временем завершения для Rest и rpc
Хороший вопрос! Таким образом, при каждом увеличении количества запросов мы ожидаем линейного увеличения времени обработки этих сообщений. Т. е. дважды сообщения должны занимать в два раза больше времени. Давайте посмотрим, так ли это было на самом деле.
gRPC (ВРП) | основание | на 74% дольше | на 49% дольше | на 40% дольше | на 17% дольше |
Отдых | основание | на 83% дольше | на 45% дольше | на 32% дольше | на 22% дольше |
Запрос на увеличение в % | 0 | на 100% больше | на 50% больше | на 33% больше | на 25% больше |
Основываясь на приведенных выше результатах, это немного хит или промах. И Rest, и gRPC примерно отслеживают увеличение. В большинстве случаев время обработки увеличивается быстрее, чем увеличивается запрос, и это хорошо! Это означает, что мы не тратим экспоненциально все больше и больше времени на обработку большего количества запросов.
О чем все это нам говорит?
Вне этого конкретного теста? Ни тонны. Это хороший пример для использования в качестве основы и хороший простой эксперимент для сравнения эффективности двух парадигм.
Как и следовало ожидать, репозиторий доступен на Github со всем исходным кодом .
Оригинал: “https://dev.to/stevenpg/grpc-vs-rest-simple-performance-test-228m”