Большой бизнес регулярно сталкивается с вызовами: экономическими, социальными, с недавних пор геополитическими. В секторе банковских переводов критическую массу проблем можно смело умножать в несколько раз. Всё зависит от того, с каким числом стран работает компания.
В этой статье мы раскроем одну из таких трудностей — поддержку работы Java-бэкенда на примере системы электронных платежей Монета.ру. Благодарим одного из её первых разработчиков и ныне технического директора Дениса Пашуткина за помощь в подготовке материала!
Нам всегда интересно, как на практике внедряются наши решения, какие практики приносят успех, и какова трудоемкость таких задач, как миграция на новые версии JDK и между серверами приложений. Внутри BellSoft-а мы больше делаем JDK, чем применяем его, поэтому стараемся опираться на теорию и на конкретные истории пользователей. Когда мы с Денисом поговорили об опыте «Монеты», то решили сделать совместный рассказ, где бы раскрывалась и архитектура этой системы, и те места, где поддержка и обновления Java-платформы играют существенную роль. С помощью коллег мы провели дополнительное интервью и оформили материал в виде статьи для Хабра.
Российские электронные платежи на американской Java
Монета.ру — многопрофильная система финансового учёта операций. Она играет разные роли в зависимости от пользователя. Для частных лиц это оператор по переводу денежных средств. Для онлайн-магазинов — универсальный агрегатор по приёму платежей. Интернет-проекты, в том числе далекие от ритейла, могут использовать Монета.ру как современную биллинговую платформу для выставления счетов. Все эти услуги также реализуются через собственное платёжное решение PayAnyWay. Ниже мы подробнее расскажем о развитии системы, чтобы понять, как она пришла к своему настоящему виду.
Естественно, такое разнообразие возникло не сразу. Проект эволюционирует уже 16 лет, со стадии идеи в 2005 г. За почти три года дизайна и разработки концепция довольно сильно изменилась, а в дальнейшем её ждала целая череда рефакторингов (которые, что важно, никогда не приводили к революции кода). Два фактора остаются неизменными:
Разработка ведётся исключительно в России.
Система почти полностью написана на Java.
На рисунке выше изображена схема Java-приложения Монета.ру. Можно заметить, что выглядит она довольно привычно. Однако система не ограничивается одним приложением, а состоит из нескольких взаимодействующих между собой сервисов, не все из которых реализованы на Java. Один связан с Системой Быстрых Платежей (СБП) — сервисом Банка России, разработанным совместно с Национальной системой платёжных карт (НСПК). В рамках взаимодействия с СБП есть требования к использованию специальных библиотек, обеспечивающих защиту информации. К сожалению, из java напрямую использовать эти алгоритмы нельзя. Стремясь исключить потенциальную точку отказа в виде JNI-обёртки, команда приняла решение создать специальный сервис на C++ и связать его с остальными сервисами по API. В остальном всё, что связано с системой межведомственного электронного взаимодействия (СМЭВ), реализовано внутри компонентов на Java с помощью библиотеки КриптоПро JCP.
Другой «не-Java» элемент относится к фронтенду. Там для удобства, продуктивности и дополнительной гарантии качества часть разработки ведётся на Kotlin.
В 2007 году, ещё до покупки торговой марки Java компанией Oracle, Монета.ру проектировалась и создавалась на Sun Microsystems JDK 1.6. В 2008-ом прототип заменили в промышленной эксплуатации на разработанную с нуля систему на той же версии JDK. На «шестёрке» компания просидела долго. Основная причина — библиотека Terracotta, которая использовалась в качестве application cash-а для получения разделяемого состояния. На новых версиях Java не поддерживалась модель обмена изменениями, а передавался полностью объект. Это снижало производительность, и нужно было подобрать замену. Выбор пал на hazelcast, компонент, который обеспечивает распределенный кэш.
Зависимость от JDK 6 была довольно сильной. Однажды инженерам даже пришлось написать свой HTTPS клиент, чтобы продолжать использовать уже устаревшие версии Java. Тем не менее, о немедленной миграции команда не задумывалась, как вдруг...
Oracle перевернул бизнес
Середина 2018-го принесла новость, которая заставила встрепенуться многие организации: End of Public Updates for Oracle Java SE 8 for commercial use after January 2019.
Переход с 1.6 на 7 не заставил себя долго ждать, хоть и был тяжёлым. После этого систему перенесли на JDK 8 меньше, чем за 3 месяца. Но команде было очевидно, что оставаться на этой версии как минимум неперспективно. Где-то на том этапе появились мысли, что JVM от Oracle — не единственная на рынке. В разработке был опыт использования JRockit, однако до эксплуатации дело не дошло.
Главные причины смены поставщика JDK компания обозначила для себя так:
Непоследовательность политики Oracle в отношении клиентов. Если пользователи узнают о глобальных переменах только постфактум, как же обстоят дела с изменениями меньшего порядка? О каких деталях вы можете даже не знать? Сколько их было до объявления о прекращении публичных обновлений и сколько будет после?
Возможность оставить код на Java без необходимости переплачивать за лицензию. Инженеры Монета.ру застали Java, когда «она была ещё Sun-овской», то есть принадлежала Sun Microsystems. Они посещали Sun Tech Days, наблюдали за тем, что постит vmrobot на blogs.sun.com. Некоторые писали на языке первых официальных версий в 1997–1998 годах. Команда стремится ориентироваться в мире Java и продолжать разработку на этой платформе.
Нельзя не отдать должное компании Oracle и другим участникам комьюнити за слаженную работу над проектом OpenJDK. На момент принятия решения альтернативы Oracle Java SE широко освещались на тематических конференциях и Java-евангелистами на Хабре. Так что выбор в пользу российского open source решения сложился почти сам собой.
Миграция на OpenJDK — плюсы, минусы, подводные камни?
В небезызвестной статье Олега Чирухина описан сервис https://jdk.dev/, где на первом месте фигурирует Liberica JDK компании BellSoft. Об этой реализации OpenJDK инженеры Монета.ру узнали на Joker 2018.
Liberica JDK проходила по важным для компании критериям:
вхождение в Единый реестр российского ПО — включена под номером 5394,
поддержка работы КриптоПро JCP 2.0 R3 (и с недавних пор версии 2.0 R4),
совместимость с существующей системой платежей, построенной на Oracle JDK.
Далее необходимо было убедиться в том, что миграция не приведёт к ошибкам.
Изучив описание Kinds of Compatibility, команда решила, что «Source compatibility» и «Binary compatibility» обеспечивают поставщик среды исполнения, исходный код OpenJDK и соответствие стандартам Java SE, подтвержденное тестами TCK. Оставалось только убедиться в «Behavioral compatibility». Здесь помог просмотр release notes всех промежуточных версий на предмет потенциально влияющих на платёжную систему изменений и прогоны сборки и тестов на демо-стенде.
По результатам тестирования на JDK 9, 10 и 11 разработчики Монета.ру запланировали достаточно экстремальный переход — с Oracle Java 8 сразу на Liberica JDK 12. Успешные тесты совместимости воодушевили, это стало решающим фактором в пользу выбора OpenJDK от BellSoft. Дальнейшие обновления проходили по плану, без сложностей и даже, по словам Дениса, «превратились в рутину», ведь их не ждут новые сюрпризы.
На момент написания статьи Монета.ру работает на актуальном релизе, Liberica JDK 16. Переход занял чуть больше времени, чем предыдущий, из-за reflective access, который с 16-ой версии стал недоступен к JDK классам по умолчанию. Инженеры знали об изменениях в модульной системе, появившейся в JDK 9, однако потребовалось более тщательное тестирование.
Система в эксплуатации и разработке
Изменилась ли система со сменой вендора? Безусловно. В настоящее время Монета.ру делает ставку на разного рода оптимизации. Экономия средств при росте производительности — горячая тема в индустрии.
С одной стороны, часть кластеров и сервисов работают на железе, без систем контейнеризации вообще. Есть сервера, поднятые при помощи систем виртуализации. С другой, есть связка Docker + Kubernetes. В этой части системы команда использует микроконтейнеры BellSoft с Alpine Linux (musl и glibc). Java-сервис поднимается на Liberica JDK и оркестрируется привычными способами.
Прижился ещё один сценарий использования: сборка образов на базе Ubuntu с Liberica JRE средствами Paketo Buildpacks при помощи плагина Maven на Spring Boot.
Ведутся эксперименты и с технологией native image при участии продукта Liberica Native Image Kit (NIK) — но не более. Инженеры не планируют с ним собирать сложные сервисы даже во внутренней корпоративной разработке. Основная причина: достаточная эффективность деплоя образов в контейнерах с Java.
Что же касается эксплуатации, «прод» пока чуть более консервативен: Java на обслуживаемых операционных системах, установленных на физических серверах. После тестирования новой версии Java инженеры выполняют обновление JDK на production серверах. Во многом это связано с требованиями, которые предъявляет к операторам денежных переводов ЦБ РФ и PCI DSS через аудиторов. Стоит заметить, что Центробанк не требует использования компонентов на определенном аппаратном обеспечении. Однако зачастую технические решения тесно связаны с организационными.
Разработку и эксплуатацию объединяют решения на Java (в общем и Liberica JDK в частности), связанные с Machine Learning. В банковской автоматизированной системе круг задач, которые можно решить с помощью ML, достаточно широк: это и антифрод, и умное наблюдение за работой инфраструктуры, и контроль за финансовой активностью, и роботы для работы с клиентскими обращениями, как голосовыми, так и текстовыми.
Для быстрого решения задач при помощи ML часто выбирают Python в связи с большим количеством мощных и удобных библиотек. Однако работа самой ML-модели — это далеко не весь функционал. Порой сбор и подготовка данных, обработка результата модели и запуск необходимых пост-процессов занимают значительно больше времени и требуют стройной архитектуры и эффективного использования ресурсов, чего значительно легче добиться на Java.
Разработчики Монета.ру выбрали для себя подход, при котором исследование данных и поиск подходящего ML-решения производятся на Python и его экосистеме, а уже в эксплуатацию попадает ML-компонент, реализованный на Java с соблюдением требований к функциональности, производительности и отказоустойчивости.
Что ждёт Монета.ру в будущем
Даже теперь, когда переход на новые версии JDK больше не связан с ворохом проблем, инженеры Монета.ру ищут, как держать себя в тонусе. Развитие языка Java к этому располагает благодаря регулярному выходу новых технологий, таких как всеми ожидаемый Project Loom. С его ранними сборками уже ведутся эксперименты, правда, за пределами реализации платёжной системы.
Помимо больших проектов, Java предлагает разный синтаксический сахар. Его хочется добавлять в код, но не переусердствовать — как говорит Денис, «так и до диабета недалеко». В среду разработки попадают далеко не все последние функции Java, в эксплуатацию — тем более. Главное то, что приносит пользу, а не то, что для хайпа. Команда в Монета.ру довольно большая, около 50 человек, и все должны в равной степени понимать, что происходит в коде на любом этапе.
План на ближайшее будущее: использовать контейнеризацию в продакшене более активно. Перенести в контейнеры все сервисы, которые поддаются этому безболезненно, поскольку слаженным оркестром легче дирижировать.
Следующий возможный этап — более тонкое конфигурирование контейнеров либо использование надстройки над образами Liberica JDK, которые компания получает от BellSoft.
С имплементацией актуальных облачных решений компания не торопится. И хотя многие «внешние» облачные провайдеры готовы предоставить сертификаты соответствия требованиям ЦБ, безопасность персональных и финансовых данных клиентов стоит на первом месте, а она должна быть безоговорочной. Команда раздумывает над возможностью полноценной cloud-native разработки, с эксплуатацией и обслуживанием системы в облаках. Но пока Монета.ру — не коробочный продукт, а сервис, который обслуживают только сами инженеры компании, а значит, такой необходимости нет.
Для крупных компаний история Монета.ру необычна. Ведь со сменой пользовательской политики Oracle многие до сих пор сидят на «восьмёрке» или даже на 1.6. Мы надеемся, что данный use case окажется интересным и полезным для всех сомневающихся, стоит ли переводить систему на новые версии.
Естественно, любое изменение требует усилий, и каждая новая версия означает множество проверок и тестов. Однако уже сейчас, сразу после обновления до Liberica JDK 16, у ведущего архитектора стоит задача «Переход на Java 17». Путь к совершенству бесконечен. И мы тоже с нетерпением ждём LTS-релиз.
aleks_pingvin
А еще Liberica, насколько я наслышан, готовить сертифицированные LTS версии java (8 и 11-ую) до конца года, что весьма востребовано будет в гос. секторе.