Pull to refresh

Comments 17

А есть результаты сравнения при достаточно большой нагрузке, в много тысяч запросов в секунду? (ʘ‿ʘ)

Это часто не обязательно для обоснования в финтехе. Хотелось перейти на Котлин с Джавы, как сделать? Показываем что-то радикальное вроде Go. Пока все в шоке, показываем Kotlin, который вроде та же Java, но на стероидах, и плюшки с Go пересекаются. Все счастливы, перемены небольшие, выбрали Котлин. Профит!

А можно пояснить - что именно подразумевается под backend в данном случае? Что-то мне подсказывает, что речь не идет о сложной бизнес-логике, которая крутится на центральных серверах банка, а о некотором промежуточном слое между фронтами и центральными системами...

  • Null Safety. Позволяет минимизировать количество NPE (NullPointerException), так знакомых всем разработчикам. То есть обращение к непроинициализированным переменным.

Проблема на самом деле несколько искусственная. Мы пишем на специализированном (те самые "центральные банковские системы" на серверах что реализуют всю банковскую логику) языке где этой проблемы просто нет как класса. Там просто не принято активно использовать динамическое выделение памяти (кроме потенциальных рисков и проблем, это еще и время на выделение-освобождение памяти), хотя язык это и поддерживает в минимальном объеме - alloc/dealloc/realloc + based переменные. Плюс к тому компилятор всегда при объявлении переменной автоматически инициализирует ее дефолтным для данного типа значением (если не указано явное значение для инициализации).

  • Неблокирующая многопоточность и IO. Если раньше приложение представляло собой монолит, не предполагающий никаких сетевых взаимодействий между его частями, то сейчас отдельным сервисам надо эффективно общаться.

Это, скорее, вопрос не языка но платформы. Любая ОС предоставляет достаточное количество механизмов межпроцессного обмена данными - разделяемая память, пайпы, сокеты - это из общего, что есть везде. Плюс специфические средства для разных систем как то

  • UNIX sockets - локальные именованные (т.е. привязанные к имени, но не к IP/порту) сокеты. Могут быть потоковыми (аналогично TCP) или датаграммными (аналогично UDP). В плане межпроцессного обмена данными датаграммные удобнее.

  • Mailslots в Windows. Некая именованная сущность - создается процессом-сервером, который может из него читать. Все остальные процессы открывают его по имени и могут в него писать. Используют датаграммный формат обмена. Механизм использования примерно такой - каждый процесс (сервис) создает свой слот с уникальным именем и таким образом все общение между процессами сводится к записи нужной информации в соответсвующий слот. Вопросами разделенного доступа занимается сама система.

  • На нашей платформе выбор еще богаче - поддерживаются UNIX sockets, но есть еще специфические для нашей системы объекты - пользовательские пространства (UserSpace) - некий аналог memory mapped file с которым можно работать просто как с областью памяти (получаешь указатель и работаешь, только размер динамически меняется при необходимости), очереди (DataQueue, UserQueue) - это не монстры типа кафки или раббита, но достаточно простые в использовании сущности - записал-прочитал. Любой может писать, любой может читать. Плюс возможность использовать ключ для чтения-записи.

Так что все это общие вопросы с конкретным языком никак не связанные.

First-Class Functions — функции, которые мы можем передавать в другую функцию как параметр и получать их как возвращаемое значение

Не совсем понятно о чем речь. Что мешает передавать указатель на процедуру (например, использовать древний как мир механизм callback-функций)? Например, есть некий сервис многопоточной параллельной обработки данных (одно головное задание, которое делает выборку данных для обработки и раздает отобранные данные нескольким заданиям-обработчикам). Ядро обеспечивает создание и эксплуатацию конвейера (механизм обмена данными), запуск дочерних заданий-обработчиков. Задача разработчика - написать две процедуры - подготовка пакетов для обработки на стороне головного задания и обработку пакета на стороне обработчика. Эти процедуры регистрируются в качестве callback-функций в ядре и все. Дальше ядро уже делает все само - на стороне головы вызовет процедуру подготовки очередного пакета, получит пакет, выложит его на конвейер. На стороне обработчика возьмет пакет с конвейера, вызовет процедуру обработки пакета.

Если же говорить о микросервисах вообще, то на мой взгляд это просто современный такой хайп на эту тему.

Есть старая (годов этак с 70-х еще) добрая модель акторов. Сиречь набор модулей, каждый из которых выполняет некоторую функцию и вызывается или напрямую, или по событию.

В *nix системах есть понятие демонов. В винде - сервисы...

В любой система можно писать отдельные модули (программы) или дингамические разделяемые библиотеки (как бы они не назывались - dll, сервисные программы или еще как) и вызывать их или по необходимости из других программ (как функцию), так и запускать в отдельном процессе (задании) чтобы они "висели" в дежурном режиме с открытым каналом связи (слот, сокет, очередь и т.п.). Вот вам и многомодульная (немонолитная) архитектура где каждый модуль может модифицироваться независимо (нужно заботиться только о постоянстве его интерфейса).

IPC? Вы к нам случаем не из python?

Нет, бог миловал от питона :-)

Много лет только на С/С++. Сейчас в основном - RPG (такой специалььный язык для коммерческих вычислений на платформе IBM). Ну и на С/С++ иногда (некоторые низкоуровневые вещи).

Мой посыл в том, что любая платформа (ОС) предоставляет широкий выбор средств межпоточного и/или межпроцессного обмена данными. На выбор - надо быстро - можно быстро (но тут придется самому рулить всеми блокировками скорее всего). Не хочется заморачиваться с блокировками - есть и такое, где всеми блокировками будет рулить сама система.

Понятно, что тут придется немного разобраться как оно работает. Возможно, один раз написать какую-то апишку для работы под свои условия. Но нет там ничего сложного. Не бином Ньютона.

Если б мы писали клиентское ПО (то самое, что обеспечивает пользовательский опыт и помимо UI имеет ответную часть, которая и зовется backend) на C/C++, то банковские продукты были бы до сих пор на уровне 2000-х. А сегодня вы имеете возможность взаимодействовать с банком через приложение в своем телефоне с приятным интерфейсом, в большинстве случаев приятным откликом, ну и достаточно динамично развивающимся.

Все это стало возможно благодаря новым подходам и новым технологиям. А новые подходы и технологии влекут за собой новые вызовы. На тему этих новых вызовов и было выступление.


При использовании Java/C#/Kotlin/Go разработчик в большей степени ориентирован на бизнес-функционал: на доменные сущности, на способ их взаимодействия, на их будущее развитие, помимо своих доменных сущностей необходимо держать в голове еще и сущности из соседних систем. Все это увеличивает когнитивную нагрузку. Поэтому, действительно, в запаре можно забыть проверить переменную на null (а в этих языках компилятор не инициализирует переменные, если они ссылочного типа). Поэтому появились всякие новомодные DDD, микросервисы и иже с ними - эти подходы позволяют снизить когнитивную нагрузку и не сойти с ума.

Опять сравнение по памяти на примере hello world. Может стоит учесть, что в указанное приложение входит куча поддерживающего кода, который по сути fixed cost? В целом какая разница, сколько 'весит' jvm и спринг, если у сервиса например будет хип на 1.5 Гб, а с метаспейсом и прочим - под 2? Или время старта приложения - 3.5 секунды против 1. Да какая разница, если при старте сервис будет что-то из базы качать для инициализации - собирать внутренние кэши или ещё что.

Понятно, что это может быть важно, но сравнивать все же лучше на боевой нагрузке. Либо если нужен супербыстрый старт - использовать другие подходы (но может и действительно не джаву). Просто везде одно и то же - пишем hello world, добавляем в него все стартеры спринга, а потом удивляемся, почему так...

Строго говоря, микросервисы должны быть мелкими в любом отношении. 10 реплик, кушающих по 1 гб памяти и 10 реплик, кушающих по 10 мб - это совсем разные расходы на инфраструктуру

На мой взгляд сомнительно. Любой сервис должен выполнять какую-то законченную бизнес-операцию. Т.е. не просто "дай мне запись из ...", а что-то более серьезное.

Т.е. не размазывать атомарную логику на 10 микросервисов.

Все сервисы, выполняющие небольшую функцию и не находящиеся под большой нагрузкой, но при этом делающие много сетевых запросов, я бы писал на Go.

Выглядит как подходящая работа для NodeJS, плюс к этому (субъективно) разработчиков под Ноду на рынке больше.

А не смотрели профайлером, что именно отжирает СТОЛЬКО памяти в жава-приложении? — детализацию бы глянуть.


Мне это чисто из любопытства, я из.нета, просто поразило НАСКОЛЬКО джава-вариант плох.

Spring boot, просто похоже его не оптимизировали и даже не пытались. Просто захотелось Котлин и go. Если честно я смотрел конференцию онлайн и так и не понял зачем переходить с java на kotlin или go. Просто если своевременно обновлять версии java и spring то всё будет в шоколаде.

А что там в этом spring boot?
Web server, насколько я понял? Ещё что-то "крупное"?

В Райффайзенбанке преимущественно на DotNET пишут. Почему не сравниваете с ним?

Это какой-то странный наброс. И сама отсылка к какой-то конкретной организации выглядит странной, и утверждение не является верным.

println(strLength(!!nullable))

И все же не исправили :) В Kotlin небезопасный "!!" ставится после переменной - nullable!!

В Go возможность создания иммутабельных объектов отсутствует.

Ну почему сразу так радикально?) Она есть, просто с определенной изюминкой

Ничто в тексте не напугало меня больше, чем это "... GraalVM — виртуальная машина, разрабатывающая Oracle..."

Sign up to leave a comment.