Как стать автором
Обновить
25
0
Антон Пантюхин @pananton

Senior C++ backend developer

Отправить сообщение

Вообще мне нравится вариант, который вы скинули с test properties. Я бы его рекомендовал вместо копирования, если бы сегодня писал статью.

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

Я вычислил нечётное совершенное число, но поля хабра слишком узки для него)

Спасибо за отзыв) Вообще я смотрел zeromq, но не помню уж по какой причине не стал его использовать. Возможно, не придумал, как мне там реал-тайм мониторинг и моканье АПИ реализовать более-менее тривиально (а для меня эти возможности критически важными были) и в сжатые сроки, т.к. всю архитектуру: клиентские либы, инфраструктурные инстурменты для разработки и документирования и т.д., я один делал. Ну и конечно не хватало альтернативных мнений)

Про зависимость всей системы от очереди - вы совершенно правы, так и есть) Но я признаться на практике за 15+ лет работы не встречал архитектур, в которых не было хотя бы 1го компонента, при падении которого вся система превращалась в тыкву. Поэтому на первый план выходит то, как быстро вы сможете обнаруживать и реанимировать такие компоненты. Именно по этой причине я топлю в статье за nats, который подкупает максимальной простотой конфигурирования и в хорошем смысле "тупостью" - легко перезапускать. Сравните с каким-нибудь реббитом, который может попасть в сплит-брейн.. Ну и вообще, за 3 года у меня ни разу натс не упал. Не готов рекомендовать свое решение всем подряд, но в моем случае для средней системы с 200к онлайном и 3-4k rps было хорошо, и запас сверху точно был (правда не успел поисследовать, какой в точности).

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

В свою очередь, фундаментальной причиной сложности инфраструктуры является необходимость организовать взаимодействие между микросервисами, которых будет, очевидно, много. А по скольку каждый еще ради ha и масштабирования будет запущен на куче инстансов, итоговое число легко перешагивает за 1к. И все это на фоне того, что микросервис на то и микро, что за значительной частью данных он обращается к множеству других микросервисов.

При этом в большинстве МСА архитектур, развитием которых я занимался, микросервисы для взаимодействия использовали классические подходы, заточенные под p2p модель: REST/HTTP, SOAP, gRPC, тысячи их. Я хочу высказать (очень спорное) предположение, что эти классические решения не годятся для МСА, т.к. они и делают инфраструктуру микросервисного проекта очень сложной, добавляя как минимум такие обязательные компоненты, как:

1 - балансеры, чтобы нагружать кучу инстансов одного сервиса равномерно

2 - service discovery, чтобы вообще найти, куда слать запрос

3 - какие-нибудь аутентифицирующие/авторизующие прокси, которые проверят, что сервисам можно общаться друг с другом

И все это надо поддерживать, своевременно обновлять, и не забываем про безопасность.

В одном из своих старых проектов я попытался побороть эту сложность с помощью организации межсервисного взаимодействия не в p2p формате, а через посредника, в качестве которого использовалась очередь сообщений. Этот формат избавил меня от необходимости тащить какой-то service discovery, т.к. каждый микросервис коннектился только к одному компоненту - очереди сообщений. Балансировка также осуществлялась очередью. Решение получилось не без проблем, конечно: проприетарное и с костылями (т.к. очереди сообщений - это больше про pub/sub, а не request/reply). Но я задумался, что могло бы получится, если бы условный гугл или яндекс предложили что-то вроде grpc через очередь сообщений, со всеми плюшки первого (кодогенерация, code as documentation...) и второго (балансировка, масштабируемость, слабая связность, pub/sub и т.д.).

Я бы посмотрел в области общей алгебры и теории полей. Там исследуются множества с заданной на нем операцией. В этой сфере математики есть понятие фактор-множества, элементами которого являются подмножества исходного множества, которые удовлетворяют условию, что для любых двух элементов А и Б при применении к ним операции получается элемент, также принадлежащий тому же подмножеству.

В контексте рассматриваемого вопроса, операция - это вычисление хэша, а исходное множество состоит из всех битовых последовательностей длиною 256 бит. С точки зрения общей алгебры можно попытаться доказать теорему, чио фактор-множество в этом случае состоит из единственного множества - исходного. Тогда действительно применение операции даст цикл длиной ровно 2^256, это уже общий результат.

Вероятно я где-то что-то напутал, т.к. общую алгебру давно не вспоминал, нов целом как-то так)

Я бы только крайне не рекомендовал в общем случае использовать кафку для RPC. Самой важной метрикой для RPC является низкий и стабильный (без внезапных периодический просадок) latency между вызовом и ответом. Кафка привносит значительный оверхед в случае RPC по сравнению с некоторыми другими очередями. Т.е. в некоторых случаях может и сгодится, но в целом я бы на нее не полагался (поэтому в статье я о ней даже не упоминаю). Лично я использовал nats и с ним не было проблем.

Есть хорошая статья по производительности нескольких очередей сообщений именно в контексте request/response взаимодействия, может вас заинтересует.

мне кажется, велосипед делаете.

Не только вам) Я вот и сам уверен, что велосипед. Создавался он под мои нужды, и свои задачи хорошо решал. Ваши технологии посмотрю, раньше с ними не сталкивался. Там правда похоже все это под Java заточено, а у нас в бэке джава не использовалась, только C++ и Go (причем с перекосом именно в сторону C++). Но вообще на первый взгляд - dubbo это типичное RPC, с service discovery, синхронной моделью взаимодействия и т.д. А меня интересуют решения, которые основаны на использовании очереди в качестве communication layer. Причины я постарался описать в статье, ну и в комментариях много было на эту тему, не буду повторяться.

Ну и жаль, что вы про esb сразу не написали) а то xml, xsd..)

А вот в этой статье сравнили, и там действительно натс и кафка рядом не валялись. Я думаю все-таки для определенных задач одно, для других другое)

Да, в продолжение. Среди вариантов esb есть опен-сорсные и бесплатные?

Вы знаете, звучит как решение. Я посмотрю получше.

А что там по производительности? Знаете, звучит хоть и элегантно, но очень уж массивно. Что если нет бюджета на покупку мощных серверов и каналов? Я работал в проектах, где на ифраструктуру не особо тратились, а нагрузки были вполне себе. Но справлялись, плюсы, асинхронность везде и т.д. Есть может у вас какие-то бенчмарки?

Вы же и сами понимаете, что будет, если шина станет недоступна) кина не будет, все сломалось. Поэтому там обязательно кластер и проверенная технология. Я использовал nats, состоящий из 2х кластеров по 3 ноды в каждом в 2х датацентрах. За 2 года не было ни одной проблемы с ним, даже при обновлении версии натса.

По первому вопросу - ничего не мешает, более того, думаю, что так и надо делать в МСА. Просто я уже где-то выше писал, что так у вас минимум 3 технологии (grpc, очередь, service discovery), а с очередью одна. Ну и многие тривиальные с очередью вещи услодняются с grpc. Как вы посмотрите, с какой именно запрос в grpc пришел? Ивент-то в очереди вы увидете, а вот с запросом будет проблема.

Вообще, идеальная для меня технология была бы комбинация что-то вроде grpc (его idl, генерация классов) и какой-то брокер для всего этого, чтобы grpc через очередь работал, с ее возможностями (мониторинг траффика, подписка на подмножество сообщений, нативная модель pub-sub). Но я такого не знаю.

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

В случае с JetStream все скорее всего посложнее, так как там уже есть мастер нода и всякий Raft для консенсуса. Тут не подскажу.

Ну и есть один момент, по которому я создавал issue в их репозитории, но не помню, исправили они что-то или нет. Смотрите, клиенты обычно скофигурированы так, чтобы рандомно выбирать ноду кластер, куда коннектиться. Получается, что во время работы кластера у нас примерно по N клиентов на каждой ноде. Потом вы начинаете рестарт кластера. Останавливаете одну ноду, и все ее N клиентов переходят на 2 оставшиеся (предположим, что 3 ноды в кластере). Потом нода поднимается, на ней 0 клиентов, на других 1.5N. Думаю, идея понятна, когда вы закончите, у вас на одной ноде будет 0 клиентов, на другой 1/3, и еще на одной 2/3 (посчитайте сами). Но повторюсь, возможно, с этим уже что-то сделано.

Снова, немного не так. Сircuit break про отключение при перегрузки, но не только сервиса, а желательно клиента - источника проблемы. \

Вы что-то путаете, может с flow control (текущее ведро и т.д.), может с чем-то другим. Circuit breaker это в точности то (за исключением некоторых параметров алгоритма), что описано.

Но менять rpc + service discovery (один сервис-брокер), на корутины + callback (в каждом вызове), и агитировать за простоту?

Это вынужденное усложенение. Не всем подходят синхронная модель взаимодействие поверх пула потоков. Максимальная производительность достигается на ивент лупах, где асинхронность идет с самого низа (с сокетов). При этом там один поток (чтобы не делать лишние локи, добиться максимальной локальности кэша процессора и т.д.), и производительность (как по latency, так и по общему throughput) - значительно выше. А корутины кстати как раз избавляют от колбеков, делая код визуально приятнее.

Багфикс распределенной системы сложнее, чем монолита!

Если где-то показалось, что я считаю наоборот, то приношу извинения. С этим согласен.

)) Да я там уже полгода не работаю, вроде справляются)

Вообще, я подозреваю, что туманно предназначение типов вроде MethodDesc и аналогичных. Не буду скрывать, это все для того, чтобы сделать библиотеку для C++ в том виде, что представлен выше. Специфика языка, что поделать - нет там интроспекции из коробки. Вероятно для большинства других ЯП, такие типы будут излишни.

Для начала про WSDL. Мои знания о нем ограничиваются тем, что его типовое использование заключается в описании API некоторого веб-сервиса, из которого потом можно сгенерировать сущности на целевом ЯП, которые предоставляют интерфейс для установки параметров вызова, а также для отправки вызова на какой-то сервис по HTTP, SOAP или чему-то еще. При этом общение между клиентом и сервером будет организовано через прямой коннект между ними. По причинам, которые я описывал в статье и уже много раз повторял в комментариях, я видел плюсы от использования очереди сообщений в качестве backbone для своего бэка. Вы в праве не разделять эти ценности, считать их надуманными и т.д., тогда для мысленного эксперимента примите их как мою блажь - сейчас не об этом, как вы сами сказали) В связи с этим возникает вопрос, что мне даст wsdl в этом случае? Зачем мне его обертки, если мне надо отправить не на сервис по HTTP/SOAP, а в некую очередь по ее собственному протоколу? Ну наверняка как-то можно замапить одно на другое, и вы полагаете, что это не будет кондово? В любом случае получается, что инструмент, заточенный под конкретный вид использования я колхозю под непонятно что. Вероятно, вы лучше меня знакомы с WSDL и чаще его использовали, поэтому я и просил чуть большей конкретики.

Если бы существовала очередь сообщений, которая позволяет описать некоторый API на каком-то IDL и потом сгенерировать для него типы, я бы конечно вероятно ее бы и использовал, но мне такая неизвестна.

Собственно в Си нужно всего лишь подключить библиотеку, которая отправляет и получает соответствующий XML на/с соответствующего адреса. Всё есть уже готовое, зачем велосипед?

Теперь про это. Да, можно описать все те же сущности на XML. Т.е. убрать вообще WSDL, оставить голый XML и сериализовать/десериализовать его. Библиотек для работы с XML пруд-пруди на любой ЯП. Не знаю, обратили ли вы внимание, но в протабаф я использую кастомные протабаф опции для выражения своих каких-то концепций (observable параметры, например, по которым можно подписываться только на подмножество вызовов метода, имеющее определенное значение этого параметра). Потом компилятор protoc добавляет эти опции к генерируемым типам, и я могу их обработать в недрах своих библиотек. Убежден, что при использовании XML эти концепции можно выразить в XSD, про который вы тоже говорили. Согласен, что это должно сработать, и мне это в свое время в голову не пришло, так я бы пристальнее посмотрел на этот вариант. Но формально - это просто другой формат. Да, использовав его, мне бы скорее всего не пришлось писать свой инструмент для генерации документации из файлов протокола, нашелся бы какой-нибудь сторонний. Но основную часть работы по-прежнему пришлось бы проделать вручную: библиотеки, которые оборачивают все эти XML/XSD в удобные интерфейсы, клиенты, которым можно сказать "вот вызови-ка метод/процедуру, описываемую вот этой XSD и используя вот эти параметры в виде XML". И в этой схеме также возникнет потребность как-то структурировать эти XML/XSD, хранить, проверять на то, что кто-то не наломал в них дров в том или ином виде, что тоже может начать смахивать на велосипед. Кстати, раз уж на то пошло, для протобафа тоже есть свои инструменты по генерации документации из proto файлов. Я предпочел написать свой, чтобы добавить полезные для меня документирующие команды и возвращать документацию в формате, учитывающим специфику платформы.

Вообще, вы не могли бы сказать, какой ваш основной ЯП? Мне важен фидбэк именно от людей с другим технологическим стеком, чем мой.

Хотя один ответ вы старательно обходите стороной - личные предпочтения. На самом деле не стоит прятать такой мотив, особенно если других не видно.

И в мыслях не было ничего прятать. Говорю как на духу - я отлично знаю протабаф, очереди сообщений (особенно NATS), С++. Более того, я люблю эти инструменты, умею использовать их сильные стороны и нивелировать слабые. Было бы странно, если бы я в проекте, который определяет вообще весь путь развития бэка, решил использовать инструмент, которым я пользуюсь раз в год. Теперь же проект вышел из частного использования, поэтому нужно посмотреть, чем остальные дышат, так сказать)

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

Давайте я в не знаю, какой раз повторю, что идея - в использовании шины сообщений для RPC. В том, чтобы сервисы не общались напрямую, как принято в grpc, SOAP, json-rpc, REST, тысячи их. Какие из этого плюсы - описано в статье, да и в комментариях много про это уже сказано. Можно ли их добиться в более традиционных архитектурах - можно, но как правило сложнее (естественно, какие-то другие вещи там будут проще, да).

Да там особенностей изначально-то особо и не было) Он фундаментально очень прост: пришло сообщение, если кто-то слушает, отправил дальше. Если нет, сразу отбросил. Причем года полтора назад, они и никакой ошибки, что никто не слушает, не отправляли. Было проблематично организовывать request-reply, потому что если принимающая сторона отсутствовала, request по таймауту только завершался.

Сейчас есть у них движок jetstream, который превращает натс в а-ля кафку. Про него не расскажу, не использовал.

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

Информация

В рейтинге
Не участвует
Откуда
Томск, Томская обл., Россия
Дата рождения
Зарегистрирован
Активность

Специализация

Backend Developer
Lead
C++
Database
NoSQL
Docker
Designing application architecture
Cross Platform Development
Algorithms and data structures
Maths