предисловие
Могут ли микросервисы Java быть такими же быстрыми, как микросервисы Go?
Это вопрос, над которым я недавно думал.
На конференции Oracle Groundbreakers Tour 2020 LATAM в августе прошлого года Марк Нельсон и Питер Нэги провели серию базовых тестов для сравнения. Далее я познакомлю вас с ним.
В кругах программистов преобладает мнение, что Javaстарый, медленный, скучный, в то время как Goбыстро, ново, круто
Чтобы провести относительно честный тест, они использовали очень простой микросервис без внешних зависимостей (таких как база данных), очень короткие пути кода (просто манипулирование строками), используя небольшие и легкие фреймворки (Helidon для Java и Go). Toolkit for Go), экспериментировал с разными версиями Java и разными jvms.
дуэт дуэт
Давайте сначала посмотрим на игроков по обе стороны ринга:
- Игроки в темной формеJAVA
Java была разработана компанией Sun Microsystems, которая была приобретена Oracle. Его версия 1.0 была выпущена в 1996 году, а последняя версия — Java 15 — в 2020 году. Основными целями проектирования являются виртуальная машина Java и переносимость байт-кода, а также управление памятью с помощью сборки мусора. Это один из самых популярных языков в мире, разработанный в среде с открытым исходным кодом.
Давайте сначала взглянем на проблему JAVA.Принято считать, что ее самая большая проблема заключается в ее медленной скорости, настолько медленной, что люди чувствуют, что она уже не разумна, а более исторична. Но за прошедшие годы в Java было создано множество различных алгоритмов сборки мусора для его ускорения.
Oracle Labs недавно разработала новую виртуальную машину Java, GraalVM, которая имеет новый компилятор и некоторые интересные новые функции, такие как возможность конвертировать байт-код Java в собственный образ, который можно запускать без операции javavm и т. д.
- А его противник молод и энергиченGO
GO был создан Робертом Граймером из Google, Робом Пайком и Кеном Томсоном. Они внесли значительный вклад в UNIX, B, C, Plan9, оконную систему UNIX и многое другое. GO имеет открытый исходный код: версия 1.0 выпущена в 2012 году (через 16 лет после JAVA), а версия 1.15 — в 2020 году. Он быстро растет как с точки зрения принятия, так и самой языковой и инструментальной экосистемы.
GO находится под влиянием нескольких языков, включая C, Python, JavaScript и C++. Разработан, чтобы быть лучшим языком для высокопроизводительных сетей и многопроцессорной обработки.
StackOverflow имеет 27872 вопроса с «Go», а Java — только 1702730. Видно, что обратные волны реки Янцзы толкают передние волны.
Go — статически типизированный компилируемый язык. У него есть легкие процессы, называемые горутинами (это не потоки ОС) с уникальными каналами связи (типизированными, FIFO) между ними. Go является предпочтительным языком для многих проектов CNCF, таких как Kubernetes, Istio, Prometheus и Grafana.
Предматчевое сравнение
С личной точки зрения преимущества Go по сравнению с JAVA:
- Go упрощает реализацию функциональных шаблонов, таких как композиция, чистые функции, неизменяемое состояние и т. д.
- Go находится на ранней стадии своего жизненного цикла, поэтому он не несет тяжелого бремени обратной совместимости — Go все еще можно легко улучшить, сняв определенные ограничения.
- Go компилируется в собственный статически связанный двоичный файл — без слоя виртуальной машины — в двоичном файле есть все необходимое для запуска программы, что отлично подходит для контейнеров «с нуля».
- Go мал, быстро запускается, быстро выполняется (в настоящее время да)
- В Go нет ООП, наследования, дженериков, утверждений, арифметики указателей.
- Меньше скобок в Go
- В Go нет циклических зависимостей, неиспользуемых переменных или импортов, принуждения к неявным преобразованиям типов.
- В Go гораздо меньше шаблонного кода
слабость это:
- Экосистема инструментов Go незрела, особенно управление зависимостями — есть несколько вариантов, ни один из которых не идеален, особенно для разработки не с открытым исходным кодом; проблемы совместимости остаются.
- Сборка кода с новыми/обновленными зависимостями выполняется очень медленно (например, знаменитая проблема Maven «загрузка из Интернета»).
- Импортирует код привязки в репозиторий, что превращает перемещение кода в репозиторий в кошмар.
- Отладка, профилирование и т. д. остаются проблемой
- указатель используется
- Некоторые базовые алгоритмы должны быть реализованы
- нет динамической ссылки
- Не так много ручек для настройки выполнения или сборки мусора, выполнения профиля или оптимизации алгоритмов.
Начало игры
Используйте JMeter для запуска нагрузочных тестов. Эти тесты вызывают эти службы несколько раз и собирают данные о времени отклика, пропускной способности (транзакций в секунду) и использовании памяти. Для Go собирается размер резидентного набора, для Java отслеживается собственная память.
Перед измерением приложение было прогрето 1000 звонками в службу поддержки.
Исходный код самого приложения, а также определение нагрузочных тестов находятся в этом репозитории GitHub:Нельсон на GitHub.com/mark…
первый раунд
В первом раунде тестирования тестировался на «маленькой» машине двухъядерный ноутбук Intel Core i7 с тактовой частотой 2,5 ГГц и 16 ГБ оперативной памяти под управлением macOS. Тест выполнялся со 100 потоками, по 10 000 циклов в каждом, со временем нарастания 10 секунд. Приложение Java работает на JDK11 и Helidon2.0.1. Приложение Go, скомпилированное с помощью Go 1.13.3.
Результат выглядит следующим образом:
Видно, что Го выиграл первый раунд!
JAVA занимает слишком много памяти; прогрев оказывает большое влияние на JVM — мы знаем, что JVM оптимизируется во время выполнения, так что это имеет смысл.
На основе первого раунда был представлен образ GraalVM, чтобы сделать среду выполнения приложения Java более похожей на среду приложения Go, и тест образа GraalVM (собственный, созданный с помощью GraalVM EE 20.1.1-JDK 11). ) было добавлено изображение) результат:
Мы не увидели существенного улучшения пропускной способности или времени отклика при запуске приложения на JVM с использованием образа GraalVM, но объем памяти уменьшился.
Ниже приведен график времени отклика для некоторых тестов:
второй раунд
Во втором раунде тестирования используйте более крупную машину для запуска тестов. 36 ядер (по два потока на ядро), 256 ГБ памяти, машина под управлением oraclelinux7.8.
Как и в первом раунде, использовалось 100 потоков, каждый поток использовал 10 000 циклов, время ускорения 10 секунд и те же версии Go, Java, Helidon и GraalVM.
Результат выглядит следующим образом:
В этом раунде побеждает образ GraalVM!
Ниже приведен график времени отклика для некоторых тестов:
Вариант Java показал себя намного лучше в этом тесте и значительно превзошел Go без использования ведения журнала Java. Кажется, что Java лучше использует несколько ядер и потоков выполнения, предоставляемых аппаратным обеспечением (по сравнению с Go).
Лучшая производительность в этом раунде у нативного образа GraalVM со средним временем отклика 0,25 мс и 82426 транзакций в секунду, а лучший результат для Go — 1,59 мс и 39227 транзакций в секунду, однако это на два порядка больше за счет памяти!
Образы GraalVM примерно на 30–40% быстрее, чем то же приложение, работающее на jvm!
третий раунд
На этот раз конкуренты запускают эти приложения в кластере Kubernetes, более естественной среде выполнения для микросервисов.
На этот раз использовался кластер Kubernetes 1.16.8 с тремя рабочими узлами, каждый с двумя ядрами (два потока выполнения на ядро), 14 ГБ оперативной памяти и oraclelinux 7.8.
Доступ к приложению осуществляется через входной контроллер Traefik, JMeter работает за пределами кластера Kubernetes для некоторых тестов, а для других используется ClusterIP, а JMeter работает в кластере.
Как и в предыдущем тесте, мы использовали 100 потоков, каждый из которых использовал 10 000 циклов, и время нарастания 10 секунд.
Вот различные размеры контейнеров:
- Go 11.6MB 11.6 MB
- Java/Helidon 1.41GB 1.41 GB
- Java/Helidon JLinked 150MB 150mb
- Native image 25.2MB 25.2 MB
Результат выглядит следующим образом:
Ниже приведен график времени отклика для некоторых тестов:
Во время этого раунда мы заметили, что Go иногда был быстрее, а образы GraalVM иногда были быстрее, но разница между ними была небольшой (обычно менее 5%).
Кажется, что Java лучше использует все доступные ядра/потоки, чем Go — мы видели лучшую загрузку ЦП в наших тестах Java. Производительность Java лучше на машинах с большим количеством ядер и памяти, производительность Go лучше на небольших/менее мощных машинах. На машине «производственного масштаба» Java легко работает так же быстро, как Go, или даже быстрее.
наконец-то
В будущем будет больше контрольных матчей, чтобы узнать, кто лучше! Если вам интересно, вы также можете попробовать сами, не забудьте сообщить нам о результате!
Ссылка на эту статью:medium.com/reasonable, ох ты/жалкий…
Добро пожаловать, чтобы обратить внимание на мою официальную учетную запись: Programmer DD, получить эксклюзивные учебные ресурсы, ежедневные галантереи и благотворительные подарки.