Помогите правильно спроектировать микросервисное приложение
От: busk  
Дата: 20.03.25 14:46
Оценка:
Привет всем.
Как-то только в теории читал про микросервисы, но вот новый проект планируется небольшой и хотел как раз попробовать микросервисы тут.

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


Второе и собственно основное я так понял из книг, что самое сложное это определить границы сервисов. Вот прошу тут помощи как нарезать на сервисы и базы?

Приложение: — Система контроля доставок грузов в разных странах (стран 10).
— Юзеры заходят по user/pswd и система определяет страну и подгружает данные этой страны. Новый юзер сам может зарегаться по логину выданному ему и восстановить пароль.
— В системе будет 4 роли: sysadmin, admin, manager, driver. В каждой стране свои пользователи. Один пользователь = 1 страна.
— Сами заказы поступают в эту систему из другой. В этой надо только мониторить и делать разные действия если доставка задержалась или не приехала.
— В каждой стране много складов и поэтому когда заказы поступают в систему то они сразу попадают на нужный склад и спец алгоритм распределяет на водителей.

— sysadmin управляет только техническими настройками разными (кому когда отчеты отсылать, как в системе заводить оптуска, сколько часов в сутки можно работать, заводит праздники), остальное всё только в режиме просмотра видит.
— admin видит всё, не может только технические настройки менять. Следит за водителями, чтобы они всрок доставляли всё — по юаю специальному, вносит отпуска, больничные их, ставит им рабочее время. Если водитель увольняется — удаляет изи системы.
— manager следит за водителями своего склада только, может посмотреть по всем своим водителям информацию и по всем доставкам, но менять не может
— driver видит только по себе все сделанные доставки и предстоящие. Каждый раз когда он начинает и заканчивает доставку то в системе нажимает Start delivery\End delivery. Если доставка не укладывается в
предполагаемые сроки то пишет к доставке комментарий почему не успел


Итого что по функционалу:
Sysadmin — логин в систему, управление настройками, праздниками и просмотр всего.
Admin — логин в систему, cледит за водителями, чтобы они всрок доставляли всё, вносит отпуска, больничные их, ставит им рабочее время. Если водитель увольняется — удаляет изи системы.
Manager логин в систему, следит за водителями своего склада только, может посмотреть по всем своим водителям информацию и по всем доставкам
Driver логин в систему, видит только по себе все сделанные доставки и предстоящие. Каждый раз когда он начинает и заканчивает доставку то в системе нажимает Start delivery\End delivery. Если доставка не укладывается в
предполагаемые сроки то пишет к доставке комментарий почему не успел


Третий вопрос. Если без докеров то как настроить этот набор микросервисов? тут их немного будет и читал что можно настроить без докер контейнеров если что.
Re: Помогите правильно спроектировать микросервисное приложение
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 20.03.25 15:32
Оценка: +5 :)
Здравствуйте, busk, Вы писали:

B>Как-то только в теории читал про микросервисы, но вот новый проект планируется небольшой и хотел как раз попробовать микросервисы тут.

Не надо, оно тебя сожрет
Re[2]: Помогите правильно спроектировать микросервисное приложение
От: busk  
Дата: 20.03.25 15:34
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, busk, Вы писали:


B>>Как-то только в теории читал про микросервисы, но вот новый проект планируется небольшой и хотел как раз попробовать микросервисы тут.

G>Не надо, оно тебя сожрет

поясни пожалуйста подробней. а то смотришь тот же Яндекс, у них везде микросервисы + ci/cd
Re: Помогите правильно спроектировать микросервисное приложение
От: DiPaolo Россия  
Дата: 20.03.25 15:40
Оценка: 2 (1)
Выглядит так, что тут вкореживать (именно так) микросервисы – дороже выйдет. Ну вообще никак они тут не просматриваются. Очень маленький набор сущностей и функционала. Элементарно нечего пилить

Опять же, если это все без кубера делать, то жди беды и геморроя Так что не стоит

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

Тогда может и будет понимание, где надо (и зачем!), а где не надо впихивать микросервисы. Ну и про кубер придет понимание, что этим зоопарком баз и сервисов как-то надо рулить. И как замечательно можно скейлить отдельные куски системы по необходимости
Патриот здравого смысла
Re: Помогите правильно спроектировать микросервисное приложение
От: Miroff Россия  
Дата: 20.03.25 15:42
Оценка: +1
Здравствуйте, busk, Вы писали:

B>Тут я понимаю, что проще было бы сделать монолит, но для обучения вполне годный вариант?


А у вас ресурсы-то на микросервисы есть? На тот же K8S и CI/CD хотя бы.

B>Второе и собственно основное я так понял из книг, что самое сложное это определить границы сервисов. Вот прошу тут помощи как нарезать на сервисы и базы?


Это самое простое. Делить нужно по бизнес-домену (мыши и кактусы отдельно, марксизм и диамат отдельно), по технологиям (ML на питоне, интеграция с внешними сервисами на Scala, интерфейс к БД на сишарпе), требованиям к масштабированию (фронтофисом пользуется вся страна, а бэкофисом 20 человек), надежности (если отчеты упадут об этом узнают через месяц, а если торговый робот упадет, компания обанкротится за 5 минут). Если ничего этого нет, микросервисы не нужны.

B>Третий вопрос. Если без докеров то как настроить этот набор микросервисов? тут их немного будет и читал что можно настроить без докер контейнеров если что.


Можно, только это очень дорого и даже Яндекс себе такого не может позволить.
Re[2]: Помогите правильно спроектировать микросервисное приложение
От: busk  
Дата: 21.03.25 04:18
Оценка:
Здравствуйте, Miroff, Вы писали:

M>Здравствуйте, busk, Вы писали:


B>>Тут я понимаю, что проще было бы сделать монолит, но для обучения вполне годный вариант?


M>А у вас ресурсы-то на микросервисы есть? На тот же K8S и CI/CD хотя бы.


я планировал без кубера, читал так можно. Ниже написал модель какую думал. ci/cd у нас есть на другом сервере и думал туда добавить билд нового проекта.
а кубер реально много ресурсов требует дополнительно? я думал он просто как failover service


B>>Второе и собственно основное я так понял из книг, что самое сложное это определить границы сервисов. Вот прошу тут помощи как нарезать на сервисы и базы?


M>Это самое простое. Делить нужно по бизнес-домену (мыши и кактусы отдельно, марксизм и диамат отдельно), по технологиям (ML на питоне, интеграция с внешними сервисами на Scala, интерфейс к БД на сишарпе), требованиям к масштабированию (фронтофисом пользуется вся страна, а бэкофисом 20 человек), надежности (если отчеты упадут об этом узнают через месяц, а если торговый робот упадет, компания обанкротится за 5 минут). Если ничего этого нет, микросервисы не нужны.


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

B>>Третий вопрос. Если без докеров то как настроить этот набор микросервисов? тут их немного будет и читал что можно настроить без докер контейнеров если что.


M>Можно, только это очень дорого и даже Яндекс себе такого не может позволить.


а почему дорого? я так понял просто каждый сервис — отдельный апп в веб сервере и есть шлюз приложение которое регулирует и каждая база на свой сервис.
Re[2]: Помогите правильно спроектировать микросервисное приложение
От: busk  
Дата: 21.03.25 04:37
Оценка:
Здравствуйте, DiPaolo, Вы писали:

DP>Выглядит так, что тут вкореживать (именно так) микросервисы – дороже выйдет. Ну вообще никак они тут не просматриваются. Очень маленький набор сущностей и функционала. Элементарно нечего пилить


DP>Опять же, если это все без кубера делать, то жди беды и геморроя Так что не стоит


DP>Потренироваться можно на пет-проекте. Самому придумать и написать что-то несложное. Один микросервис отдает погоду, второй загруженность дорог. Третий все это забирает и что-то отдает наружу. Плюс отдельный микросервис принимают от пользователей какие-то данные. Тут же добавить кэши, обратный прокси. можно потом с лоад балансером поиграться. Каждый сервис пусть по базе имеет. Сделать несколько инстансов каждого микросервиса. Ну и так далее...


DP>Тогда может и будет понимание, где надо (и зачем!), а где не надо впихивать микросервисы. Ну и про кубер придет понимание, что этим зоопарком баз и сервисов как-то надо рулить. И как замечательно можно скейлить отдельные куски системы по необходимости


Понял, спасибо. Монолит тогда сделаю.

А так вот, чисто для развития и понимания в реальных приложениях, подскажи пожалуйста как тут нарезать сервисы?

дополнительно. Еще будет 3 сервиса на питоне: один будет из 1с качать информацию по отпускам, болничным, один будет также из 1с качать новых сотрудников.

я правильно понимаю: сервис аутенфикации, сервис получения заказов со статусами по дням, сервис настроек и сервис сотрудников (где можно им выставлять рабочее время, заводить отгулы, удалять их если они уволились)
Re[3]: Помогите правильно спроектировать микросервисное приложение
От: DiPaolo Россия  
Дата: 21.03.25 05:11
Оценка:
B>А так вот, чисто для развития и понимания в реальных приложениях, подскажи пожалуйста как тут нарезать сервисы?
Да вот именно, что сложно их как-то нарезать. Как коллега правильно заметил, есть несколько вариантов нарезки, и ни один из них сюда не подходит.

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

Именно тут я бы не стал делить. А для практики придумал другой сервис, где нарезка имеет больший смысл.

B>дополнительно. Еще будет 3 сервиса на питоне: один будет из 1с качать информацию по отпускам, болничным, один будет также из 1с качать новых сотрудников.


Все что с 1С лучше вынести в один сервис (адаптер для интеграции со сторонним сервисом). Тем самым вся логика работы с конкретной сторонней системой будет сосредоточена в одном месте и будет инкапсулировать все что касается работы с этим сервисом. А наружу давать уже обработанные данные в форматах и сущностях, с коротким работает ваша система.

B>я правильно понимаю: сервис аутенфикации, сервис получения заказов со статусами по дням, сервис настроек и сервис сотрудников (где можно им выставлять рабочее время, заводить отгулы, удалять их если они уволились)


Я бы сделал так:
— основной бэк (заказы, настройки, сотрудники)
— сервис аутентификации (в вашем случае это тоже лишнее — выносить в отдельный микросервис; но пусть, так часто делают, когда микросервисов много и/или есть SSO)
— сервис для работы с 1С
Патриот здравого смысла
Re: Помогите правильно спроектировать микросервисное приложение
От: DiPaolo Россия  
Дата: 21.03.25 05:17
Оценка:
B>Третий вопрос. Если без докеров то как настроить этот набор микросервисов? тут их немного будет и читал что можно настроить без докер контейнеров если что.

Что касается докера и кубера... это хорошая идея – начать без них. Тогда чуть позже придет понимание исходя из реальных потребностей, зачем один и второй нужен.

Сделать можно так: скрипт, который запускает все сервисы + СУБД должна быть запущена (ее проще всего поднять в докере как раз) и базы созданы.

При этом надо продумать: а как определять, что тот или иной сервис упал/недоступен?

Далее, если понадобится вторая машина, тут встанет тоже вопрос, как с этим управляться.

Ну и дальше будет постепенно приходить понимание, зачем кубер и прочее.

Кстати, кубер сразу не стоит брать. Достаточно будет привнести докеры, а потом Docker compose. Этого хватит. А уже потом – кубер.
Патриот здравого смысла
Re[2]: Помогите правильно спроектировать микросервисное приложение
От: busk  
Дата: 21.03.25 07:32
Оценка:
Здравствуйте, DiPaolo, Вы писали:

B>>Третий вопрос. Если без докеров то как настроить этот набор микросервисов? тут их немного будет и читал что можно настроить без докер контейнеров если что.


DP>Что касается докера и кубера... это хорошая идея – начать без них. Тогда чуть позже придет понимание исходя из реальных потребностей, зачем один и второй нужен.



а я кстати тут вот понял, что без кубера и докера у меня бы точно были проблемы. Читал, что вроде нормально это всё под линухом работает.
а у меня на проде венда + mssql.

За советы спасибо!

видимо, да, домашний проект надо под линукс + postrges
Re[3]: Помогите правильно спроектировать микросервисное приложение
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 21.03.25 08:08
Оценка: +1
Здравствуйте, busk, Вы писали:

B>Здравствуйте, gandjustas, Вы писали:


G>>Здравствуйте, busk, Вы писали:


B>>>Как-то только в теории читал про микросервисы, но вот новый проект планируется небольшой и хотел как раз попробовать микросервисы тут.

G>>Не надо, оно тебя сожрет

B>поясни пожалуйста подробней. а то смотришь тот же Яндекс, у них везде микросервисы + ci/cd


1) Ты не яндекс, даже на 1% не яндекс, и никогда яндексом не станешь
2) яндекс на старте не был микросервисным
3) cd\cd без микросервисов работает лучше
Re[4]: Помогите правильно спроектировать микросервисное приложение
От: busk  
Дата: 21.03.25 08:25
Оценка:
Здравствуйте, gandjustas, Вы писали:


G>2) яндекс на старте не был микросервисным


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

G>3) cd\cd без микросервисов работает лучше


звучит что микросервисы удел либо больших компаний либо крупных систем.
Re: Помогите правильно спроектировать микросервисное приложение
От: bnk СССР http://unmanagedvisio.com/
Дата: 21.03.25 09:41
Оценка: +1
Здравствуйте, busk, Вы писали:

B>Второе и собственно основное я так понял из книг, что самое сложное это определить границы сервисов. Вот прошу тут помощи как нарезать на сервисы и базы?


Они проходят по границам команды. Одна команда — один микросервис.
Re[3]: Помогите правильно спроектировать микросервисное приложение
От: Miroff Россия  
Дата: 21.03.25 11:23
Оценка:
Здравствуйте, busk, Вы писали:

B>я планировал без кубера, читал так можно. Ниже написал модель какую думал. ci/cd у нас есть на другом сервере и думал туда добавить билд нового проекта.


Можно, но микросервисы плохо работают без полноценного CD. Релизить руками умаешься.

B>а кубер реально много ресурсов требует дополнительно? я думал он просто как failover service


Ресурсов в смысле админа, который умеет k8s поднять и способен его настроить. Там же не один k8s, а еще сбор логов, CD пайплайны, мониторинг и т.п.

B>Но я так понял что поддержка и настройка микросервисов дело хлопотное и надо делать в кубере, а если без опыта то времени на изучение и настройку уйдет с неделю точно.


Микросервисы позволяют пернести часть сложности из приложения в оркестрацию. Это сильно упрощает разработку, когда у тебя в сервисе меньше 10к строк и один разработчик. Нет ни мердж конфликтов, не нужно ни с кем договариваться, не нужна документация, планирование, архитектура. Выставляешь Restful API и проблема других сервисов как этим API воспользоваться. Если в проекте энфорсится RMM level 3 и стопроцентная обратная совместимость, можно делать проекты на 1000 человеко-лет с минимальным оверхедом. За это приходится расплачиваться необходимостью контроллировать сложность взаимодействия. Вплоть до экономических механизмов, когда каждая команда платит за ресурсы потребленные их микросервисами в облаке.

B>а почему дорого?


Потому что k8s и docker сейчас умеют даже студенты, а для рукопашного CD нужны крайне продвинутые админы, умеющего автоматизировать развертывание каким-нибудь Chef или Puppet. Даже когда Chef был на пике моды, таких были единицы.

B>я так понял просто каждый сервис — отдельный апп в веб сервере и есть шлюз приложение которое регулирует и каждая база на свой

сервис.

Тогда не получится ни масштабирования, ни rolling updates без даунтайма, ни надежности. Непонятно зачем тогда вообще микросервисы?
Re: Помогите правильно спроектировать микросервисное приложение
От: Qulac Россия  
Дата: 21.03.25 12:43
Оценка:
Здравствуйте, busk, Вы писали:

B>Привет всем.

B>Как-то только в теории читал про микросервисы, но вот новый проект планируется небольшой и хотел как раз попробовать микросервисы тут.

Я потренировался бы сначала, прежде чем делать реальный проект на микросервисах или в крайнем случае вывел бы в сервисы какую ни будь не критичную часть функционала, типа хранения разных типов уведомлений для пользователей.
Программа – это мысли спрессованные в код
Re: Помогите правильно спроектировать микросервисное приложение
От: SkyDance Земля  
Дата: 21.03.25 17:09
Оценка:
B>самое сложное это определить границы сервисов. Вот прошу тут помощи как нарезать на сервисы и базы?

Это как раз самое простое. Границы определяются orgchart — "организационной диаграммой". Иными словами, разделением ответственности по принципу "если это делает другая команда, это другой сервис".

Все остальные разделения рано или поздно скатятся во все ту же диаграмму подчинения.

PS: не видел еще ни одного продукта с микросервисной архитектурой который бы не скатился именно в этот принцип разделения. Во многих случаях разделение идет дальше (вплоть до того, что каждому программисту — по микросервису, а то и два-три), но в этом случае нередок обратный процесс помещения нескольких микросервисов внутрь единого огромного бинарника (привет фейсбуку).
Re: Помогите правильно спроектировать микросервисное приложение
От: L_G Россия  
Дата: 22.03.25 13:17
Оценка:
Даже подразумевая, что всё это делается лишь для тренировки/обучения и не более —
больше, чем на две базы данных описанное разделить крайне трудно. Получается 1) аутентификация и авторизация 2) всё остальное.
Тем более, сервис аутентификации и авторизации вполне логично сделать централизованным (общим на весь корпоративный зоопарк приложений).
А сервисов больше, чем баз делать может иметь смысл только когда их реально делают разные команды (я не про экземпляры одинаковых).
Думаю, и 2 сервисов должно вполне хватить для отработки основных навыков.
Каша в голове — пища для ума (с)
Re: Помогите правильно спроектировать микросервисное приложение
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 22.03.25 23:52
Оценка: 9 (1)
Здравствуйте, busk, Вы писали:

B>Как-то только в теории читал про микросервисы, но вот новый проект планируется небольшой и хотел как раз попробовать микросервисы тут.

Если это реальный проект за деньги, то лучшее делать его на базе известных подходов, например монолит на базе хексогональной архитектуры.
B>Первое что хотел сказать, что везде пишут микросервисы это где много команд часто или много функционала.
Это не основное их назначение. В монолите точно также можно делить всё на разные компоненты между командами.
B>но зато скоп определен четко и подумал прекрасная возможность потренироваться, чтобы потом уверенее пробовать в большом проекте.
Проект, честно скажем, небольшой.
B>Итого что по функционалу:
Ты забыл внешние системы такие как 1С и систему-поставщика заказов.

B>Третий вопрос. Если без докеров то как настроить этот набор микросервисов?

Это будет сложно. Можно на этом проекте поизучать контейнеризацию на базе докера и засунуть свой монолит и базу в отдельные контейнеры, настроить между ними сетевую связанность и подключить хранилища, подумать как будешь делать бэкап этой базы.
Для микросервисной архитектуры нужно ещё продумывать системный дизайн и процесс деплоя.
Sic luceat lux!
Re[3]: Помогите правильно спроектировать микросервисное приложение
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.03.25 03:01
Оценка:
Здравствуйте, busk, Вы писали:

G>>Не надо, оно тебя сожрет


B>поясни пожалуйста подробней. а то смотришь тот же Яндекс, у них везде микросервисы + ci/cd


В том же яндексе в каждом микросервисе ад и Израиль, оно тебе надо?
Маньяк Робокряк колесит по городу
Re[5]: Помогите правильно спроектировать микросервисное приложение
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.03.25 03:04
Оценка:
Здравствуйте, busk, Вы писали:

B>звучит что микросервисы удел либо больших компаний либо крупных систем.


Монолит в одно жало/одной командой пилить гораздо проще.

Когда дорастёшь до того, что начнут возникать проблемы с монолитом — ты уже будешь нанимать программистов по 500 рублей и на архитектуру (монолит/микросервисы) тебе уже будет начхать
Маньяк Робокряк колесит по городу
Re[3]: Помогите правильно спроектировать микросервисное приложение
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.03.25 03:08
Оценка:
Здравствуйте, busk, Вы писали:

B>а я кстати тут вот понял, что без кубера и докера у меня бы точно были проблемы. Читал, что вроде нормально это всё под линухом работает.

B>а у меня на проде венда + mssql.

Докер под виндой десяткой вроде работает без проблем
Маньяк Робокряк колесит по городу
Re[4]: Помогите правильно спроектировать микросервисное приложение
От: m2user  
Дата: 23.03.25 07:31
Оценка:
M>Это сильно упрощает разработку, когда у тебя в сервисе меньше 10к строк и один разработчик.
M>Нет ни мердж конфликтов,

+1

M>не нужно ни с кем договариваться, не нужна документация,


Как минимум нужно предоставить документацию на API и получить feedback

M> планирование, архитектура.


слабо верится, и над архитектурой нужно тоже думать, и планировать (хотя бы по срокам имплементации этого самого API)

M> За это приходится расплачиваться необходимостью контроллировать сложность взаимодействия. Вплоть до экономических механизмов, когда каждая команда платит за ресурсы потребленные их микросервисами в облаке.


Так это вроде и без микросервисов всегда так было. Есть проблемы с производительностью — отвечает автор кода, являющегося узким местом.
Re[5]: Помогите правильно спроектировать микросервисное приложение
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 23.03.25 17:14
Оценка: +5
Здравствуйте, busk, Вы писали:

B>Здравствуйте, gandjustas, Вы писали:



G>>2) яндекс на старте не был микросервисным


B>ну вот да, книжку читал и пишут, что большие проекты часто вначале делают монолитом, когда еще не всё ясно и четко по логике и потом типа уже распиливают на микросервисы.

И вообще не факт что это надо делать.


G>>3) cd\cd без микросервисов работает лучше

B>звучит что микросервисы удел либо больших компаний либо крупных систем.

Основная проблема в том, что MSA несет очень большие накладные расходы. Как по времени разработки, так и по железным ресурсам. Если пытаться оценить в деньгах MSA против монолита, то последний почти гарантированно победит.

Поэтому MSA это техническое решение, а организационное. Если у вас много команд, каждая со своим подходом, технологическим стеком, архитектурой итд, то подружить их в рамках монолитного приложения будет технически невозможно.
Даже если все команды придерживаются одного стека и архитектуры, но у каждой свой график релизов, то в рамках монолита им может быть сложно взаимодействовать. Ведь релиз монолита накатывается и откатывается целиком. Если одна команда пытается стабилизировать, а вторая активно пилит новый функционал, то они будут друг другу мешать.

В этом случае может быть выгодно иметь микросервисы как раз по границам команд. Других адекватных причин использовать MSA я не видел.
Re[5]: Каких программ вам не хватает?
От: Miroff Россия  
Дата: 24.03.25 14:35
Оценка:
Здравствуйте, m2user, Вы писали:

M>Как минимум нужно предоставить документацию на API и получить feedback


Прелесть RMM L3 в том, что он самодокументируемый и на 99% фидбека можно сразу отвечать: "это не RESTful, мы этого делать не будем"

M>слабо верится, и над архитектурой нужно тоже думать, и планировать (хотя бы по срокам имплементации этого самого API)


Так RMM L3 однозначный, там не над чем думать. Размышлений требует дефиниция ресурсов, но она в 90% случаев типовая и там опять же думать не над чем.

M>Так это вроде и без микросервисов всегда так было. Есть проблемы с производительностью — отвечает автор кода, являющегося узким местом.


Это вопрос не производительности, а потребляемых ресурсов. Микросервис суперпросто поднять, но суперсложно удалить. Например, компания, которая ввела внутренний биллинг, обнаружила себя тратящей несколько десятков миллионов в месяц на порядка тысячи микросервисов, которые непонятно кто и с какой целью поднял. Причем административными средствами проблема не решалась, потому что всегда оказывалось что микросервис поднял Вася пять лет назад для проекта X и за 5 лет Вася уволился, проект X влили в проект Y, который заменили на проект Z, в процессе два раза сменив команду и три раза сделав пивот на 180 градусов. И теперь концов уже не найти, нужен ли этот сервис СЕЙЧАС и если нужен, то ДЛЯ ЧЕГО.
Re[6]: Каких программ вам не хватает?
От: RushDevion Россия  
Дата: 24.03.25 18:32
Оценка:
M>Прелесть RMM L3 в том, что он самодокументируемый и на 99% фидбека можно сразу отвечать: "это не RESTful, мы этого делать не будем"

Чисто для общего развития.
RMM L3 — это когда, получив первый ресурс, мы по link/rel определяем, что с ним дальше можно сделать (и на какие url слать соответствующие запросы), так ведь?

Можно пример какого-нибудь публичного REST API, которое именно классический RMM L3 (т.е. не Graph QL и т.п.)?

Просто в моей микросервисной практике все попытки внедрить hypermedia в конечном итоге скатывались либо в полноценную Open API/Swagger спеку, либо в Graph QL, либо в текстовую документацию.
Отредактировано 24.03.2025 21:02 RushDevion . Предыдущая версия . Еще …
Отредактировано 24.03.2025 18:49 RushDevion . Предыдущая версия .
Re[7]: Каких программ вам не хватает?
От: Miroff Россия  
Дата: 25.03.25 01:30
Оценка:
Здравствуйте, RushDevion, Вы писали:

RD>RMM L3 — это когда, получив первый ресурс, мы по link/rel определяем, что с ним дальше можно сделать (и на какие url слать соответствующие запросы), так ведь?


Да, но не только. Это как с третьей нормальной формой, RMM L3, это RMM L2 + HATEOAS. В первую очередь хорошее API обеспечивается правильным разделением на ресурсы, с которыми можно оперировать с помощью HTTP глаголов. HATEOAS на это просто очень удачно ложится и позволяет не размывать логику между клиентом и сервером.

RD>Можно пример какого-нибудь публичного REST API, которое именно классический RMM L3 (т.е. не Graph QL и т.п.)?


PayPal API

RD>Просто в моей микросервисной практике все попытки внедрить hypermedia в конечном итоге скатывались либо в полноценную Open API/Swagger спеку, либо в Graph QL, либо в текстовую документацию.


HATEOAS не отменяет сваггера. Все равно нужно описывать семантику полей и действий.
Re[6]: Помогите правильно спроектировать микросервисное приложение
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.25 05:50
Оценка: +2
Здравствуйте, gandjustas, Вы писали:

G>В этом случае может быть выгодно иметь микросервисы как раз по границам команд. Других адекватных причин использовать MSA я не видел.


Ну ещё ограничить failure domain. Чтобы бага в одном углу приложения клала его не целиком, а только блокировала отдельные сценарии.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.25 06:07
Оценка: +2
Здравствуйте, Miroff, Вы писали:

M>Здравствуйте, RushDevion, Вы писали:


RD>>RMM L3 — это когда, получив первый ресурс, мы по link/rel определяем, что с ним дальше можно сделать (и на какие url слать соответствующие запросы), так ведь?


M>Да, но не только. Это как с третьей нормальной формой, RMM L3, это RMM L2 + HATEOAS. В первую очередь хорошее API обеспечивается правильным разделением на ресурсы, с которыми можно оперировать с помощью HTTP глаголов. HATEOAS на это просто очень удачно ложится и позволяет не размывать логику между клиентом и сервером.

Я не вижу каких-то прямо практически значимых преимуществ HATEOAS.
1. Discoverability немножко улучшается, но не очень значительно. Вот мы дёрнули какой-то ресурс GET-ом. Он прислал нам
— набор ссылок на объекты внутри своих свойств (типа "owner": "https://our-api-enpdoint/users/23412312-ws-44"}
— набор ссылок на "глаголы" в коллекции links (типа {"href": "https://api-m.paypal.com/v1/payments/sale/36C38912MN9658832/refund","rel": "refund","method": "POST"})
Дальше что? Всё равно, без чтения документации невозможно понять,
— можно ли в качестве owner использовать URL юзер-аккаунта в другом скоупе
— что делает глагол refund, и какие у него будут параметры, и где их брать
2. Evolvability улучшается крайне незначительно. У нас нет никакого способа научить клиентов всегда ходить только по указанным нами ссылкам. Если мы решили перенести endpoint для рефандов в другое место, то недостаточно просто отдавать новую ссылку в links. Примерно 99% разработчиков клиента зашьют логику генерации ссылки в своё приложение, вместо того, чтобы прикапывать URL для каждого платежа в своей системе (и тратить место; и опять же рисковать пойти по устаревшей ссылке) или там бегать всякий раз делать GET и искать этот ./links[@rel=refund] (и увеличивать нагрузку на сеть и латентность своих сервисов). Нам так или иначе придётся до каждого из них дойти и убедиться, что они переписали своё приложение
3. Накладные расходы значительно увеличиваются. Там, где в RMM L2 мы обходились GUID-ом, а то и вообще int-ом, теперь мы тащим длиннюшие урлы с совершенно бесполезными обрамлениями. Можно немножко починить это путём компрессии реквестов и респонсов, но всё равно — растёт allocation size для каждого запроса, учащаются сборки мусора, снижается общая эффективность, повышается расход электроэнергии.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Помогите правильно спроектировать микросервисное приложение
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.25 06:34
Оценка: 32 (3) +2
Здравствуйте, busk, Вы писали:
B>Первое что хотел сказать, что везде пишут микросервисы это где много команд часто или много функционала. В этом проекте ни того ни другого не будет,
B>но зато скоп определен четко и подумал прекрасная возможность потренироваться, чтобы потом уверенее пробовать в большом проекте.
Это — хорошая идея.
B>Тут я понимаю, что проще было бы сделать монолит, но для обучения вполне годный вариант?
Да, проще. Да, годный — невозможно сходу научиться резать монолит на микросервисы так, чтобы не стало хуже, чем было.

B>Второе и собственно основное я так понял из книг, что самое сложное это определить границы сервисов.

Да, совершенно точно.

B>Вот прошу тут помощи как нарезать на сервисы и базы?


B>Приложение: — Система контроля доставок грузов в разных странах (стран 10).

B> — Юзеры заходят по user/pswd и система определяет страну и подгружает данные этой страны. Новый юзер сам может зарегаться по логину выданному ему и восстановить пароль.
B> — В системе будет 4 роли: sysadmin, admin, manager, driver. В каждой стране свои пользователи. Один пользователь = 1 страна.
B> — Сами заказы поступают в эту систему из другой. В этой надо только мониторить и делать разные действия если доставка задержалась или не приехала.
B> — В каждой стране много складов и поэтому когда заказы поступают в систему то они сразу попадают на нужный склад и спец алгоритм распределяет на водителей.

B> — sysadmin управляет только техническими настройками разными (кому когда отчеты отсылать, как в системе заводить оптуска, сколько часов в сутки можно работать, заводит праздники), остальное всё только в режиме просмотра видит.

B> — admin видит всё, не может только технические настройки менять. Следит за водителями, чтобы они всрок доставляли всё — по юаю специальному, вносит отпуска, больничные их, ставит им рабочее время. Если водитель увольняется — удаляет изи системы.
B> — manager следит за водителями своего склада только, может посмотреть по всем своим водителям информацию и по всем доставкам, но менять не может
B> — driver видит только по себе все сделанные доставки и предстоящие. Каждый раз когда он начинает и заканчивает доставку то в системе нажимает Start delivery\End delivery. Если доставка не укладывается в
B>предполагаемые сроки то пишет к доставке комментарий почему не успел

Важно, чтобы микросервисы как можно меньше взаимодействовали между собой. Если не получается — значит, границы выбраны неверно.
По вашему описанию не вполне понятно, что собственно должна делать система. Распределять заказы между водителями?
Смотрите:
0. Сервис аутентификации. Его хочется делать крайне надёжной, т.к. если никто не может зайти, то не работает вообще всё. Очень опасно делать монолит, в котором выкат какой-нибудь мелкой фичи типа "а давайте поздравим всех водителей-женщин с 8 марта" способен сломать логин. То есть эту штуку мы как можно реже релизим, и при каждом выкате покрываем тестами в шесть слоёв. Отдельные пацаны аудируют код на предмет потенциальных уязвимостей, т.к. кража базы паролей — почти самое плохое, что с нами вообще может случиться. Сам сервис скорее всего раскатан в нескольких экземплярах с геодистрибуцией и офигенной избыточностью — чтобы отключение света в нижегородском ДЦ не валило всю федеральную сеть водителей.
(Кстати, очень часто мы захотим это вообще делегировать наружу, чтобы не заниматься дорогостоящими инвестициями в эти пять девяток и прочие особенности. Привинчиваем OAuth и полагаемся на Google/Facebook/etc)
1. Сервис авторизации. После того, как пользователь залогинился, нам нужно ещё и получить набор его прав. В большинстве случаев это довольно-таки типовая структура, вроде ролей. Опять же, требования к ней довольно-таки жёсткие, т.к. она нужна в каждом первом сценарии. Ещё можно заметить, что она в значительной мере дублирует информацию из 0-й системы — как минимум, у нас должен быть тот же самый список пользователей. Поэтому в современном мире зачастую 0 и 1 объединяют в одну.
2. Сервис профилей. Всякие личные данные, предпочтения, и прочее. Набор этих данных меняется относительно часто, поэтому несмотря на структурную похожесть с предыдущим сервисом, его имеет смысл держать отдельно. Если даже кто-то очень криво выкатит обнову, которая даёт пользователю вместо фоточки на аватару выкладывать короткий ролик, логины и права продолжат работать.
Опять же, данные этого сервиса подпадают под всякие регуляторные нормы типа GDPR и его аналогов, поэтому имеет смысл их держать в отдельной базе с отдельными полисями бэкапа, контроля доступа, и функций своевременной очистки.
3. Сервис флагов/пользовательских настроек. Иногда его объединяют с предыдущим, но в большой системе лучше разделять. Потому что требования разные — флаги и настройки не являются personal information, зато постоянно нужны другим сервисам для принятия решений типа "а можно ли этого водителя назначить на рейс в Европу".

4. Вы упомянули про отпуска/больничные/рабочее время. Это выглядит как достаточно изолированный кусок, который может развиваться независимо от других. Опять же, он может попадать под какие-нибудь регуляторные требования в юрисдикции эксплуатации — всякие там нормы от минтруда и прочих проверяющих.

Обратите внимание, во всех сервисах, которые пока что были перечислены, есть понятие "пользователя". Типичной ошибкой начинающих проектировщиков является идея "а давайте мы всех пятерых подключим к одной базе данных — в конце-концов, список пользователей-то у нас общий! Зачем его дублировать?".
Вот это — плохая идея: получите все недостатки МСА без её достоинств. Да, список пользователей будет дублироваться. Да, на это придётся потратить немножко усилий. Но на самом деле всё не так уж и плохо — в том смысле, что, к примеру, настоящее имя пользователя и его дата рождения хранится только в одной системе, а какие-нибудь данные о его трудовой биографии — в другой. Дублирования не так уж и много; основное затруднение — невозможность контролировать ссылочную целостность. У вас всегда будет риск получить в четырёх базах "подвисшие" записи для пользователей, логин которых был забанен в 0м сервисе навсегда. Уборка мусора становится отдельной maintenance задачей.

Едем дальше — вот у нас что-то там про доставки. Собственно, тут пояснений недостаточно, придётся фантазировать. Очевидно, нужен какой-то сервис, который показывает водителю его доставки и позволяет с ними взаимодействовать.
Раздача доставок по водителям может быть частью этого сервиса, а может быть отдельной подсистемой. Чтобы опять же нововведения в алгоритме раздачи заявок не могли ничего отломать в учёте статуса доставок — у водителя в пути не всегда есть возможность "подождать до четверга", чтобы отметить статус заявки. Этому сервису будут нужны данные о том, кто когда планируется на смене — из того сервиса, где учитывались больничные/отпуска и т.п. Обратите внимание, что ему не надо никаких подробностей — можно придумать относительно стабильный, узкий API, по которому этот сервис запрашивает доступность того или иного водителя.

Наверняка нам потребуются какие-нибудь отчёты. Вот тут обычно начинаются приключения, потому что отчёты запросто могут соединять данные изо всех систем. Типа "а давайте посчитаем корреляцию между выработкой водителя, его возрастом и стажем работы". Кроме того, у этих отчётов совсем другой цикл работы, и отдельные требования к надёжности. Поэтому, опять же в предположении большой или очень большой системы, мы не будем их привинчивать ни в какой из упомянутых сервисов. И не будем их привинчивать поверх общей базы данных. Вместо этого у нас будет отдельный data warehouse, куда будет собираться первичная инфа изо всех сервисов (и заодно в "активных" сервисах будут подчищаться архивы, чтобы избежать деградации производительности над текущими задачами), а уже в этот warehouse, который выступает отдельным сервисом, будет даден доступ всем уполномоченным и заинтересованным.

Вот примерно так это и должно работать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: Каких программ вам не хватает?
От: Miroff Россия  
Дата: 25.03.25 08:10
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Я не вижу каких-то прямо практически значимых преимуществ HATEOAS.


HATEOAS позволяет не размазывать логику между сервером и клиентом. Клиенту не нужно думать, можно ему дергать какой-то ресурс или нет. Прислали ссылку, значит можно. Не прислали -- нельзя. Вместе с OPTIONS это такой подход позволяет полностью перенести авторизацию с клиента на сервер. Или, например, пейджинг: клиенту не нужно вычислять сколько страниц всего, какая предыдущая, какая следующая и т.п. Вместо этого ему сразу приходит список страниц, которые можно дернуть.

S>- можно ли в качестве owner использовать URL юзер-аккаунта в другом скоупе


HATEOAS это про чтение, что ты собрался использовать при чтении. Можно ли поменять owner? Надо пробовать, может да, может нет, может в каких-то случаях да, а в остальных нет. Даже OpenAPI не позволяет описать настолько сложные контракты.

S>- что делает глагол refund, и какие у него будут параметры, и где их брать


Это же ресурс, делаешь GET, смотришь, меняешь, делаешь PUT.

S>2. Evolvability улучшается крайне незначительно. У нас нет никакого способа научить клиентов всегда ходить только по указанным нами ссылкам. Если мы решили перенести endpoint для рефандов в другое место, то недостаточно просто отдавать новую ссылку в links.


Правильно делать GET перед PUT, потому что ссылки могут измениться, и вообще конкурентные обновления. Если разработчики не умеют пользоваться REST API это их проблема. Можно тупо менять ссылки при каждом запросе, чтобы даже желания сохранять их куда либо не возникало.

S>3. Накладные расходы значительно увеличиваются.


Я тебя умоляю, мы видео в 4К по сети гоняем и GUID вместо id используем. Несколько ссылок погоды не сделают.
Re[10]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.25 08:38
Оценка:
Здравствуйте, Miroff, Вы писали:

M>HATEOAS позволяет не размазывать логику между сервером и клиентом. Клиенту не нужно думать, можно ему дергать какой-то ресурс или нет. Прислали ссылку, значит можно. Не прислали -- нельзя.

Это заблуждение. Авторизация проверяется совершенно отдельно. Ещё не хватало в представлении ресурса показывать разный набор ссылок в зависимости от transient штуки вроде Bearer-токена.

M>Вместе с OPTIONS это такой подход позволяет полностью перенести авторизацию с клиента на сервер.

Размещение авторизации ортогонально HATEOAS. Естественно, она полностью выполняется на сервере. Если вы хотите прятать кнопки на клиенте на основе правил авторизации, то это в большинстве случаев контрпродуктивная идея.

M>Или, например, пейджинг: клиенту не нужно вычислять сколько страниц всего, какая предыдущая, какая следующая и т.п. Вместо этого ему сразу приходит список страниц, которые можно дернуть.

Да, пейджинг — это один из немногих случаев корректного и полезного применения ссылок. Но вообще, его изготовить правильно — очень сложно. Сильно сложнее, чем кажется на первые три взгляда. В частности, "список страниц, которые можно дёрнуть" — плохая идея, которая ломается в большом количестве сценариев.

Более-менее детерминированный способ никаких ссылок не содержит, но его редко применяют на практике по ряду вполне приземлённых причин.

M>HATEOAS это про чтение, что ты собрался использовать при чтении.

Нет конечно. HATEOAS — это про идентификацию ресурсов. REST сам по себе (даже без HATEOAS) — как раз про то, что все действия выполняются через управление представлением состояния.
В частности, приделывание к платёжке ссылки refund с методом POST — это RMM не L3, а L1. Потому, что нормальный способ — это PUT либо PATCH, которые прямым либо косвенным образом меняют состояние платежа на refunded.

M>Можно ли поменять owner? Надо пробовать, может да, может нет, может в каких-то случаях да, а в остальных нет. Даже OpenAPI не позволяет описать настолько сложные контракты.

Конечно позволяет. Вот у вас есть объект, у него есть представление. Всё, можно делать PUT этого представления. Если что-то запрещено бизнес-правилами — приедет 409. Если правами доступа — 403.

S>>- что делает глагол refund, и какие у него будут параметры, и где их брать

M>Это же ресурс, делаешь GET, смотришь, меняешь, делаешь PUT.
Нет конечно. Это не ресурс, это адрес для POST запроса.

M>Правильно делать GET перед PUT, потому что ссылки могут измениться, и вообще конкурентные обновления. Если разработчики не умеют пользоваться REST API это их проблема. Можно тупо менять ссылки при каждом запросе, чтобы даже желания сохранять их куда либо не возникало.

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

M>Я тебя умоляю, мы видео в 4К по сети гоняем и GUID вместо id используем. Несколько ссылок погоды не сделают.

Сделают. Стоимость эксплуатации складывается из мелочей. Два-три десятка таких идиотских решений — и вот уже ваш стейкхолдер вместо одного виртуального сервера оплачивает ферму из восьми выделенных.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Помогите правильно спроектировать микросервисное приложение
От: cppguard  
Дата: 25.03.25 08:58
Оценка:
Здравствуйте, busk, Вы писали:

B>Привет всем.

B>Как-то только в теории читал про микросервисы, но вот новый проект планируется небольшой и хотел как раз попробовать микросервисы тут.

Так, во-первых не слушай старых пердунов (ну, или молодых смузихлёбов , утверждающих, что для микросервисной архитектуры нужны большие ресурсы. Я целых два(!!!) раза успешно реализовывал микросервисы в одиночку. Большие команды нужны, потому что средненькие программисты генерируют средьненький код, который с линейным ростом команды растёт экспоненциально, поэтому нужны ресурсы на затычку дырок и замазывание щелей говнокодом. Если ты полиглот в плане языков программирования, дружишь с кодогенерацией, то проблем вообще нет.

B>Второе и собственно основное я так понял из книг, что самое сложное это определить границы сервисов. Вот прошу тут помощи как нарезать на сервисы и базы?


Я бы начал с ответа на вопрос: зачем вообще тебе микросервисы? Просто попробовать или действительно есть нужда? Просто пробовать на боевом проекте это почти всегда или фиаско, или бессонные ночи. Иногда сразу оба варианта В моём случае я оба раза выбирал микросервисы по прочине нехватки ресурсов для реализации всего функционала. Но не надо путать с нехваткой ресурсов для написания микросервисов как таковых — что монолит, что микросервисы потребовали бы целой команды, а я был один. Поэтому я разбил проект на непересекающиеся модули и для каждого использовал фреймворк или библиотеку, которая на старте давала 80% функционала из коробки. Например, нужен обыкновыенний CRUD? — Берём сразу Rail и не думаем. Илитных икспертов, которые расскажут, что Ruby медленный, посылаем в /dev/null — современный Ruby можно горизонтально масштабировать, а выигрышь от ускорения за счёт использования другого языка никогда не окупит время разработки эквивалентного функционала на этом языке. Теперь помимо CRUD нужно добавить возможность запускать процессы (например, мы пишем свой godbolt), изолировать их и контролировать. Отлично! Используем systemd для запуска процессов, а контроль осуществим через DBus. И как круто, что есть возможность генерировать интерфейсы классов на Python для DBus — не нужно руками прописывать вызовы API! Теперь у нас есть Ruby и Python. Просто связываем их через БД (вообще любая подойдёт). И вот у нас уже микросервисы. А если пойти дальше, то выяснится, что пресловутые микросервисы это REST гипертрофированный до размера операционной системы — состояние хранится где-то на диске (или в памяти в особо тяжёлых случаях), вызовы происходят через сервисы, а корректность состояния осуществляется через блокировки хранилища. Другого пока не придумали. Сложности и ошибки возникают, когда какой-то smart ass, решает, что он очень уж smart и пытается вынести контроль целостности данных с уровня хранилища на уровень приложения. Не надо так делать, и всё будет хорошо. И не надо бояться использовать разные языки. Лично я не понимаю, какой вообще смысл микросервисов, если мы всё пишем на одном языке? Теряется вся гибкость, всё преимущество возможности стоять на плечах гигантов и использовать готовые решения.

B>Третий вопрос. Если без докеров то как настроить этот набор микросервисов? тут их немного будет и читал что можно настроить без докер контейнеров если что.


Это вообще ортогональный вопрос. Контейнеры и микросервисы никак не связаны, но контейнеры позволяют изолировать многие процессы, в том числе и процесс выкатывания обновлений. Если, например, сервис это .exe то вообще никакой выгоды от контейнеров. Ну и при горизонтальном масштабировании не приходится настраивать систему с нуля. Но если не нравится докер, то есть контейнеры systemd, если lxc — выбирай на свой вкус.

Резюме: 80% написанного в личных блогах про микросервисы это каргокульт, можно не читать. Микросервисы это вообще обыкновенная архитектура — 100% современных автомобилей используют микросервисную архитектуру ещё с нулевых, не нужно её бояться. Купи книгу с кабанчиком (Клепман) и прочти её три раза.
Re[2]: Помогите правильно спроектировать микросервисное приложение
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 25.03.25 09:54
Оценка:
Здравствуйте, cppguard, Вы писали:

C>Так, во-первых не слушай старых пердунов (ну, или молодых смузихлёбов , утверждающих, что для микросервисной архитектуры нужны большие ресурсы. Я целых два(!!!) раза успешно реализовывал микросервисы в одиночку.

Мы все видели твои решения в некоторых разделах. Что ты там успешно напроектировал и реализовал — большой вопрос .
Sic luceat lux!
Re[6]: Помогите правильно спроектировать микросервисное приложение
От: · Великобритания  
Дата: 25.03.25 11:22
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

G>В этом случае может быть выгодно иметь микросервисы как раз по границам команд. Других адекватных причин использовать MSA я не видел.

В мною виденных трейдинговых системах — везде сабж. Одна команда (~10 девов) пилит пол-сотни приложух, которые разворачивачивется в ~тысячу сервисов на десятках хостов в пятёрке датацентров.
И да, сервисы не через REST взаимодйествуют, а через pub-sub сообщения (kafka/29west/mq/fix/аналоги).
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[2]: Помогите правильно спроектировать микросервисное приложение
От: TG  
Дата: 25.03.25 12:58
Оценка:
Здравствуйте, cppguard, Вы писали:

C>Я бы начал с ответа на вопрос: зачем вообще тебе микросервисы?

Дайте своё определение микросервисов.

C>А если пойти дальше, то выяснится, что пресловутые микросервисы это REST гипертрофированный до размера операционной системы — состояние хранится где-то на диске (или в памяти в особо тяжёлых случаях), вызовы происходят через сервисы, а корректность состояния осуществляется через блокировки хранилища.

Это Вы Кафку и прочие MQ REST-ом обозвали? Зачем?

C>Купи книгу с кабанчиком (Клепман) и прочти её три раза.

"Кабанчик" хорош, но его мало. Например, он никак не поможет определить границы сервисов.
Re[6]: Каких программ вам не хватает?
От: TG  
Дата: 25.03.25 13:01
Оценка:
Здравствуйте, Miroff, Вы писали:

M>Это вопрос не производительности, а потребляемых ресурсов. Микросервис суперпросто поднять, но суперсложно удалить. Например, компания, которая ввела внутренний биллинг, обнаружила себя тратящей несколько десятков миллионов в месяц на порядка тысячи микросервисов, которые непонятно кто и с какой целью поднял. Причем административными средствами проблема не решалась, потому что всегда оказывалось что микросервис поднял Вася пять лет назад для проекта X и за 5 лет Вася уволился, проект X влили в проект Y, который заменили на проект Z, в процессе два раза сменив команду и три раза сделав пивот на 180 градусов. И теперь концов уже не найти, нужен ли этот сервис СЕЙЧАС и если нужен, то ДЛЯ ЧЕГО.


Как-то не очень в такое верится.
"Тысячи микросервисов" — это при инстансы или типы сервисов?
Re[2]: Помогите правильно спроектировать микросервисное приложение
От: TG  
Дата: 25.03.25 13:06
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Обратите внимание, во всех сервисах, которые пока что были перечислены, есть понятие "пользователя". Типичной ошибкой начинающих проектировщиков является идея "а давайте мы всех пятерых подключим к одной базе данных — в конце-концов, список пользователей-то у нас общий! Зачем его дублировать?".

S>Вот это — плохая идея: получите все недостатки МСА без её достоинств. Да, список пользователей будет дублироваться. Да, на это придётся потратить немножко усилий. Но на самом деле всё не так уж и плохо — в том смысле, что, к примеру, настоящее имя пользователя и его дата рождения хранится только в одной системе, а какие-нибудь данные о его трудовой биографии — в другой. Дублирования не так уж и много; основное затруднение — невозможность контролировать ссылочную целостность. У вас всегда будет риск получить в четырёх базах "подвисшие" записи для пользователей, логин которых был забанен в 0м сервисе навсегда. Уборка мусора становится отдельной maintenance задачей.

Для таких вещей надо делать сервис реконсиляции.
С последующим ручным (скорее всего) разбором и разрешением коллизий.
Re[3]: Помогите правильно спроектировать микросервисное приложение
От: cppguard  
Дата: 25.03.25 13:16
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Мы все видели твои решения в некоторых разделах. Что ты там успешно напроектировал и реализовал — большой вопрос .


Очень большой вопрос, но за это платили деньги и просили продолжать работать. Для меня это критерий успешности
Re[4]: Помогите правильно спроектировать микросервисное приложение
От: TG  
Дата: 25.03.25 13:24
Оценка: +1
Здравствуйте, Miroff, Вы писали:

M>Микросервисы позволяют пернести часть сложности из приложения в оркестрацию. Это сильно упрощает разработку, когда у тебя в сервисе меньше 10к строк и один разработчик. Нет ни мердж конфликтов, не нужно ни с кем договариваться, не нужна документация, планирование, архитектура.


API приложения полностью зависит от нужд потребителя. Договариваться придётся.
И документация на API нужна (даже если у вас RMM L3). Людям нужно знать не столько функционал отдельного эндпойнта, сколько возможность осуществить некоторый сценарий. Свагер такого не описывает.

M>Выставляешь Restful API и проблема других сервисов как этим API воспользоваться.

Даже условный Яндекс с его, например, Картами не может себе такого позволить и думает о потребителях, иначе конкуренты сожрут.
Re[3]: Помогите правильно спроектировать микросервисное приложение
От: cppguard  
Дата: 25.03.25 13:51
Оценка:
Здравствуйте, TG, Вы писали:

C>>Я бы начал с ответа на вопрос: зачем вообще тебе микросервисы?

TG>Дайте своё определение микросервисов.

Зачем?

TG>Это Вы Кафку и прочие MQ REST-ом обозвали? Зачем?


Ну, это было очень грубое сравнение. Просто мало людей понимают, что есть данные и есть код, и код изменяет данные. И можно придумывать велосипед снова и снова и говорить про принципиально новые подходы к разработке, но суть меняется мало. Например, возьмём понолит, реализуем ключевые функции через динамические библиотеки, реализуем механизм горячего обновления функций при измении соответствующего файла библиотеки — опа! У нас получилась микросервисная архитектура. Или не микросервисная — как посмотреть. Я работал в разных проектах — от социальных сетей до роботов, и везде было одно и то же: код, данные, шины обмена данными, интерфейсы взаимодейсвтия. И когда начинают сраться по поводу микросервисов и монолитов, я в упор не понимаю, в чём реально принципиальная разница? Если открыть произвольную статью про проблемы микросервисов, то 99% нытья сведётся к тому, что архитектура получилась слабосвязная, валидации никакой нет, поэтому команды каждый день ломают друг другу совместимость. Но это норма. Когда-то срались по поводу REST vs. XML RPC (хотя это ложная дихотомия, одно не отменяет другого), потом конечно же RPC вернулся в виде gRCP и Thrift, только об этом стыдливо умолчали, ведь сколько людей было унижено на собеседовании вопросами об абсолютном доминировании REST.

TG>"Кабанчик" хорош, но его мало. Например, он никак не поможет определить границы сервисов.


Что посоветуете почитать? Выбор зоны ответственности сервиса это вопрос, выходящий далеко за рамки темы микросервисов. Детское автомобильное кресло это категория "товары для детей" или "автоаксессуары"? Вот и с сервисами так же. У меня недостаточно опыта работы в кровавом энтерпрайзе, чтобы дискутировать на эту тему, хотя даже за его пределами приходится решать эту проблему. Вот прямо сейчас нужно понять, данные с лидара нужно слать в сыром виде по шине, а другой сервис будет заниматься обработкой, или же всё делать в рамках одного сервиса? В первом случае возникает нагрузка на шину, во втором случае — нагрузка на вычислительный узел. Пока что решение — вынести вообще всю систему восприятия робота в отдельную подсистему, но там свои нюансы.
Re[7]: Помогите правильно спроектировать микросервисное приложение
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.03.25 15:02
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, gandjustas, Вы писали:


G>>В этом случае может быть выгодно иметь микросервисы как раз по границам команд. Других адекватных причин использовать MSA я не видел.


S>Ну ещё ограничить failure domain. Чтобы бага в одном углу приложения клала его не целиком, а только блокировала отдельные сценарии.


В managed среда это можно и без микросервисов сделать. А даже в случае unmanaged можно разделить по процессам и использовать unix-sockets\named-pipes для общения между ними в рамках одного сервера, обеспечивая все взаимодействие и синхронизацию разных инстансов (серверов\контейнеров) через базу.

Если говорить failure domain с точки зрения логики приложения, то разделение на микросервисы делает ситуацию только хуже. Так как разработчики одного микросервиса могут внести изменения, ломающие работу других и даже не узнают об этом. Поэтому с точки зрения бизнес-логики идеально чтобы бизнес-процесс начинался и заканчивался в одном микросервисе.

В итоге подходящая модель для MSA — где команды разделены по бизнес-доменам, где все транзакционные бизнес-процессы полностью лежат в ответственности домена. Например закупки, склад, производство, продажи, планирование. Причем это будут дольно большие домены и, соответственно, большие сервисы. Почему их называют "микро-сервисами"&
Re[7]: Помогите правильно спроектировать микросервисное приложение
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.03.25 15:32
Оценка: :)
Здравствуйте, ·, Вы писали:

·>Здравствуйте, gandjustas, Вы писали:


G>>В этом случае может быть выгодно иметь микросервисы как раз по границам команд. Других адекватных причин использовать MSA я не видел.

·>В мною виденных трейдинговых системах — везде сабж. Одна команда (~10 девов) пилит пол-сотни приложух, которые разворачивачивется в ~тысячу сервисов на десятках хостов в пятёрке датацентров.
·>И да, сервисы не через REST взаимодйествуют, а через pub-sub сообщения (kafka/29west/mq/fix/аналоги).

Я конечно тоже видел системы, где микросервисов больше чем программистов и пользователей вместе взятых, но при проверке оказывалось что все то же самое можно было бы запились в монолит с меньшими затратами, не потеряв вообще никаких потребительских качеств системы.
Re[8]: Помогите правильно спроектировать микросервисное приложение
От: · Великобритания  
Дата: 25.03.25 16:55
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>·>В мною виденных трейдинговых системах — везде сабж. Одна команда (~10 девов) пилит пол-сотни приложух, которые разворачивачивется в ~тысячу сервисов на десятках хостов в пятёрке датацентров.

G>·>И да, сервисы не через REST взаимодйествуют, а через pub-sub сообщения (kafka/29west/mq/fix/аналоги).
G>Я конечно тоже видел системы, где микросервисов больше чем программистов и пользователей вместе взятых, но при проверке оказывалось что все то же самое можно было бы запились в монолит с меньшими затратами, не потеряв вообще никаких потребительских качеств системы.
Охотно верю. Я лишь рассказал о типах систем, которые ты не видел. Если интересно и есть вопросы, спрашивай.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[8]: Помогите правильно спроектировать микросервисное приложение
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.04.25 05:17
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

G>В managed среда это можно и без микросервисов сделать.

Не очень понятно, что вы имеете в виду. Поддержку AppDomain выпилили (за ненадобностью) из нового дотнета, а в жаве её никогда и не было.
Управляемая среда всего лишь гарантирует отсутствие ошибок типизации и "повисших" ссылок. Всё. Никакой изоляции она из коробки не предоставляет.
Понятно, что она лучше любого анменеджеда хотя бы тем, что в ней нет undefined behavior (если, опять же, придерживаться гигиены и не пользоваться всякими ансейф и около-ансейф вещами).
Но defined behavior недостаточно для ограничения failure domain. Потому что если есть разделяемое состояние, то невозможно гарантировать его целостность при наступлении неожиданных результатов.
Вот у вас есть разделяемая в памяти коллекция, и один поток начал её модификацию, пока второй читает. Ок, мы обеспечили отсутствие гонок, обложив доступ примитивами синхронизации.
Менеджед-среда (более-менее) гарантирует нам то, что при выбросе исключения будут обработаны все блоки finally и, в частности, все удерживаемые блокировки будут отпущены. Но она вовсе не гарантирует нам то, что после отпускания блокировок коллекция придёт в консистентное (с точки зрения прикладных инвариантов) состояние.

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

G>А даже в случае unmanaged можно разделить по процессам и использовать unix-sockets\named-pipes для общения между ними в рамках одного сервера, обеспечивая все взаимодействие и синхронизацию разных инстансов (серверов\контейнеров) через базу.

Всё верно. Если у нас shared state вынесен в "базу", которая предоставляет ACID-гарантии, то у нас масштабы проблемы ограничены.
В предположении, что все инварианты инкапсулированы в этой базе. На практике, зачастую собственно перемещение логики из базы в "сервисы" и делается ради того, чтобы обеспечить те инварианты, которые в базе поддерживать оказывается тяжело. То есть у нас опять корректность разделяемого состояния определяется тем, насколько корректно себя ведёт каждый сервис. И наличие бесконтрольного доступа в базу приводит к тому, что ошибка в сервисе А приводит к записи в базу мусора, который нарушает предположения, на основе которых реализованы другие сервисы.

Поэтому сервисная архитектура и появляется как развитие идеи "давайте разведём сервисы по процессам и заставим их взаимодействовать по ограниченным каналам". Выбор JSON over HTTP вместо "proprietary binary protocol over named pipes" обусловлен уже не вопросами надёжности, а вопросами совместимости и готовности к эволюции.
Если мы попытаемся спроектировать свой бинарный протокол со встроенной поддержкой всех нужных negotiations, а также с умением восстанавливаться после сбоев и кэшировать результаты, то у нас получится примерно такой же REST, чутка отличающийся диалектом.

G>Если говорить failure domain с точки зрения логики приложения, то разделение на микросервисы делает ситуацию только хуже. Так как разработчики одного микросервиса могут внести изменения, ломающие работу других и даже не узнают об этом. Поэтому с точки зрения бизнес-логики идеально чтобы бизнес-процесс начинался и заканчивался в одном микросервисе.

Это уже административные вопросы. Вы неявно предполагаете, что единицей тестирования является отдельный микросервис, из-за чего бизнес-процесс, пересекающий границы микросервисов, останется непротестированным.
Но с таким подходом мы налетим на те же проблемы и в монолите — если мы ограничимся юнит-тестами компонентов без интеграционного тестирования получится ровно такой же результат.
А если у нас процесс тестирования построен (хотя бы частично) вокруг бизнес-сценариев, то нам всё равно, сколько там компонентов, сервисов, или микросервисов в нём участвует.
Микросервисы несколько выигрывают по сравнению с другими архитектурами как раз потому, что сокращают возможности по внесению нежелательных зависимостей.
То есть пока у нас всё лежит в монолите, сотрудник команды А имеет возможность подсмотреть в код команды Б, и напрямую завязаться на то, что интерфейс IFoo реализован некоторым классом FooImpl. И вместо того, чтобы обратиться по стандартным каналам к архитекторам команды Б "добавьте мне в IFoo метод по расчёту предварительной цены без заключения сделки", делает даункаст и вызывает потрошки напрямую.
Когда вы распиливаете монолит на процессы и пайпы, такой возможности уже нет — у Foo своё адресное пространство, и мимо протокола к нему обратиться не получится.
Зато можно полезть напрямую в базу "я же знаю, в каких таблицах у них что лежит". В итоге команда Б, полагая себя единоличными владельцами схемы, что-то перекраивает в очередной версии своего сервиса, и код команды А начинает падать, хотя такой же код неделю назад прекрасно работал.

G>В итоге подходящая модель для MSA — где команды разделены по бизнес-доменам, где все транзакционные бизнес-процессы полностью лежат в ответственности домена. Например закупки, склад, производство, продажи, планирование. Причем это будут дольно большие домены и, соответственно, большие сервисы. Почему их называют "микро-сервисами"


Не, это вы как раз рассказываете про SOA, где сервисы всё ещё представляют собой очень крупные блоки. А MSA — это как раз экстремальное развитие SOA, когда мы дробим задачу на ещё более мелкие единицы, которые не реализуют никакой бизнес-процесс, а, скорее, отвечают за некоторые кирпичики этого процесса. Например, у вас есть "ядро" — микросервис, который отвечает за финансовые транзации. Только переводы между счетами, и всё. У него очень жёсткие инварианты, и всё покрыто требованиями регулятора. Поверх этого вы реализуете функциональность типа "Выдача кредитов". Наличие отдельного ядра гарантирует вам, что криворукий джун, разрабатывая код бизнес-процессов "выдача кредита" и "внесение очередного платежа" не напорет с транзакциями и не сломает базовые гарантии типа сохранения суммы всех балансов.
Опять же сбоку этого делается отдельный сервис по оценке рисков, который никак не может сломать поведение бизнес-процесса "рассмотрение кредитных заявок", и в худшем случае у вас какие-то из видов кредитов перестанут выдаваться. Но никаких шансов запороть механику начисления процентов и списания задолженности у этого микросервиса нет.
И так далее — всё строится из параноидально изолированных микрокомпонентов. Один умеет рассчитывать стоимость залогового имущества, другой — умеет управлять статусами залогового имущества. Третий из этих двух собирает бизнес-процесс "переоценка рисков и досрочное истребование кредита в связи с изменением существенных обстоятельств".
Дополнительными бонусами являтся возможность один писать на питоне, другой — на тайпскрипте.

Как-то так.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: Помогите правильно спроектировать микросервисное приложение
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 01.04.25 14:04
Оценка: -1 :)
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, gandjustas, Вы писали:


G>>В managed среда это можно и без микросервисов сделать.

S>Не очень понятно, что вы имеете в виду. Поддержку AppDomain выпилили (за ненадобностью) из нового дотнета, а в жаве её никогда и не было.

Ну есть экспериментальные DotNetIsolator [EXPERIMENTAL]

Правда 2 года не изменялась

// Set up an isolated runtime
using var host = new IsolatedRuntimeHost().WithBinDirectoryAssemblyLoader();
using var runtime = new IsolatedRuntime(host);

// Output: I'm running on X64
Console.WriteLine($"I'm running on {RuntimeInformation.OSArchitecture}");

runtime.Invoke(() =>
{
    // Output: I'm running on Wasm
    Console.WriteLine($"I'm running on {RuntimeInformation.OSArchitecture}");
});
и солнце б утром не вставало, когда бы не было меня
Re[9]: Помогите правильно спроектировать микросервисное приложение
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 02.04.25 07:45
Оценка: 80 (1)
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, gandjustas, Вы писали:


G>>В managed среда это можно и без микросервисов сделать.

S>Не очень понятно, что вы имеете в виду. Поддержку AppDomain выпилили (за ненадобностью) из нового дотнета, а в жаве её никогда и не было.
S>Управляемая среда всего лишь гарантирует отсутствие ошибок типизации и "повисших" ссылок. Всё. Никакой изоляции она из коробки не предоставляет.
S>Понятно, что она лучше любого анменеджеда хотя бы тем, что в ней нет undefined behavior (если, опять же, придерживаться гигиены и не пользоваться всякими ансейф и около-ансейф вещами).
Я говорю о том, что вручную выстроенная модульность внутри приложения, на уровне отсутствия ссылок из группы объектов, поддерживается самой managed средой. Без использования ансейфа и разделяемых данных без должной осмотрительности крайне сложно в managed среде во время обработки одного запроса нарушить работу кода, обрабатывающего другие запросы.


S>Но defined behavior недостаточно для ограничения failure domain. Потому что если есть разделяемое состояние, то невозможно гарантировать его целостность при наступлении неожиданных результатов.

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

Очень хороший кейс.

А давай прикинем как это будет в MSA. там будет точно такая же коллекция в одном из сервисов, и менять её будет не поток, порожденный программистом, а поток порожденный хостом для обработки запроса. А все остальное будет то же самое. И, как в случае монолитного приложения, так и в случае MSA падения как такового не будет. Восстановление после такого falure возможно только сбросом состояния путем насильного перезапуска, например по хелсчеку. Разница в случае MSA будет только в том, что будет перезапущен один маленький сервис, а не толстое приложение. Но при этом весь сценарий работать не будет, пока микросервис с разделяемой коллекцией в памяти не оживет.

Надежный способ решения это использовать какое-то хранилище, которое поддерживает acid транзакции. Но это и в монолите возможно. Причем в монолите есть простор для оптимизации. Так как можно использовать STM например. Но на практике, когда экземпляров приложения может быть больше одного, все разделяемое состояние надо хранить во внешних, желательно транзакционных, хранилищах.




G>>А даже в случае unmanaged можно разделить по процессам и использовать unix-sockets\named-pipes для общения между ними в рамках одного сервера, обеспечивая все взаимодействие и синхронизацию разных инстансов (серверов\контейнеров) через базу.

S>Всё верно. Если у нас shared state вынесен в "базу", которая предоставляет ACID-гарантии, то у нас масштабы проблемы ограничены.
При горизонтальном масштабировании к этому все и придут обязательно. В принципе грамотный архитектор должен сразу на такое натолкнуть.

S>В предположении, что все инварианты инкапсулированы в этой базе. На практике, зачастую собственно перемещение логики из базы в "сервисы" и делается ради того, чтобы обеспечить те инварианты, которые в базе поддерживать оказывается тяжело. То есть у нас опять корректность разделяемого состояния определяется тем, насколько корректно себя ведёт каждый сервис. И наличие бесконтрольного доступа в базу приводит к тому, что ошибка в сервисе А приводит к записи в базу мусора, который нарушает предположения, на основе которых реализованы другие сервисы.

Опять-таки MSA ничем не помогает в этом случае. Без разницы будет мусор писать в базу микросервис или монолит.

G>>Если говорить failure domain с точки зрения логики приложения, то разделение на микросервисы делает ситуацию только хуже. Так как разработчики одного микросервиса могут внести изменения, ломающие работу других и даже не узнают об этом. Поэтому с точки зрения бизнес-логики идеально чтобы бизнес-процесс начинался и заканчивался в одном микросервисе.

S>Это уже административные вопросы. Вы неявно предполагаете, что единицей тестирования является отдельный микросервис, из-за чего бизнес-процесс, пересекающий границы микросервисов, останется непротестированным.
Так это самые важные вопрос. Я еще раз напомню тезис, который в этой теме и другие коллеги подтверждают: MSA это больше про оргструктуру, а не про архитектуру. В интернетах предлагают "правильную" MSA с разделением микросервисов по разным репозитариям исходного кода. Как в этом случае обеспечить синхронность изменений разных микросервисах, если изменяемый бизнес-процесс затрагивает несколько таких микросервисов?

S>Но с таким подходом мы налетим на те же проблемы и в монолите — если мы ограничимся юнит-тестами компонентов без интеграционного тестирования получится ровно такой же результат.

В монолите обычно используется одна репа и там по крайней мере все изменения можно (и нужно) вносить в одной (отдельной) ветке.

S>А если у нас процесс тестирования построен (хотя бы частично) вокруг бизнес-сценариев, то нам всё равно, сколько там компонентов, сервисов, или микросервисов в нём участвует.

В msa весьма вероятна ситуация, что в принципе невозможно собрать работающее сочетание микросервисов. Я такое на практике видел. Было три микросервиса (А,Б,В) и два процесса(1,2), затрагивающие три сервиса. В один момент было так, что: А/HEAD, Б/HEAD, В/HEAD~1 работал сценарий 1, но не работал 2. А/HEAD, Б/HEAD~1, В/HEAD работал 2, но не работал 1 и при этом же А/HEAD~1, Б/HEAD, В/HEAD также работал 2, но не работал 1.

И каждый разработчик миросервиса доказывал что "work on my microservice" (современный аналог work on my machine)


S>Микросервисы несколько выигрывают по сравнению с другими архитектурами как раз потому, что сокращают возможности по внесению нежелательных зависимостей.

Скажем так: в микросервисах сложнее внести зависимость. Иногда это выгоднее, но иногда нет, когда зависимость нужна.
Дисциплина, современные среды, языки и библиотеки (я не про Go) позволяют создавать достаточную изоляцию и внутри монолитного приложения, не получая огромных затрат на внесение зависимостей когда они нужны.

S>То есть пока у нас всё лежит в монолите, сотрудник команды А имеет возможность подсмотреть в код команды Б, и напрямую завязаться на то, что интерфейс IFoo реализован некоторым классом FooImpl. И вместо того, чтобы обратиться по стандартным каналам к архитекторам команды Б "добавьте мне в IFoo метод по расчёту предварительной цены без заключения сделки", делает даункаст и вызывает потрошки напрямую.

Доункаст к чему, если у него нет паблик класса, к которому даункастить?

S>Когда вы распиливаете монолит на процессы и пайпы, такой возможности уже нет — у Foo своё адресное пространство, и мимо протокола к нему обратиться не получится.

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

S>Зато можно полезть напрямую в базу "я же знаю, в каких таблицах у них что лежит". В итоге команда Б, полагая себя единоличными владельцами схемы, что-то перекраивает в очередной версии своего сервиса, и код команды А начинает падать, хотя такой же код неделю назад прекрасно работал.

Так можно и в базу другого микросервиса полезть. А чтобы этого не было — надо чтобы это были разные репы и фактически было невозможно запустить сервисы на одной машине. А это автоматом означает сложности в тестировании.
В случае единой репы и нормального архитектора — на ревью бить по рукам (или по лицу) за такой код.

G>>В итоге подходящая модель для MSA — где команды разделены по бизнес-доменам, где все транзакционные бизнес-процессы полностью лежат в ответственности домена. Например закупки, склад, производство, продажи, планирование. Причем это будут дольно большие домены и, соответственно, большие сервисы. Почему их называют "микро-сервисами"


S>Не, это вы как раз рассказываете про SOA, где сервисы всё ещё представляют собой очень крупные блоки. А MSA — это как раз экстремальное развитие SOA, когда мы дробим задачу на ещё более мелкие единицы, которые не реализуют никакой бизнес-процесс, а, скорее, отвечают за некоторые кирпичики этого процесса. Например, у вас есть "ядро" — микросервис, который отвечает за финансовые транзации. Только переводы между счетами, и всё. У него очень жёсткие инварианты, и всё покрыто требованиями регулятора. Поверх этого вы реализуете функциональность типа "Выдача кредитов". Наличие отдельного ядра гарантирует вам, что криворукий джун, разрабатывая код бизнес-процессов "выдача кредита" и "внесение очередного платежа" не напорет с транзакциями и не сломает базовые гарантии типа сохранения суммы всех балансов.

Я именно об этом и говорю. Знаю один банк где над таким ядром-"микросервисом" трудится команда из 40+ только программистов. То есть ни разу он не "микро", о чем я и говорю. А выдача кредитов это вообще с десяток связанных процессов, на каждом из которых команда в 10+ человек. То есть их тоже "микро" назвать сложно.

Напомню что апологеты микросервисов говорят что микросервис это когда команду можно накормить двумя пиццами, грубо 4-5 человек.

S>Дополнительными бонусами являтся возможность один писать на питоне, другой — на тайпскрипте.

Это какбы единственное неоспоримое преимущество MSA, с которым никто никогда и не спорил.
Re[10]: Помогите правильно спроектировать микросервисное приложение
От: Sinclair Россия https://github.com/evilguest/
Дата: 02.04.25 09:51
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

G>Я говорю о том, что вручную выстроенная модульность внутри приложения, на уровне отсутствия ссылок из группы объектов, поддерживается самой managed средой. Без использования ансейфа и разделяемых данных без должной осмотрительности крайне сложно в managed среде во время обработки одного запроса нарушить работу кода, обрабатывающего другие запросы.

Это понятно, просто "не использовать разделяемые данные" бывает достаточно сложно, кмк. Менеджед-гарантии, конечно, лучше, чем аналоги из неуправляемого мира, где даже и без разделяемых данных можно разломать всё, что угодно, но, увы, я не знаю способов быстро сказать по внешнему виду какого-нибудь кода, использует ли он какие-то разделяемые данные или нет.

G>А давай прикинем как это будет в MSA. там будет точно такая же коллекция в одном из сервисов, и менять её будет не поток, порожденный программистом, а поток порожденный хостом для обработки запроса. А все остальное будет то же самое. И, как в случае монолитного приложения, так и в случае MSA падения как такового не будет. Восстановление после такого falure возможно только сбросом состояния путем насильного перезапуска, например по хелсчеку. Разница в случае MSA будет только в том, что будет перезапущен один маленький сервис, а не толстое приложение. Но при этом весь сценарий работать не будет, пока микросервис с разделяемой коллекцией в памяти не оживет.

Всё верно. MSA не гарантирует безошибочности. MSA гарантирует, что падение не затронет сценарии, в которых микросервис не задействован.

G>Надежный способ решения это использовать какое-то хранилище, которое поддерживает acid транзакции. Но это и в монолите возможно. Причем в монолите есть простор для оптимизации. Так как можно использовать STM например. Но на практике, когда экземпляров приложения может быть больше одного, все разделяемое состояние надо хранить во внешних, желательно транзакционных, хранилищах.

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

G>При горизонтальном масштабировании к этому все и придут обязательно. В принципе грамотный архитектор должен сразу на такое натолкнуть.

Вопрос открытый. Чего я только не видел в энтерпрайзе, при самых грамотных архитекторах.

G>Опять-таки MSA ничем не помогает в этом случае. Без разницы будет мусор писать в базу микросервис или монолит.

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

G>Так это самые важные вопрос. Я еще раз напомню тезис, который в этой теме и другие коллеги подтверждают: MSA это больше про оргструктуру, а не про архитектуру. В интернетах предлагают "правильную" MSA с разделением микросервисов по разным репозитариям исходного кода. Как в этом случае обеспечить синхронность изменений разных микросервисах, если изменяемый бизнес-процесс затрагивает несколько таких микросервисов?

Никак — MSA, собственно, и обеспечивает отсутствие синхронности. Это преимущество, а не недостаток.
Изменения в бизнес-процессе накатываются постепенно: сначала мы обучаем новостям самый "нижний" микросервис в топологически отсортированном списке микросервисов, затем — чуть более "верхние".
Изменения в БП становятся видны в тот момент, когда мы выкатываем изменения "корневого" микросервиса, который оркестрирует весь БП.

S>>Но с таким подходом мы налетим на те же проблемы и в монолите — если мы ограничимся юнит-тестами компонентов без интеграционного тестирования получится ровно такой же результат.

G>В msa весьма вероятна ситуация, что в принципе невозможно собрать работающее сочетание микросервисов. Я такое на практике видел. Было три микросервиса (А,Б,В) и два процесса(1,2), затрагивающие три сервиса. В один момент было так, что: А/HEAD, Б/HEAD, В/HEAD~1 работал сценарий 1, но не работал 2. А/HEAD, Б/HEAD~1, В/HEAD работал 2, но не работал 1 и при этом же А/HEAD~1, Б/HEAD, В/HEAD также работал 2, но не работал 1.

G>И каждый разработчик миросервиса доказывал что "work on my microservice" (современный аналог work on my machine)

Это организационная проблема. В монолите все эти команды делали бы ровно то же самое ровно с тем же результатом.
А, ну и, возможно, неудачно были проведены границы между микросервисами. Это — отдельное искусство, настолько редкое, что я, ЕМНИП, видел только одно правильное решение (и с десяток заведомо неверных).

G>Дисциплина, современные среды, языки и библиотеки (я не про Go) позволяют создавать достаточную изоляцию и внутри монолитного приложения, не получая огромных затрат на внесение зависимостей когда они нужны.

Может быть. Я не говорю, что MSA — единственный верный способ деятельности

G>Доункаст к чему, если у него нет паблик класса, к которому даункастить?

Почему вы думаете, что нету?
А если нету — всегда можно запилить reflection. Пытливому уму все средства хороши.

G>Тут даже комментировать не буду. В дотнете и жабе полно средств изоляции. При желании даже в JS можно инкапсуляцию сделать, чтобы до потрохов никто не добрался.

Как раз в JS-то можно. Но, опять же, можно!=делают.

G>Так можно и в базу другого микросервиса полезть.

Невозможно. Базу чужого микросервиса даже не видно. И даже если вдруг чужая база лежит на той же машине, то доступ к ней выдан другому сервис-аккаунту, чем тот, под которым бегает этот микросервис.

G>В случае единой репы и нормального архитектора — на ревью бить по рукам (или по лицу) за такой код.

Это всё хорошо работает до определённых размеров кодовой базы, команды, и уровня ответственности за промахи. Там, где за ошибки принято тюремное заключение или суровые штрафы, делают именно так, не полагаясь на бдительность peer review и личность архитектора.

G>Я именно об этом и говорю. Знаю один банк где над таким ядром-"микросервисом" трудится команда из 40+ только программистов. То есть ни разу он не "микро", о чем я и говорю. А выдача кредитов это вообще с десяток связанных процессов, на каждом из которых команда в 10+ человек. То есть их тоже "микро" назвать сложно.

Так "micro" это же не про размер команды. А про "площадь поверхности".

G>Напомню что апологеты микросервисов говорят что микросервис это когда команду можно накормить двумя пиццами, грубо 4-5 человек.

Хм. Я не очень тесно знаком с апологетами микросервисов, могу чего-то не знать.

G>Это какбы единственное неоспоримое преимущество MSA, с которым никто никогда и не спорил.

Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: Помогите правильно спроектировать микросервисное приложение
От: · Великобритания  
Дата: 02.04.25 10:08
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

G>Я говорю о том, что вручную выстроенная модульность внутри приложения, на уровне отсутствия ссылок из группы объектов, поддерживается самой managed средой. Без использования ансейфа и разделяемых данных без должной осмотрительности крайне сложно в managed среде во время обработки одного запроса нарушить работу кода, обрабатывающего другие запросы.

Гы. Как минимум, память и gc — разделяемые. Так что когда запрос какого-нибудь отчёта для аналитики вдруг роняет по OOM всё сразу, в т.ч. обработку заказов — ничего хорошего.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[11]: Помогите правильно спроектировать микросервисное приложение
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 02.04.25 11:03
Оценка: +1
Здравствуйте, ·, Вы писали:

·>Здравствуйте, gandjustas, Вы писали:


G>>Я говорю о том, что вручную выстроенная модульность внутри приложения, на уровне отсутствия ссылок из группы объектов, поддерживается самой managed средой. Без использования ансейфа и разделяемых данных без должной осмотрительности крайне сложно в managed среде во время обработки одного запроса нарушить работу кода, обрабатывающего другие запросы.

·>Гы. Как минимум, память и gc — разделяемые. Так что когда запрос какого-нибудь отчёта для аналитики вдруг роняет по OOM всё сразу, в т.ч. обработку заказов — ничего хорошего.
Ничего не мешает в рамках монолитного решения вынести отдельный инстанс для обработки тяжелых запросов и на уровне балансера распределять.

Еще раз повторю тезис: MSA это больше про оргструктуру и следующие за ней технические решения. А все инструменты: докеры, кубернетесы, балансеры, кэши, готовые сервисы хранения и расчетов, вполне можно применять даже если у вас весь ваш код в одной репе, копилируется в один бинарник и запускается в одном контейнере.
Re[12]: Помогите правильно спроектировать микросервисное приложение
От: · Великобритания  
Дата: 02.04.25 11:21
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Я говорю о том, что вручную выстроенная модульность внутри приложения, на уровне отсутствия ссылок из группы объектов, поддерживается самой managed средой. Без использования ансейфа и разделяемых данных без должной осмотрительности крайне сложно в managed среде во время обработки одного запроса нарушить работу кода, обрабатывающего другие запросы.

G>·>Гы. Как минимум, память и gc — разделяемые. Так что когда запрос какого-нибудь отчёта для аналитики вдруг роняет по OOM всё сразу, в т.ч. обработку заказов — ничего хорошего.
G>Ничего не мешает в рамках монолитного решения вынести отдельный инстанс для обработки тяжелых запросов и на уровне балансера распределять.
Видимо ты тут намекаешь на какую-то принципиальную разницу между SOA и MSA?
Ещё почему-то ты предполагаешь что есть некий один универсальный балансер. А в приложухе может быть REST для аналитики, FIX для заказов и т.п.

G>Еще раз повторю тезис: MSA это больше про оргструктуру и следующие за ней технические решения.

По-моему, ты причину со следствием путаешь.

G>А все инструменты: докеры, кубернетесы, балансеры, кэши, готовые сервисы хранения и расчетов, вполне можно применять даже если у вас весь ваш код в одной репе, копилируется в один бинарник и запускается в одном контейнере.

А зачем обязательно один бинарник? Если деплоймент разный всё равно. Чтобы были многочасовые билды?
Сборка, деплой и перезапуск мелкого сервиса занимает минуты от момента мержа PR. Тогда как типичная выкатка монолита — приятно проведённые выходные.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[13]: Помогите правильно спроектировать микросервисное приложение
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 02.04.25 14:32
Оценка: +1
Здравствуйте, ·, Вы писали:

·>Здравствуйте, gandjustas, Вы писали:


G>>>>Я говорю о том, что вручную выстроенная модульность внутри приложения, на уровне отсутствия ссылок из группы объектов, поддерживается самой managed средой. Без использования ансейфа и разделяемых данных без должной осмотрительности крайне сложно в managed среде во время обработки одного запроса нарушить работу кода, обрабатывающего другие запросы.

G>>·>Гы. Как минимум, память и gc — разделяемые. Так что когда запрос какого-нибудь отчёта для аналитики вдруг роняет по OOM всё сразу, в т.ч. обработку заказов — ничего хорошего.
G>>Ничего не мешает в рамках монолитного решения вынести отдельный инстанс для обработки тяжелых запросов и на уровне балансера распределять.
·>Видимо ты тут намекаешь на какую-то принципиальную разницу между SOA и MSA?

«Они очень маленькие. Даже сто строк кода, вероятно, считаются сегодня большим сервисом», — Фред Джордж, Barcelona Ruby Conference


«Команда на две пиццы» https://aws.amazon.com/executive-insights/content/amazon-two-pizza-team/


«Если сервис проектирует и поддерживает несколько программистов, то это не микросервис», — Фред Джордж, GOTO 2016


«Каждый сервис автономен, самостоятелен и выполняет уникальный процесс». https://www.paloaltonetworks.co.uk/cyberpedia/what-are-microservices#:~:text=Each%20service%20is%20autonomous%20and%20self%2Dcontained%20and%20runs%20a%20unique%20process


«Каждый микросервис упакован как контейнер Docker, чтобы обеспечить возможность развёртывания в кластер Kubernetes для оркестрации приложения». https://thinkmicroservices.com/


Тут и паттерны, и технологии, и оргструктуры и много чего еще.


·>Ещё почему-то ты предполагаешь что есть некий один универсальный балансер. А в приложухе может быть REST для аналитики, FIX для заказов и т.п.

Я не понял к чему эта фраза

G>>Еще раз повторю тезис: MSA это больше про оргструктуру и следующие за ней технические решения.

·>По-моему, ты причину со следствием путаешь.
А может и наоборот, не задумывался об этом?
Я вижу что микросервисы цветут там, где слишком много команд и разработчиков чтобы пилить монолиты. Поэтому техническая архитектура диктуется оргструктурой. Если у тебя команда небольшая или ты вообще один что-то делаешь — тебе в принципе не нужны микросервисы.


G>>А все инструменты: докеры, кубернетесы, балансеры, кэши, готовые сервисы хранения и расчетов, вполне можно применять даже если у вас весь ваш код в одной репе, копилируется в один бинарник и запускается в одном контейнере.

·>А зачем обязательно один бинарник? Если деплоймент разный всё равно. Чтобы были многочасовые билды?
А ты думаешь сборка одного толстого бинарника медленнее, чем сборка трех бинарников потоньше? Или ты думаешь что обязательно пересобирать все проекты каждый раз?
Да и в целом время сборки для деплоя мало интересует, интересует время от команды run до запуска приложения, если ты это делаешь 25 раз в день.

·>Сборка, деплой и перезапуск мелкого сервиса занимает минуты от момента мержа PR. Тогда как типичная выкатка монолита — приятно проведённые выходные.

В теории да. Но внезапно:
1) в микросервисах надо тупо больше кода править
2) если ты затрагиваешь несколько сервисов своим изменением, то несколько сервисов собираются дольше чем один
3) даже докер умеет кэшировать образы, поэтому вполне можно сделать сбору с кэшированием и не пересобирать то, что не изменилось
Re[11]: Помогите правильно спроектировать микросервисное приложение
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 02.04.25 22:01
Оценка:
Здравствуйте, Sinclair, Вы писали:

G>>А давай прикинем как это будет в MSA. там будет точно такая же коллекция в одном из сервисов, и менять её будет не поток, порожденный программистом, а поток порожденный хостом для обработки запроса. А все остальное будет то же самое. И, как в случае монолитного приложения, так и в случае MSA падения как такового не будет. Восстановление после такого falure возможно только сбросом состояния путем насильного перезапуска, например по хелсчеку. Разница в случае MSA будет только в том, что будет перезапущен один маленький сервис, а не толстое приложение. Но при этом весь сценарий работать не будет, пока микросервис с разделяемой коллекцией в памяти не оживет.

S>Всё верно. MSA не гарантирует безошибочности. MSA гарантирует, что падение не затронет сценарии, в которых микросервис не задействован.
Смотря что значит "не затронет". Если сервис А зависит от срвиса Б, а сервис Б содержит ошибку, даже неважно приводящую к падению или нет, то и А не будет корректно работать.
Падение — не самая страшная часть, даже в проде. Плохо когда: после падения не может подняться, или вместо падения не работает корректно — висит в ожидании или отдает некорректные данные. Причем второе при несинхронной разработке весьма вероятно.

G>>Надежный способ решения это использовать какое-то хранилище, которое поддерживает acid транзакции. Но это и в монолите возможно. Причем в монолите есть простор для оптимизации. Так как можно использовать STM например. Но на практике, когда экземпляров приложения может быть больше одного, все разделяемое состояние надо хранить во внешних, желательно транзакционных, хранилищах.

S>Либо отказываться от разделяемого состояния. Потому что людей, умеющих изготовить полноценное клиент-серверное приложение внутри ACID-хранилища, на рынке не осталось (даже если предположить, что они когда-то были)
Его же не надо "внутри", надо чтобы разделяемое состояние польностью сохранялось и обрабатывалось ACID хранилищем, желательно внешним по отношению к самому приложению. Чтобы приложение можно было безопасно масштабировать и перезапускать.

G>>При горизонтальном масштабировании к этому все и придут обязательно. В принципе грамотный архитектор должен сразу на такое натолкнуть.

S>Вопрос открытый. Чего я только не видел в энтерпрайзе, при самых грамотных архитекторах.
Бывает конечно всякое, и архитекторы, которые не понимают как и почему базы работают. Но в целом это подход по умолчанию: "давайте состояние приложения положим в базу". Раньше по умолчанию выбирали РСУБД, но сейчас уговаривать приходится.

G>>Опять-таки MSA ничем не помогает в этом случае. Без разницы будет мусор писать в базу микросервис или монолит.

S>Нет, разница принципиальная. Микросервис физически не может записать в чужую базу кривую запись о переводе денег.
Ну физически то может. Но сделать это гораздо сложнее чем в монолите.
Но у этой медали есть и обратная сторона: если у вас разные базы, то сделать джоин в них крайне сложно. Задачи которые в монолите бы решались одной строкой в SQL в MSA начинают требовать тонны кода.
Пример реальный: профили пользователей лежат в одном сервисе, данные о туристических маршрутах в другом. Важная часть логики: для несовреннолетних доступна одна часть маршрутов, для соврешеннолетных — другая. Есть еще другие признаки для фильтров: по регионам, интересам итд.
Теперь нам надо сделать рассылку, подобрав подходящие маршруты для клиентов.
В монолите — один джоин. В MSA — пожалуйста напишите тонну кода.
В реальности ситуация была еще хуже. Данные о бронях групп и совершенных путешествиях лежали в третьем сервисе. И конечно же надо было из предложений исключить тех кто уже ездил.


G>>Так это самые важные вопрос. Я еще раз напомню тезис, который в этой теме и другие коллеги подтверждают: MSA это больше про оргструктуру, а не про архитектуру. В интернетах предлагают "правильную" MSA с разделением микросервисов по разным репозитариям исходного кода. Как в этом случае обеспечить синхронность изменений разных микросервисах, если изменяемый бизнес-процесс затрагивает несколько таких микросервисов?

S>Никак — MSA, собственно, и обеспечивает отсутствие синхронности. Это преимущество, а не недостаток.
А в чем собственно преимущество? Ну если в деньгах посчитать.

S>Изменения в бизнес-процессе накатываются постепенно: сначала мы обучаем новостям самый "нижний" микросервис в топологически отсортированном списке микросервисов, затем — чуть более "верхние".

S>Изменения в БП становятся видны в тот момент, когда мы выкатываем изменения "корневого" микросервиса, который оркестрирует весь БП.
Если сервисы имеют строгую иерархию и представляют из себя "слои" приложения, то возможно это и так.
Но сразу три замечания:
1) это цикл внедрения фичи удлиняет. Так как скорости выгоднее делать "вертикальное" деление проекта.
2) Это противоречит мысли самодостаточности сервиса. "Верхний" не работает без "нижних", а "нижние" не нужны без "верних".
3) При падении\ошибке в "нижних" "верхние" тоже ломаются.



S>>>Но с таким подходом мы налетим на те же проблемы и в монолите — если мы ограничимся юнит-тестами компонентов без интеграционного тестирования получится ровно такой же результат.

G>>В msa весьма вероятна ситуация, что в принципе невозможно собрать работающее сочетание микросервисов. Я такое на практике видел. Было три микросервиса (А,Б,В) и два процесса(1,2), затрагивающие три сервиса. В один момент было так, что: А/HEAD, Б/HEAD, В/HEAD~1 работал сценарий 1, но не работал 2. А/HEAD, Б/HEAD~1, В/HEAD работал 2, но не работал 1 и при этом же А/HEAD~1, Б/HEAD, В/HEAD также работал 2, но не работал 1.

G>>И каждый разработчик миросервиса доказывал что "work on my microservice" (современный аналог work on my machine)

S>Это организационная проблема. В монолите все эти команды делали бы ровно то же самое ровно с тем же результатом.
Это в монорепе гораздо сложнее, до уровня "почти невозможно", так как версия всех компонент в монорепе всегда одна. Если вы не балуетесь выносом бизнес-логики во внешние пакеты.

S>А, ну и, возможно, неудачно были проведены границы между микросервисами. Это — отдельное искусство, настолько редкое, что я, ЕМНИП, видел только одно правильное решение (и с десяток заведомо неверных).

Может быть мне так везло, но я участвовал в 6 проектах с MSA и у десятка "стоял рядом" и везде были такие проблемы.
Более того я два проекта с MSA запилил назад в монолит и стало всем лучше. Но там четко одна команда работала над проектом.

G>>Дисциплина, современные среды, языки и библиотеки (я не про Go) позволяют создавать достаточную изоляцию и внутри монолитного приложения, не получая огромных затрат на внесение зависимостей когда они нужны.

S>Может быть. Я не говорю, что MSA — единственный верный способ деятельности
Я делаю более сильное утверждение: MSA пригодна только там, где есть соответствующая оргструктура: много несвязанных команд, каждая из которых работает на процессами, слабо связанными друг с другом. Такое в банках и маркетплейсах такое очень часто встречается, а они составляют основу русского бигтеха.
А например в корпоративных системах оно не надо, как при кастомной разработке, так и при разработке тиражируемого продукта.

G>>Доункаст к чему, если у него нет паблик класса, к которому даункастить?

S>Почему вы думаете, что нету?
S>А если нету — всегда можно запилить reflection. Пытливому уму все средства хороши.
Ну я точно также могу сказать про запись в чужую базу. Оно ведь все равно деплоится все в одно приложение докера\кубера и контейнеры видят друг друга. И все равно разраб сталкивается с тестовой средой, где может "в дикой природе" наблюдать какие еще сервисы работают и с какими хранилищами.

G>>Тут даже комментировать не буду. В дотнете и жабе полно средств изоляции. При желании даже в JS можно инкапсуляцию сделать, чтобы до потрохов никто не добрался.

S>Как раз в JS-то можно. Но, опять же, можно!=делают.
Так и в MSA изоляция зачастую условная. Да, у каждого сервиса база своя, но сервер БД один. Дорого поднимать несколько экзепляров даже постгреса. И учетные данные одни.
Если разработчикам не прививать дисциплину, то никакая изоляция не поможет.

G>>Так можно и в базу другого микросервиса полезть.

S>Невозможно. Базу чужого микросервиса даже не видно. И даже если вдруг чужая база лежит на той же машине, то доступ к ней выдан другому сервис-аккаунту, чем тот, под которым бегает этот микросервис.
Ну-ну. Это на практике может быть в бигтехе, где базы нарезаются отдельной командой и не входят в профиль деплоя. Но пока все приложение это одни набор yaml файлов для docker\kuber — пролезть можно. Опять-таки если недостаточная дисциплина.

Один раз премии лишить за рефлекшн без необходимости и сразу желание пропадет так писать.

G>>В случае единой репы и нормального архитектора — на ревью бить по рукам (или по лицу) за такой код.

S>Это всё хорошо работает до определённых размеров кодовой базы, команды, и уровня ответственности за промахи. Там, где за ошибки принято тюремное заключение или суровые штрафы, делают именно так, не полагаясь на бдительность peer review и личность архитектора.
Ну давай честно: есть предел размера команды или предел структуры управления для монолита. С этим никто не спорит.
Далее возможно развитие или по пути MSA или по пути "ядро\платформа и прикладная часть".
Но до этого предела монолит превосходит MSA по любым параметрам.

G>>Я именно об этом и говорю. Знаю один банк где над таким ядром-"микросервисом" трудится команда из 40+ только программистов. То есть ни разу он не "микро", о чем я и говорю. А выдача кредитов это вообще с десяток связанных процессов, на каждом из которых команда в 10+ человек. То есть их тоже "микро" назвать сложно.

S>Так "micro" это же не про размер команды. А про "площадь поверхности".
Не очень понятно в чем она измеряется.
Re[2]: Помогите правильно спроектировать микросервисное приложение
От: busk  
Дата: 03.04.25 09:07
Оценка:
Здравствуйте, Sinclair, Вы писали:


S>Важно, чтобы микросервисы как можно меньше взаимодействовали между собой. Если не получается — значит, границы выбраны неверно.

S>По вашему описанию не вполне понятно, что собственно должна делать система. Распределять заказы между водителями?
S>Смотрите:
S>0. Сервис аутентификации. Его хочется делать крайне надёжной, т.к. если никто не может зайти, то не работает вообще всё. Очень опасно делать монолит, в котором выкат какой-нибудь мелкой фичи типа "а давайте поздравим всех водителей-женщин с 8 марта" способен сломать логин. То есть эту штуку мы как можно реже релизим, и при каждом выкате покрываем тестами в шесть слоёв. Отдельные пацаны аудируют код на предмет потенциальных уязвимостей, т.к. кража базы паролей — почти самое плохое, что с нами вообще может случиться. Сам сервис скорее всего раскатан в нескольких экземплярах с геодистрибуцией и офигенной избыточностью — чтобы отключение света в нижегородском ДЦ не валило всю федеральную сеть водителей.
S>(Кстати, очень часто мы захотим это вообще делегировать наружу, чтобы не заниматься дорогостоящими инвестициями в эти пять девяток и прочие особенности. Привинчиваем OAuth и полагаемся на Google/Facebook/etc)
S>1. Сервис авторизации. После того, как пользователь залогинился, нам нужно ещё и получить набор его прав. В большинстве случаев это довольно-таки типовая структура, вроде ролей. Опять же, требования к ней довольно-таки жёсткие, т.к. она нужна в каждом первом сценарии. Ещё можно заметить, что она в значительной мере дублирует информацию из 0-й системы — как минимум, у нас должен быть тот же самый список пользователей. Поэтому в современном мире зачастую 0 и 1 объединяют в одну.



вот эти 2 прямо можно в один сервис и отдельную базу, на остальном боюсь не хватит ресурсов и опыта для начала.

а вопрос такой: если это будет винда и один сервер то как проще организовать архитектуру двух сервисов (аутенфикация + авторизация) и всего остального?
докер или один общий шлюз (я так понял приложение) и дальше запрос идет либо на сервис 1 либо на сервис 2?
Re[14]: Помогите правильно спроектировать микросервисное при
От: · Великобритания  
Дата: 03.04.25 10:41
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>·>Гы. Как минимум, память и gc — разделяемые. Так что когда запрос какого-нибудь отчёта для аналитики вдруг роняет по OOM всё сразу, в т.ч. обработку заказов — ничего хорошего.

G>>>Ничего не мешает в рамках монолитного решения вынести отдельный инстанс для обработки тяжелых запросов и на уровне балансера распределять.
G>·>Видимо ты тут намекаешь на какую-то принципиальную разницу между SOA и MSA?
...
G>Тут и паттерны, и технологии, и оргструктуры и много чего еще.
Ок, можно согласится что в разных контекстах/организациях под SOA/MSA понимаются разные вещи. Нет никакого официального математически строгого определения.
Я рассуждаю с т.з. "собираем много разных бинарей, деплоим в разные места с разными опциями".

G>>>Еще раз повторю тезис: MSA это больше про оргструктуру и следующие за ней технические решения.

G>·>По-моему, ты причину со следствием путаешь.
G>А может и наоборот, не задумывался об этом?
Задумывался. Вполне возможно где-то может быть и наоборот в соответствии с карго-культом.

G>Я вижу что микросервисы цветут там, где слишком много команд и разработчиков чтобы пилить монолиты. Поэтому техническая архитектура диктуется оргструктурой. Если у тебя команда небольшая или ты вообще один что-то делаешь — тебе в принципе не нужны микросервисы.

Иногда нужны — если есть соответствующие технические требования.

G>·>А зачем обязательно один бинарник? Если деплоймент разный всё равно. Чтобы были многочасовые билды?

G>А ты думаешь сборка одного толстого бинарника медленнее, чем сборка трех бинарников потоньше? Или ты думаешь что обязательно пересобирать все проекты каждый раз?
Гы. Трёх? Ты тут выше написал о сотне строк на сервис. За "монолит" объёмом на 3 сотни — я всеми конечностями.

G>Да и в целом время сборки для деплоя мало интересует, интересует время от команды run до запуска приложения, если ты это делаешь 25 раз в день.

В мире soa/msa часто бывает так, что запустить приложение ты просто не можешь командой run. Ресурсов на рабочей машине не хватит. Так что run запускаются только некоторые части, чаще просто тесты.

G>·>Сборка, деплой и перезапуск мелкого сервиса занимает минуты от момента мержа PR. Тогда как типичная выкатка монолита — приятно проведённые выходные.

G>В теории да. Но внезапно:
G>1) в микросервисах надо тупо больше кода править
зато общий impact правок ниже.

G>2) если ты затрагиваешь несколько сервисов своим изменением, то несколько сервисов собираются дольше чем один

В msa у тебя будет не три бинарника, а хотя бы тридцать. И работая над очередной фичей типично трогаешь 1-2, в плохих случаях 4-5 бинарников. А вот сборка 2 бинарников от 30 отличается уже на порядок.

G>3) даже докер умеет кэшировать образы, поэтому вполне можно сделать сбору с кэшированием и не пересобирать то, что не изменилось

А дальше? Как потом бинарник будет решать кем он сейчас работает — rest-сервером или fix-коннектором или распределённым кешем? Потребуется нетривиальная система конфигов.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 03.04.2025 11:02 · . Предыдущая версия .
Re[15]: Помогите правильно спроектировать микросервисное при
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.04.25 13:04
Оценка:
Здравствуйте, ·, Вы писали:

G>>Я вижу что микросервисы цветут там, где слишком много команд и разработчиков чтобы пилить монолиты. Поэтому техническая архитектура диктуется оргструктурой. Если у тебя команда небольшая или ты вообще один что-то делаешь — тебе в принципе не нужны микросервисы.

·>Иногда нужны — если есть соответствующие технические требования.
Предположим:
Команда из 10 человек, 7 разрабы, 3 аналитики и тестеры. Используется всеми один стек: условно дотнет и TS\react на клиенте.
Какие могут быть технические требования, чтобы с микросервисами они реализовывались проще, чем без них?


G>>·>А зачем обязательно один бинарник? Если деплоймент разный всё равно. Чтобы были многочасовые билды?

G>>А ты думаешь сборка одного толстого бинарника медленнее, чем сборка трех бинарников потоньше? Или ты думаешь что обязательно пересобирать все проекты каждый раз?
·>Гы. Трёх? Ты тут выше написал о сотне строк на сервис. За "монолит" объёмом на 3 сотни — я всеми конечностями.
уже на трех одновременно пересобираемых микросервисах время сборки монолита оказывается меньше.

G>>Да и в целом время сборки для деплоя мало интересует, интересует время от команды run до запуска приложения, если ты это делаешь 25 раз в день.

·>В мире soa/msa часто бывает так, что запустить приложение ты просто не можешь командой run. Ресурсов на рабочей машине не хватит. Так что run запускаются только некоторые части, чаще просто тесты.
Довольно странное заявление. Почему может не хватить ресурсов запустить проекта, который ничего не делает? Только кривостью рук разработчиков может быть такое решение обосновано.

G>>·>Сборка, деплой и перезапуск мелкого сервиса занимает минуты от момента мержа PR. Тогда как типичная выкатка монолита — приятно проведённые выходные.

G>>В теории да. Но внезапно:
G>>1) в микросервисах надо тупо больше кода править
·>зато общий impact правок ниже.
Я не понимаю что это. Что значит "общий импакт"? Я считаю количество строк\методов\объектов.

G>>2) если ты затрагиваешь несколько сервисов своим изменением, то несколько сервисов собираются дольше чем один

·>В msa у тебя будет не три бинарника, а хотя бы тридцать. И работая над очередной фичей типично трогаешь 1-2, в плохих случаях 4-5 бинарников. А вот сборка 2 бинарников от 30 отличается уже на порядок.
Тогда непонятно с чем ты споришь. Всегда найдется N, такое, что пересборка N микросервисов будет дольше чем пересборка монолита с аналогичным функционалом. Причем это N оказывается довольно небольшим. По моей практике N бывает от 3 до 5.

G>>3) даже докер умеет кэшировать образы, поэтому вполне можно сделать сбору с кэшированием и не пересобирать то, что не изменилось

·>А дальше? Как потом бинарник будет решать кем он сейчас работает — rest-сервером или fix-коннектором или распределённым кешем? Потребуется нетривиальная система конфигов.
Она все равно O(1), то пишется один раз и потом вносятся правки, независимые от объема изменений кода.
А кот конфиг для микросервисов зачастую O(N), так как развитие систем на базе MSA приводит к росту числа микросервисов, что в свою очередь увеличивает объем конфигов.
Re[3]: Помогите правильно спроектировать микросервисное приложение
От: Sinclair Россия https://github.com/evilguest/
Дата: 03.04.25 13:56
Оценка: 3 (1)
Здравствуйте, busk, Вы писали:

B>а вопрос такой: если это будет винда и один сервер то как проще организовать архитектуру двух сервисов (аутенфикация + авторизация) и всего остального?

B>докер или один общий шлюз (я так понял приложение) и дальше запрос идет либо на сервис 1 либо на сервис 2?
Обычно никаких шлюзов нет, и пользователь явно идёт за токеном в сервис номер 1, а уже потом с этим токеном идёт в сервис номер 2.

Можем посмотреть на пример:

Сервис номер 2 расположен по адресу https://graph.microsoft.com/{version}/{resource}?{query-parameters}.
Токены для него получаем из сервиса номер 1 по адресу https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize

Наличие в сервисе 1 авторизации означает, что у вас сервис номер один возвращает в токене не просто идентити пользователя, а и некий набор привилегий, которые сервис номер 2 считывает для принятия решения о том, чего пользователю делать можно, а чего — нельзя. В частности, для Microsoft Graph мы прямо в запросе авторизационного токена сервису логина указываем список scopes, к которым хотим получить доступ. И в случае успеха, токен будет содержать информацию об этом.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Помогите правильно спроектировать микросервисное приложение
От: Sharov Россия  
Дата: 03.04.25 15:39
Оценка:
Здравствуйте, ·, Вы писали:

·>И да, сервисы не через REST взаимодйествуют, а через pub-sub сообщения (kafka/29west/mq/fix/аналоги).


А в чем проблема взаимодействовать по REST'у?
Кодом людям нужно помогать!
Re[8]: Помогите правильно спроектировать микросервисное приложение
От: · Великобритания  
Дата: 03.04.25 20:49
Оценка:
Здравствуйте, Sharov, Вы писали:

S>·>И да, сервисы не через REST взаимодйествуют, а через pub-sub сообщения (kafka/29west/mq/fix/аналоги).

S>А в чем проблема взаимодействовать по REST'у?
Отсутствие гибкости. Rest — это синхронный p2p request-response только. Притом с большим оверхедом в виде http обёртки.
Сообщения — это кто угодно с кем угодно, streaming, множество отправителей/получателей и т.п. В MSA без такого трудно обойтись.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[16]: Помогите правильно спроектировать микросервисное при
От: · Великобритания  
Дата: 03.04.25 21:02
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Я вижу что микросервисы цветут там, где слишком много команд и разработчиков чтобы пилить монолиты. Поэтому техническая архитектура диктуется оргструктурой. Если у тебя команда небольшая или ты вообще один что-то делаешь — тебе в принципе не нужны микросервисы.

G>·>Иногда нужны — если есть соответствующие технические требования.
G>Предположим:
G>Команда из 10 человек, 7 разрабы, 3 аналитики и тестеры. Используется всеми один стек: условно дотнет и TS\react на клиенте.
G>Какие могут быть технические требования, чтобы с микросервисами они реализовывались проще, чем без них?
Ну тут Sinclair вроде рассказывал варианты. Могу рассказать что я видал, но там много чего, а не просто ts/react. Сразу скажу, это торговые системы, где процент веба около нуля.

G>>>А ты думаешь сборка одного толстого бинарника медленнее, чем сборка трех бинарников потоньше? Или ты думаешь что обязательно пересобирать все проекты каждый раз?

G>·>Гы. Трёх? Ты тут выше написал о сотне строк на сервис. За "монолит" объёмом на 3 сотни — я всеми конечностями.
G>уже на трех одновременно пересобираемых микросервисах время сборки монолита оказывается меньше.
Очень сомневаюсь, когда бинарников десятки.

G>>>Да и в целом время сборки для деплоя мало интересует, интересует время от команды run до запуска приложения, если ты это делаешь 25 раз в день.

G>·>В мире soa/msa часто бывает так, что запустить приложение ты просто не можешь командой run. Ресурсов на рабочей машине не хватит. Так что run запускаются только некоторые части, чаще просто тесты.
G>Довольно странное заявление. Почему может не хватить ресурсов запустить проекта, который ничего не делает? Только кривостью рук разработчиков может быть такое решение обосновано.
А зачем вообще запускать что-то, что ничего не делает? Ты уж определись.

G>·>зато общий impact правок ниже.

G>Я не понимаю что это. Что значит "общий импакт"? Я считаю количество строк\методов\объектов.
Что обновив какой-нибудь условный коннектор с платёжной системой можно сломать только платежи, а не всю систему.

G>>>2) если ты затрагиваешь несколько сервисов своим изменением, то несколько сервисов собираются дольше чем один

G>·>В msa у тебя будет не три бинарника, а хотя бы тридцать. И работая над очередной фичей типично трогаешь 1-2, в плохих случаях 4-5 бинарников. А вот сборка 2 бинарников от 30 отличается уже на порядок.
G>Тогда непонятно с чем ты споришь. Всегда найдется N, такое, что пересборка N микросервисов будет дольше чем пересборка монолита с аналогичным функционалом. Причем это N оказывается довольно небольшим. По моей практике N бывает от 3 до 5.
Ну видимо какие-то простые маленькие системы в твоей практике были.

G>·>А дальше? Как потом бинарник будет решать кем он сейчас работает — rest-сервером или fix-коннектором или распределённым кешем? Потребуется нетривиальная система конфигов.

G>Она все равно O(1), то пишется один раз и потом вносятся правки, независимые от объема изменений кода.
G>А кот конфиг для микросервисов зачастую O(N), так как развитие систем на базе MSA приводит к росту числа микросервисов, что в свою очередь увеличивает объем конфигов.
Так растёт число не само по себе, а потому что добавляется новая функциональность, которую надо конфигурить — адреса-пароли-явки.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[9]: Помогите правильно спроектировать микросервисное приложение
От: Sharov Россия  
Дата: 03.04.25 22:33
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, Sharov, Вы писали:


S>>·>И да, сервисы не через REST взаимодйествуют, а через pub-sub сообщения (kafka/29west/mq/fix/аналоги).

S>>А в чем проблема взаимодействовать по REST'у?
·>Отсутствие гибкости. Rest — это синхронный p2p request-response только. Притом с большим оверхедом в виде http обёртки.
·>Сообщения — это кто угодно с кем угодно, streaming, множество отправителей/получателей и т.п. В MSA без такого трудно обойтись.

А что мешает его сделать асинхронным?
Кодом людям нужно помогать!
Re[9]: Помогите правильно спроектировать микросервисное приложение
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.04.25 01:14
Оценка:
Здравствуйте, ·, Вы писали:

·>Отсутствие гибкости. Rest — это синхронный p2p request-response только. Притом с большим оверхедом в виде http обёртки.

·>Сообщения — это кто угодно с кем угодно, streaming, множество отправителей/получателей и т.п. В MSA без такого трудно обойтись.
Вот с чем никогда в жизни не работал — так это с описываемой вами архитектурой.
Как в ней решаются вопросы
1. Согласованности: чтобы вся эта слабосвязанная мешанина реально делала то, что нужно?
2. Зависимостей — как мне понять, сколько сервисов нужно запустить, чтобы реализовался сценарий X? Чтобы не получилось, как в анекдоте: "один копает ямы, а другой закапывает; ещё один должен был туда деревья вставлять, но он не пришёл".
3. Предотвращения лайв-локов: один сервис ждёт с шины сообщение А, потом отправит сообщение Б. Другой сервис как раз ждёт сообщение Б, чтобы отправить А

Если есть какая-то книжка на эту тему — отправьте в неё, пожалуйста
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: Помогите правильно спроектировать микросервисное при
От: Miroff Россия  
Дата: 04.04.25 03:24
Оценка: 82 (1) +1
Здравствуйте, Sinclair, Вы писали:

S>Вот с чем никогда в жизни не работал — так это с описываемой вами архитектурой.


В такой архитектуре, думают не через сценарии, а через доменные сущности, их состояния и переходы между ними. Сквозные сценарии либо реализуются сами собой, в том числе и те, о которых бизнес аналитики даже и не подозревали, либо путем создания дополнительных доменных сущностей по общему правилу:
1. Сервис отвечает за свои, и только свои, доменные объекты и является для них единственным источником правды
2. Сервис принимает команды на изменение состояния своих объектов
3. Сервис отправляет нотификации о ВСЕХ изменениях ВСЕХ своих объектов независимо от того, нужна кому-то эта информация или не нужна
4. Сервис может подписываться только на нотификации об изменениях в других сервисах и только на команды, адресованные непосредственно этому сервису. Нельзя подписаться на команды другого сервиса.

S>1. Согласованности: чтобы вся эта слабосвязанная мешанина реально делала то, что нужно?


В рамках доменной области у тебя всегда будет eventual consistency, до той степени, какую обеспечивает твоя доменная модель. Реальный мир устроен схожим образом: большинство бизнес процессов могут прерваться на середине и в этом нет ничего страшного.

S>2. Зависимостей — как мне понять, сколько сервисов нужно запустить, чтобы реализовался сценарий X? Чтобы не получилось, как в анекдоте: "один копает ямы, а другой закапывает; ещё один должен был туда деревья вставлять, но он не пришёл".


Никак. Тебе как разработчику нужно понять какой последовательности изменений состояния доменных сущностей соответствует твой сценарий, либо, если это невозможно, добавить новые доменные сущности. Ровно как в REST, если изменение не укладывается в CRUD над имеющимися ресурсами, ты добавляет новый ресурс в который изменение укладывается.

Ситуации в духе "но тот, который деревья сажает сегодня не пришел" для такой архитектуры скорее норма, чем исключение.

S>3. Предотвращения лайв-локов: один сервис ждёт с шины сообщение А, потом отправит сообщение Б. Другой сервис как раз ждёт сообщение Б, чтобы отправить А


Это не RPC, сервис ничего не ждёт. Сервис отправляет запрос на изменение и забывает о нем. Если сервису важно, чтобы запрос отработал в за какой-то тайм-аут, он проверяет изменения спустя какое-то время и если изменений не произошло, шлет команду на отмену.

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

Рассылки это новый домен относительно пользователй и туров, значит нужен новый сервис. Этому сервису необходимы пользователи, туры и поездки, значит подписываемся на изменения в трёх доменах. От пользователей храним е-мейл и возраст, от тура храним описание, от поездки храним сам факт связи пользователя и тура. Все это складываем в контекст и из контекста извлекаем что кому рекомендовать. При рассылке отправляем нотификации: создана рассылка для пользователя X приглашающая в туры {Y}. И такая система получается очень гибкой и расширяемой. Если нам нужно поменять правила рассылки, мы меняем один сервис. Если нужны новые данные, добавляем подписки. Если нужно действие после рассылки, добавляем нового подписчика. И т.п.

Разумеется, у такой архитектуры полно недостатков: нужен глубокий анализ домена, нужно бить по рукам тем, кто пытается домен ломать, полная схема взаимодействий становится очень сложной и превращается в комбинаторную стейт машину через которую практически невозможно протащить единичный сценарий, авторизация становится нетривиальным занятием. Но зато можно поддерживать небольшой командой в 10-15 человек несколько сотен микросервисов почти не напрягаясь.

S>Если есть какая-то книжка на эту тему — отправьте в неё, пожалуйста


Можно начать со знакомства с моделью акторов на практике
https://www.oreilly.com/library/view/reactive-messaging-patterns/9780133846904/
https://www.oreilly.com/library/view/applied-akka-patterns/9781491934876/ch01.html
Либо поискать что-то более фундаментальное.
Отредактировано 08.04.2025 7:53 Miroff . Предыдущая версия .
Re[10]: Помогите правильно спроектировать микросервисное приложение
От: TG  
Дата: 04.04.25 05:55
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Вот с чем никогда в жизни не работал — так это с описываемой вами архитектурой.

S>Как в ней решаются вопросы
S>1. Согласованности: чтобы вся эта слабосвязанная мешанина реально делала то, что нужно?
S>2. Зависимостей — как мне понять, сколько сервисов нужно запустить, чтобы реализовался сценарий X? Чтобы не получилось, как в анекдоте: "один копает ямы, а другой закапывает; ещё один должен был туда деревья вставлять, но он не пришёл".
S>3. Предотвращения лайв-локов: один сервис ждёт с шины сообщение А, потом отправит сообщение Б. Другой сервис как раз ждёт сообщение Б, чтобы отправить А

S>Если есть какая-то книжка на эту тему — отправьте в неё, пожалуйста


Только оркестрацией сервисов. Например, https://github.com/temporalio/temporal.
Re[11]: Помогите правильно спроектировать микросервисное приложение
От: TG  
Дата: 04.04.25 06:01
Оценка: +1
Здравствуйте, Miroff, Вы писали:

Как у Вас это:
M>Разумеется, у такой архитектуры полно недостатков: нужен глубокий анализ домена, нужно бить по рукам тем, кто пытается домен ломать, полная схема взаимодействий становится очень сложной и превращается в комбинаторную стейт машину через которую практически невозможно протащить единичный сценарий, авторизация становится нетривиальным занятием.
сочетается с этим:
M> Но зато можно поддерживать небольшой командой в 10-15 человек несколько сотен микросервисов почти не напрягаясь.
?

Что понимается под поддержкой?
Re[11]: Каких программ вам не хватает?
От: Miroff Россия  
Дата: 04.04.25 06:11
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Это заблуждение. Авторизация проверяется совершенно отдельно. Ещё не хватало в представлении ресурса показывать разный набор ссылок в зависимости от transient штуки вроде Bearer-токена.


Можно это как-то обосновать? Мне кажется, мы о разных вещах говорим. Есть ресурс, есть набор связанных ресурсов с которыми можно проделывать какие-то операции. HATEOS позволяет НЕ ВЫЗЫВАЯ операций предсказать, будут они доступны клиенту или нет. Например, в списке сотрудников рядом с именем Sinclair либо показывать кнопку "объявить выговор" или не показывать. И чтобы это реализовать без HATEOAS часть логики авторизации, кому можно налагать взыскания и на кого, вынужденно скопируется из сервиса в его клиента. А поскольку мы сейчас обсуждаем микросервисную архитектуру, где акторами являются не только пользователи, но и другие сервисы, эта логика начинает неконтролируемо расползаться по системе. Как в примере из соседнего поста, когда сервис туров следит чтобы определенные туры были доступны только совершеннолетним пользователям и эта же логика дублируется в сервисе рекомендаций чтобы не показывать несоврешеннолетним то, что им и так недоступно. HATEOAS бы эту проблему решил докинув ресурс user список доступных для него туров.

S>Да, пейджинг — это один из немногих случаев корректного и полезного применения ссылок. Но вообще, его изготовить правильно — очень сложно. Сильно сложнее, чем кажется на первые три взгляда. В частности, "список страниц, которые можно дёрнуть" — плохая идея, которая ломается в большом количестве сценариев.


Опять же, можешь раскрыть тему? Пейджинг это простая штука если перестать думать о нем, как о RPC и начать думать как об отдельном ресурсе. Ты СОЗДАЕШЬ отдельный объект "поисковый запрос" и в ответ получаешь список страниц с результатами этого запроса. И, внезапно, у тебя уже нет проблем со стабильностью, сортировки, изменению состава страниц, кэшированию и т.п. Результат фиксируется в момент создания запроса и далее до нового поиска уже не меняется.

S>В частности, приделывание к платёжке ссылки refund с методом POST — это RMM не L3, а L1. Потому, что нормальный способ — это PUT либо PATCH, которые прямым либо косвенным образом меняют состояние платежа на refunded.


Нет. POST refund это создание ДРУГОГО ресурса. Другого потому что у него другой URI. Нужно думать о рефанде не как об изменении платежа, а как ос создании нового объекта — сторнирующей операции, потому что сам платеж изменять не позволяет принцип двойной бухгалтерии известный с 17 века: сделанная проводка не может быть удалена.

S>Конечно позволяет. Вот у вас есть объект, у него есть представление. Всё, можно делать PUT этого представления. Если что-то запрещено бизнес-правилами — приедет 409. Если правами доступа — 403.


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

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


Людям вообще нравится RPC, даже по этой теме видно. Но RPC не дает необходимой для микросервисов изоляции и довольно быстро превращает приложение в распределенный монолит.
Re[5]: Помогите правильно спроектировать микросервисное приложение
От: Miroff Россия  
Дата: 04.04.25 06:19
Оценка:
Здравствуйте, TG, Вы писали:

TG>API приложения полностью зависит от нужд потребителя. Договариваться придётся.


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

Альтернатива — дизайн от доменной модели, когда ты определяешь доменные сущности, их состояния и переходы между ними и выставляешь полное API для манипулирования этими сущностями не беспокоясь о том, нужно кому-то это прямо сейчас или нет. Это позволяет клиентам твоего сервиса реализовать любой сценарий не дергая тебя и не требуя изменений твоего API. Это и есть полноценная микросервисная архитектура.
Re[6]: Помогите правильно спроектировать микросервисное приложение
От: TG  
Дата: 04.04.25 07:14
Оценка:
Здравствуйте, Miroff, Вы писали:

TG>>API приложения полностью зависит от нужд потребителя. Договариваться придётся.


M>Дизайн от сценариев лишь один из возможных подходов. Если ты дизайнишь API в расчете на пользователя, пользователь, конечно рад, но при каждом изменении сценариев потребителя тебе приходится подстраивать под них свое API, а если потребителей много то еще и увязывать их сценарии между собой. В результате ты делаешь кучу ненужной работы, переусложняешь свой сервис и в конце концов обнаруживаешь себя внутри распределенного монолита.


Почему ненужной? Пользователи/клиенты же просили.
И если клиент готов платить, почему не делать?
А если мы не можем удобно увязать сценарии разных клиентов, то, может, им просто нужны разные сервисы и это мы не правы, пытаясь скрестить ужа с ежом?

M>Альтернатива — дизайн от доменной модели, когда ты определяешь доменные сущности, их состояния и переходы между ними и выставляешь полное API для манипулирования этими сущностями не беспокоясь о том, нужно кому-то это прямо сейчас или нет. Это позволяет клиентам твоего сервиса реализовать любой сценарий не дергая тебя и не требуя изменений твоего API. Это и есть полноценная микросервисная архитектура.


Что Вы понимаете под доменной моделью?
И что значит "полное API"?
Re[7]: Помогите правильно спроектировать микросервисное приложение
От: Miroff Россия  
Дата: 04.04.25 07:25
Оценка:
Здравствуйте, TG, Вы писали:

TG>И если клиент готов платить, почему не делать?


Если цель доить заказчиков, это отличный вариант. Именно так и получаются команды в 400 разработчиков для поддержки небольшой региональной логистической системы.

TG>Что Вы понимаете под доменной моделью?


https://martinfowler.com/bliki/DomainDrivenDesign.html

TG>И что значит "полное API"?


Возможность достигнуть любого состояния системы посредством API. CRUD на все доменныек сущности плюс переходы по всем возможным состояниям.
Re[10]: Помогите правильно спроектировать микросервисное приложение
От: · Великобритания  
Дата: 04.04.25 07:32
Оценка:
Здравствуйте, Sharov, Вы писали:

S>·>Отсутствие гибкости. Rest — это синхронный p2p request-response только. Притом с большим оверхедом в виде http обёртки.

S>·>Сообщения — это кто угодно с кем угодно, streaming, множество отправителей/получателей и т.п. В MSA без такого трудно обойтись.
S>А что мешает его сделать асинхронным?
Спека http. Я наверное неточно выразился, я имел в виду, что на каждый запрос приходит ответ, который надо прочитать, даже если это "204 No Content". Притом ответ ровно один.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[8]: Помогите правильно спроектировать микросервисное приложение
От: TG  
Дата: 04.04.25 10:09
Оценка:
Здравствуйте, Miroff, Вы писали:

TG>>И если клиент готов платить, почему не делать?

M>Если цель доить заказчиков, это отличный вариант. Именно так и получаются команды в 400 разработчиков для поддержки небольшой региональной логистической системы.

Пусть об этом голова у менеджмента болит.

TG>>И что значит "полное API"?

M>Возможность достигнуть любого состояния системы посредством API. CRUD на все доменныек сущности плюс переходы по всем возможным состояниям.

Так сервис может не ограничиваться CRUD-ом и состояниями.
Построение маршрута там же Яндекс.Карты, например.
Какое там "полное API" для всех клиентов можно выкатить?
Re[9]: Помогите правильно спроектировать микросервисное приложение
От: Miroff Россия  
Дата: 04.04.25 10:16
Оценка: +1
Здравствуйте, TG, Вы писали:

TG>Так сервис может не ограничиваться CRUD-ом и состояниями.

TG>Построение маршрута там же Яндекс.Карты, например.
TG>Какое там "полное API" для всех клиентов можно выкатить?

Посмотри на API OpenStreetMap, версия 0.7 вышла 15 лет назад когда, еще JSON не изобрели, и с тех пор ее не апдейтили потому что и так хорошо вышло. Так бывает, когда API проектируют инженеры, а не менеджеры.
Re[10]: Помогите правильно спроектировать микросервисное приложение
От: TG  
Дата: 04.04.25 10:37
Оценка:
Здравствуйте, Miroff, Вы писали:

TG>>Так сервис может не ограничиваться CRUD-ом и состояниями.

TG>>Построение маршрута там же Яндекс.Карты, например.
TG>>Какое там "полное API" для всех клиентов можно выкатить?

M>Посмотри на API OpenStreetMap, версия 0.7 вышла 15 лет назад когда, еще JSON не изобрели, и с тех пор ее не апдейтили потому что и так хорошо вышло. Так бывает, когда API проектируют инженеры, а не менеджеры.

Это не означает, что все довольны.

Вот, допустим, я заказчик/клиент Яндекс.Карт, OSM и т.д.
Задача: построить маршрут с условиями:
— маршрут не должен проходить по дорогам общего пользования (в том числе грунтовым) и вообще не должен приближаться к ним ближе, чем на 5 км.
— если без пересечения дорог общего пользования не обойтись, то пересечение маршрута с ними должно идти под углом, близким к прямому
— нельзя прокладывать маршрут по: болотам, лесам, возвышенностям
— нельзя прокладывать маршрут по определенным зонам, задаваемым пользователем в запросе.

Какое готовое API известных сервисов картографии такое уже умеет?
Re[13]: Помогите правильно спроектировать микросервисное приложение
От: SkyDance Земля  
Дата: 04.04.25 17:26
Оценка:
·>Сборка, деплой и перезапуск мелкого сервиса занимает минуты от момента мержа PR. Тогда как типичная выкатка монолита — приятно проведённые выходные.

Беда приходит тогда, когда требуется поменять код, общий для многих/всех микросервисов. Например, добавить (m)TLS, или еще что-то такое. Любой инфраструктурный проект в МСА вызывает многолетнюю попаболь, и приводит к жутчайшим штуковинам типа Istio и прочим service-mesh'ам.
Re[8]: Помогите правильно спроектировать микросервисное приложение
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 05.04.25 15:51
Оценка: +1
Здравствуйте, Sharov, Вы писали:

S>А в чем проблема взаимодействовать по REST'у?

В том, что его применяют там, где он не нужен. У меня в последнее время есть сомнения что народ в массе понимает что такое REST и зачем он нужен.
Sic luceat lux!
Re[12]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.04.25 06:09
Оценка: 8 (1)
Здравствуйте, Miroff, Вы писали:

M>Можно это как-то обосновать?

Можно. Когда я делаю GET на ресурс, я получаю его представление. Крайне желательно, чтобы это представление зависело от состояния ресурса, а не от состояния пользователя, который его получает.
Например, можно воткнуть reverse proxy перед сервером приложения, и тогда он сможет снять значительную часть нагрузки с сервера.
Как только мы начинаем менять представление объекта в зависимости от пользователя, о кэшировании можно забыть.

M>Мне кажется, мы о разных вещах говорим. Есть ресурс, есть набор связанных ресурсов с которыми можно проделывать какие-то операции.

Тут всё верно. Ресурсы обычно связаны друг с другом не искусственными линками, а естественным образом, спрятанным в представлении.
Возьмём, к примеру, ресурс Payment.
Вот как выглядит представление этого ресурса через PayPal API:
{
  "id": "0VF52814937998046",
  "status": "CREATED",
  "amount": {
    "value": "10.99",
    "currency_code": "USD"
  },
  "invoice_id": "INVOICE-123",
  "seller_protection": {
    "status": "ELIGIBLE",
    "dispute_categories": [
      "ITEM_NOT_RECEIVED",
      "UNAUTHORIZED_TRANSACTION"
    ]
  },
  "payee": {
    "email_address": "merchant@example.com",
    "merchant_id": "7KNGBPH2U58GQ"
  },
  "expiration_time": "2017-10-10T23:23:45Z",
  "create_time": "2017-09-11T23:23:45Z",
  "update_time": "2017-09-11T23:23:45Z",
  "links": [
    {
      "rel": "self",
      "method": "GET",
      "href": "https://api-m.paypal.com/v2/payments/authorizations/0VF52814937998046"
    },
    {
      "rel": "capture",
      "method": "POST",
      "href": "https://api-m.paypal.com/v2/payments/authorizations/0VF52814937998046/capture"
    },
    {
      "rel": "void",
      "method": "POST",
      "href": "https://api-m.paypal.com/v2/payments/authorizations/0VF52814937998046/void"
    },
    {
      "rel": "reauthorize",
      "method": "POST",
      "href": "https://api-m.paypal.com/v2/payments/authorizations/0VF52814937998046/reauthorize"
    }
  ]
}

Этот ресурс, судя по всему, связан с другим ресурсом — invoice. Но никаких намёков на то, как получить информацию об этом ресурсе, внутри ресурса нет. И линков тоже нет. Зато есть линки про то, как изменить состояние этого же ресурса. Так что это никакой не REST.
В настоящем хардкорном RMM3 REST вместо атрибута invoice_id был бы атрибут invoice со значением "https://www.paypal.com/invoice/details/INVOICE-123".

M>HATEOS позволяет НЕ ВЫЗЫВАЯ операций предсказать, будут они доступны клиенту или нет.

Нет, ничего подобного HATEOAS не предполагает. Нет никакой гарантии, что операции будут доступны. Нет никакой гарантии, что никаких других операций нет.

M>Например, в списке сотрудников рядом с именем Sinclair либо показывать кнопку "объявить выговор" или не показывать. И чтобы это реализовать без HATEOAS часть логики авторизации, кому можно налагать взыскания и на кого, вынужденно скопируется из сервиса в его клиента.

Нет конечно. Зачем? Это крайне контрпродуктивная идея.
Во-первых, "объявление выговора" в REST-системе — это не операция с "сотрудником с именем Синклер". Это создание ресурса "выговор". А точнее — создание ресурса "приказ об объявлении выговора".
В котором могут фигурировать, к примеру, несколько сотрудников. И права на создание этого выговора весьма косвенно связаны с перечисленными там сотрудниками.
Во-вторых, построение безопасности путём скрытия действий в UI — это популярная, но плохая идея. В основном — потому, что она неимоверно бесит пользователей. Вот я сижу перед списком пользователей, хочу объявить выговор. Поискал в меню — нет такой команды. Поискал в свойствах сотрудника — нет такой кнопки. Полез в инструкцию — сказано "для объявления выговора нажмите на кнопку "Объявить выговор". И вот я уже полчаса думаю, то ли я дурак, то ли инструкция устарела, то ли программа глючит. Внезапно, "некрасивый" способ — дать мне нажать на кнопку, а потом вывести "403 у вас недостаточно прав для объявления выговора этому сотруднику" — в разы гуманнее по отношению к пользователю, чем предлагаемая вами идея.

M>А поскольку мы сейчас обсуждаем микросервисную архитектуру, где акторами являются не только пользователи, но и другие сервисы, эта логика начинает неконтролируемо расползаться по системе.

Ничего никуда не расползается. Зачем? Микросервис просто делает свою работу. Поймите, нельзя строить микросервис на том, что "я прочитал ресурс — если нет ссылки, значит нельзя рефандить и надо идти по ветке А, а если ссылка есть — то надо идти по ветке Б и выполнять рефанд". Возможно, настройки прав или ешё что-то поменялось между чтением ресурса и переходом по ссылке; всегда можно получить в ответ "403". Так что вместо вот этой вот двухшаговой наркомании "если ссылка, то идём по ветке Б, и если получили 403, то переключаемся обратно на ветку А". Просто идём и пытаемся сделать рефанд, не делая никаких предположений о правах там и всём остальном.

M>Как в примере из соседнего поста, когда сервис туров следит чтобы определенные туры были доступны только совершеннолетним пользователям и эта же логика дублируется в сервисе рекомендаций чтобы не показывать несоврешеннолетним то, что им и так недоступно. HATEOAS бы эту проблему решил докинув ресурс user список доступных для него туров. ,


Это очень, очень плохая архитектура. В первую очередь потому, что вы инвертируете зависимости. Теперь у вас ресурс user (и его микросервис) обязан знать всё о турах (которые вообще-то обрабатываются другим микросервисом).
А ресурс "тур", ясное дело, должен знать всё о пользователях. Поздравляю, вы получили не просто монолит, а трудноразвиваемый монолит.

M>Опять же, можешь раскрыть тему? Пейджинг это простая штука если перестать думать о нем, как о RPC и начать думать как об отдельном ресурсе. Ты СОЗДАЕШЬ отдельный объект "поисковый запрос" и в ответ получаешь список страниц с результатами этого запроса. И, внезапно, у тебя уже нет проблем со стабильностью, сортировки, изменению состава страниц, кэшированию и т.п. Результат фиксируется в момент создания запроса и далее до нового поиска уже не меняется.

И это — тоже очень, очень плохая архитектура. Смотрите как это работает: "поисковый запрос" — это эфемерный ресурс. Последнее, что мы хотим — это хранить его. В первую очередь по соображениям масштабирования. Сколько пользователей вы ожидаете ежедневно? Двух? Как только у вас появляется хотя бы несколько сотен тысяч запросов в сутки, хранение (даже в течение ограниченного времени) их эфемерных запросов становится неподъёмным.
Как раз наоборот — пользователь, который получил в ответ на поиск информацию о том, что нашлось 100000 страниц, скорее всего выполнит новый запрос, потому что этот оказался недостаточно точным.
Нет, бывают такие ситуации, когда поиск сам по себе очень дорогой, и мы как отдельную фичу предлагаем "сохранение запросов", да ещё и иногда с оповещениями об изменениях. Но в простых гражданских случаях это не работает, и поиск делается поверх реалтаймовых данных, а не поверх какого-то снапшота, полученного неведомо когда.
И вот в такой обстановке "традиционный" пейджинг в стиле "дай мне позиции с 120 по 139" — тупиковая ветвь проектировщицкой мысли. Единственное его достоинство — простота реализации.
Зато недостатки у него принципиальные — в частности, невозможность восстановить целостную картину.

Есть несколько способов решить эту проблему. Один из них — примерно то, что вы предлагаете, "думать о запросе как об отдельном ресурсе", только правильно реализованный.
Правильно — значит иметь один ресурс "поисковый запрос". Несмотря на его эфемерность, он вполне реален. То есть не два разных ресурса "пользователи на букву А с 0 по 99" и "пользователи на букву А с 100 по 199", а один ресурс "пользователи на букву А". Если этот ресурс слишком велик для прожёвывания его одним запросом, то мы добавляем к запросу range header и тащим комфортными для нас частями.
А непротиворечивость гарантируется тем, что последующие запросы мы дооборудуем хидером if-match/if-none-match, что позволяет нам заметить момент, когда данные на серверной стороне поменялись, и закешированную версию нужно выкинуть.

M>Нет. POST refund это создание ДРУГОГО ресурса. Другого потому что у него другой URI. Нужно думать о рефанде не как об изменении платежа, а как ос создании нового объекта — сторнирующей операции, потому что сам платеж изменять не позволяет принцип двойной бухгалтерии известный с 17 века: сделанная проводка не может быть удалена.

Отлично, давайте зайдём с этого конца. Хотя там, если покопать в API, будет пачка методов по изменению именно того же объекта (https://developer.paypal.com/docs/api/payments/v2/#authorizations_reauthorize).
В нормальном REST избегают POST методов, поскольку в случае потери результата POST крайне сложно понять, чем там кончилось дело, и что делать теперь.
К сожалению, авторы PayPal API книжек по REST-у не читали. Поэтому у них нет ничего идемпотентного.

M>Это требует проделать вызов. В микросервисной архитектуре такой подход означает что сценарий клиента может развалиться в середине выполнения и, как следствие, для каждого сложного сценария потребуется делать распределенные транзакции с откатом. Так, конечно, можно делать, но это очень дорого. Поэтому в большинстве случаев ты сперва делаешь пречек собирая все доступные ресурсы, проверяешь пререквизиты и только потом начинаешь выполнять изменения.

Простите, но вы рассказываете какие-то небылицы. Что такое "пречеки"? Мы пробежались по всем нужным ресурсам, и убедились, что все нужные нам "действия" торчат в виде линков?
Ну так это ничего не значит. Посмотрите в тот же PayPal API — там очень редко бывает так, что достаточно POST с пустым телом. То есть — результат будет зависеть от параметров запроса. А их вы никаким пречеком не проверите (если в API нет специального метода precheck). Поэтому — да, либо rollback (если вдруг у нас есть детерминированный способ сделать rollback), либо rollforward. Чудес не бывает.
Если вы собрались изображать в любой архитектуре, хоть микросервисной, хоть монолитной, композитный сценарий вроде "запросили кредит — перевели деньги на расчётный счёт — расплатились за покупку товара", то он всегда может сфейлиться на каждом этапе. В прошлом веке для этого применяли протокол двухфазного коммита. Сейчас у нас два варианта:
— реализовать двухфазный коммит (каждый из этапов на самом деле делается в виде двух отдельных методов типа "подготовить ресурс" и "использовать ресурс"; при этом подготовленный ресурс после некоторого таймаута саморассасывается.
— понимать, что мы можем застрять посреди процесса — например, с выданным кредитом, но без дефицитной игровой приставки, которую успели купить.
Никакие "пречеки" тут не помогут, если нет реального резервирования ресурсов.

M>Людям вообще нравится RPC, даже по этой теме видно. Но RPC не дает необходимой для микросервисов изоляции и довольно быстро превращает приложение в распределенный монолит.

RPC людям нравится не за то, что у него есть преимущества, а за то, что они не сразу видят его недостатки.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Каких программ вам не хватает?
От: TG  
Дата: 07.04.25 06:58
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Во-вторых, построение безопасности путём скрытия действий в UI — это популярная, но плохая идея. В основном — потому, что она неимоверно бесит пользователей. Вот я сижу перед списком пользователей, хочу объявить выговор. Поискал в меню — нет такой команды. Поискал в свойствах сотрудника — нет такой кнопки. Полез в инструкцию — сказано "для объявления выговора нажмите на кнопку "Объявить выговор". И вот я уже полчаса думаю, то ли я дурак, то ли инструкция устарела, то ли программа глючит. Внезапно, "некрасивый" способ — дать мне нажать на кнопку, а потом вывести "403 у вас недостаточно прав для объявления выговора этому сотруднику" — в разы гуманнее по отношению к пользователю, чем предлагаемая вами идея.


Ну, идея как-то промаркировать элементы в списке, с которыми я могу что-то делать и с которыми не могу, вполне нормальная.
Жмякнуть на кнопку, подождать стандартный таймаут в 60 сек. и получить отлуп, может выбешивать не меньше.
Re[14]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.04.25 07:29
Оценка:
Здравствуйте, TG, Вы писали:

TG>Ну, идея как-то промаркировать элементы в списке, с которыми я могу что-то делать и с которыми не могу, вполне нормальная.

Нет.
TG>Жмякнуть на кнопку, подождать стандартный таймаут в 60 сек. и получить отлуп, может выбешивать не меньше.
Не очень понятно, откуда взялся "стандартный таймаут". Большинство сервисов отвечают в течение 1-2 секунд. Это я говорю про обращения с другого континента.
А уж если им и делать ничего не надо, а только вернуть ошибку — то ещё быстрее.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Каких программ вам не хватает?
От: TG  
Дата: 07.04.25 08:46
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, TG, Вы писали:


TG>>Ну, идея как-то промаркировать элементы в списке, с которыми я могу что-то делать и с которыми не могу, вполне нормальная.

S>Нет.

Сайты с бесплатными объявлениями бывают вываливают в поиске архивные объявления и какие-то кнопки там неактивны.
Мы такой подход не одобряем (с), но тамошние маркетологи, видимо, имеют другое мнение.
Я не призываю делать бан кнопок через HATEOAS. Но чем сама идея такого UI плоха?

TG>>Жмякнуть на кнопку, подождать стандартный таймаут в 60 сек. и получить отлуп, может выбешивать не меньше.

S>Не очень понятно, откуда взялся "стандартный таймаут".

"Стандартный таймаут" — который часто выставляет фреймворк, например, WCF. Кто-то вообще не заморачивается на эти таймауты и оставляет всё по умолчанию.

S> Большинство сервисов отвечают в течение 1-2 секунд. Это я говорю про обращения с другого континента.

S>А уж если им и делать ничего не надо, а только вернуть ошибку — то ещё быстрее.

Это, скажем так, в норме. За городом на мобильном интернете лаг уже составляет секунды.
Да и в "городском" энтерпрайзе пользователи могут столкнуться с тормозами, если они сидят через VPN и админы как-то криво "раскрасили" трафик.
Re[16]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.04.25 11:22
Оценка: 2 (1)
Здравствуйте, TG, Вы писали:

TG>Я не призываю делать бан кнопок через HATEOAS. Но чем сама идея такого UI плоха?

Сама идея такого UI плоха тем, что
1. не даёт пользователю никакой информации о причинах того, что кнопка неактивна. То ли у пользователя нет прав; то ли у объявления истёк срок доступности этой кнопки; то ли просто баг на сайте.
2. даёт пользователю неверную информацию — состояние кнопки вычисляется в момент t0, а нажатие на эту кнопку происходит в произвольный момент t1, где разница между t1 и t0 может составлять дни, а не секунды.


TG>"Стандартный таймаут" — который часто выставляет фреймворк, например, WCF. Кто-то вообще не заморачивается на эти таймауты и оставляет всё по умолчанию.

Я не понимаю, какое отношение стандартный таймаут имеет к вопросу о проектировании UI.

TG>Да и в "городском" энтерпрайзе пользователи могут столкнуться с тормозами, если они сидят через VPN и админы как-то криво "раскрасили" трафик.


И это всё ещё лучше, чем прятать от пользователя возможность без объяснения причин.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Каких программ вам не хватает?
От: Miroff Россия  
Дата: 08.04.25 07:14
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Можно. Когда я делаю GET на ресурс, я получаю его представление. Крайне желательно, чтобы это представление зависело от состояния ресурса, а не от состояния пользователя, который его получает.

S>Например, можно воткнуть reverse proxy перед сервером приложения, и тогда он сможет снять значительную часть нагрузки с сервера.
S>Как только мы начинаем менять представление объекта в зависимости от пользователя, о кэшировании можно забыть.

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

S>Во-вторых, построение безопасности путём скрытия действий в UI — это популярная, но плохая идея. В основном — потому, что она неимоверно бесит пользователей. Вот я сижу перед списком пользователей, хочу объявить выговор. Поискал в меню — нет такой команды. Поискал в свойствах сотрудника — нет такой кнопки. Полез в инструкцию — сказано "для объявления выговора нажмите на кнопку "Объявить выговор". И вот я уже полчаса думаю, то ли я дурак, то ли инструкция устарела, то ли программа глючит. Внезапно, "некрасивый" способ — дать мне нажать на кнопку, а потом вывести "403 у вас недостаточно прав для объявления выговора этому сотруднику" — в разы гуманнее по отношению к пользователю, чем предлагаемая вами идея.


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

M>>Как в примере из соседнего поста, когда сервис туров следит чтобы определенные туры были доступны только совершеннолетним пользователям и эта же логика дублируется в сервисе рекомендаций чтобы не показывать несоврешеннолетним то, что им и так недоступно. HATEOAS бы эту проблему решил докинув ресурс user список доступных для него туров. ,


S>Это очень, очень плохая архитектура. В первую очередь потому, что вы инвертируете зависимости. Теперь у вас ресурс user (и его микросервис) обязан знать всё о турах (которые вообще-то обрабатываются другим микросервисом).

S>А ресурс "тур", ясное дело, должен знать всё о пользователях. Поздравляю, вы получили не просто монолит, а трудноразвиваемый монолит.

У тебя в любом случае есть связь между двумя ресурсами. Ее можно показать с одного конца, с другого конца или с обоих концов. Последний вариант самый универсальный. Если связь пересекает границы микросервисов, существуют способы это реализовать не увеличивая лишнюю связность: обогащение на уровне gateway, backend for frontend, обогащения на уровне middleware, наконец, просто засунуть в HATEOAS вместо списка туров, ссылку по которой этот список можно получить. Обычно, за HATEOS как раз и отвечает не сам сервис, а middleware. Можно, конечно, замести связь под ковер, но как раз усложняет поддержку сервисов.

S>И это — тоже очень, очень плохая архитектура. Смотрите как это работает: "поисковый запрос" — это эфемерный ресурс. Последнее, что мы хотим — это хранить его. В первую очередь по соображениям масштабирования. Сколько пользователей вы ожидаете ежедневно? Двух? Как только у вас появляется хотя бы несколько сотен тысяч запросов в сутки, хранение (даже в течение ограниченного времени) их эфемерных запросов становится

неподъёмным.

А давай посчитаем Один указатель (кэшировать нужно не весь результат, а только порядок записей), пусть long -- 8 байт * 300k запросов в сутки * 1000 записей (ты же не забываешь про max_search_results)= всего 2.2Gb При этом 300к уникальных запросов это где-то 20M DAU т.е. федеральная система уровня всего СНГ по поиску с запасом влазит на одну машину. У нас, слава богу, не 2005 год и уже завезли кэши в разделяемой памяти, типа hazelcast и ehcache.

S>А непротиворечивость гарантируется тем, что последующие запросы мы дооборудуем хидером if-match/if-none-match, что позволяет нам заметить момент, когда данные на серверной стороне поменялись, и закешированную версию нужно выкинуть.


Во-первых, проверка изменились ли результаты поиска эквивалентна выполнению самого запроса, так что кэширование результатов поиска не имеет смысла и никто им не пользуется. Во-вторых, допустим клиент узнает что результаты изменились, делать-то ему что? Повторять запрос? Тогда никакой консистентности при переходе между страницами не будет и получится ровно то же самое что и с параметрами offset + limit в запросе. Настроить промежуточный кэширующий сервер, который примет полные результаты поиска, а отдавать будет с учетом range. Ну так то же хранение и получится.

S>Простите, но вы рассказываете какие-то небылицы. Что такое "пречеки"? Мы пробежались по всем нужным ресурсам, и убедились, что все нужные нам "действия" торчат в виде линков?


Мы подняли все ресурсы, входящие в сценарий, убедились, что их состояние позволяет реализовать этот сценарий и только после этого начинаем претворять сценарий в жизнь. Понимаешь, когда речь идет про микро сервисы, когда каждый сервис отвечает за свой домен и управляет одним-двумя ресурсами, почти все сценарии захватывают несколько сервисов. При этом подавляющее большинство сценариев не требует строгой консистентности, вполне достаточно eventual consistency. Поэтому нет необходимости любой сценарий превращать в сагу или двухфазный коммит. Более того, сценарии, требующие строгой консистентности встречаются настолько редко, что большинство разработчиков такого не реализовывали ни разу в жизни. В то же время, eventual consistency это все еще consistency, а если у нас сценарии разваливаются через раз, никакой консистентности не будет. Поэтому, дизайнить систему так, чтобы сценарии не разваливались, это хорошая идея. В том числе поддерживать между сервисами контракт, что если мы получили от строннего сервиса ресурс и список связанных ресурсов, то попытка обратиться к этим ресурсам не вызовет ошибки.
Re[14]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.04.25 09:19
Оценка:
Здравствуйте, Miroff, Вы писали:

M>Желание похвальное, только эта абстракция практически сразу протекает. Ты же сам рассуждаешь о представлениях ресурса, а представления зависят от того, кто на них смотрит.

Я бы разводил такие вещи по разным "ресурсам", так, чтобы границы безопасности совпадали с границами ресурсов. Потому что это и надёжнее, и эффективнее.
Например: есть у нас, допустим, судебное постановление. Имена и реквизиты упомянутых там лиц — дело чувствительное. Анонимной публике их видеть не положено; а вот авторизованной — да, нужно.
Вариантов три:
1. При отдаче текста постановления смотрим в токен пользователя, и либо заменяем все имена плейсхолдерами, либо вставляем как надо.
2. Делаем два ресурса: "анонимизированное постановление", "полноценное постановление". Анонимный доступ ко второму получает 401, аутентифицированный доступ без прав на данное дело получает 403.
3. Делаем два ресурса: постановление, в "тексте" которого есть ссылки на фигурантов, каждый из которых — самостоятельный ресурс. Постановления отдаём всем желающим, детали фигурантов — только авторизованным пользователям. Остальные получают 403.
Как по мне, так первый вариант, очевидно, самый-самый плохой. Он плохо масштабируется, и крайне плохо проверяется на корректность.

M>Кому-то можно показывать одно, кому-то другое, третьему вообще ничего нельзя показывать. В результате, во всех без исключения проектах, которые я видел, кэширование за пределами контроллируемого контура отключено по-умолчанию и включается только для определенным образом проверенных ресурсов.

Всё верно. Сначала люди создают себе проблему путём принятия неверных архитектурных решений, потом всю жизнь от неё страдают. Интернет полон вопросов "как мне запретить кэширование респонсов моего сервиса?". Это не потому, что кэширование — плохо, а потому, что не все умеют проектировать сервисы.

M>Современная ИБ говорит, что если какой-то функционал пользователю недоступен он и не должен знать о существовании этого функционала.

Можно ссылку на источник, который вы цитируете? Я не эксперт по ИБ, с удовольствием ознакомлюсь.
M>Иначе мотивированный пользователь начнет искать способ для эскалации привилегий и, чем черт не шутит, вдруг найдет.
В той литературе по ИБ, которую я читал в детстве, излагаемая вами концепция называлась "security by obscurity" и считалась однозначным злом. По сравнению, естественно, с нормальной безопасностью, которая не построена на невежестве пользователей.

REST зарубает вашу идею на корню, т.к. весь "функционал" в нём известен заранее: GET/PUT/DELETE.


M>К тому же, с точки зрения UX скрытие кнопки эквивалентно вызову с ошибкой потому что а) причин ошибки бесконечно много и в этом случае все их нужно обрабатывать и б) ИБ не велит раскрывать внутреннее устройство приложения через сообщения об ошибках, так что пользователь максимум что увидит это "тебе нельзя".

Я не понимаю, что вы имеете под пунктом а). Да, совершенно верно, причин ошибки много, и их надо обрабатывать. В любом случае. Как минимум вы должны уметь отличать 4хх от 5хх. Полагаться на то, что ошибок не существует — верный способ заслужить ненависть пользователей. Я знаю, что сейчас модно либо вообще не обрабатывать ошибки (тыкаешь кнопку — и ничего не происходит), либо обрабатывать их в стиле "произошла неизвестная ошибка". Но нужно отдавать себе отчёт в том, что это — не лучший UX. Его можно чем-то оправдывать, но стремиться надо к хорошему — к UX, который пользователя уважает. В частности, не требует от него навыков трассировки веб-сайтов по F12 для того, чтобы отличить ситуацию "в этом детском саду нет мест" от "сессия прокисла, перелогиньтесь".

M>У тебя в любом случае есть связь между двумя ресурсами. Ее можно показать с одного конца, с другого конца или с обоих концов. Последний вариант самый универсальный. Если связь пересекает границы микросервисов, существуют способы это реализовать не увеличивая лишнюю связность: обогащение на уровне gateway, backend for frontend, обогащения на уровне middleware, наконец, просто засунуть в HATEOAS вместо списка туров, ссылку по которой этот список можно получить. Обычно, за HATEOS как раз и отвечает не сам сервис, а middleware.

Можно. Такая реализация, собственно, разрывает жёсткую зависимость микросервисов друг от друга. Фасад, при условии того, что он сам по себе устроен достаточно примитивно — хорошая штука для построения интегрированных сценариев. Но, опять же, он не является необходимым звеном. А вот устранение кольцевых зависимостей микросервисов — как раз суровая необходимость.

M>А давай посчитаем Один указатель (кэшировать нужно не весь результат, а только порядок записей), пусть long -- 8 байт * 300k запросов в сутки * 1000 записей (ты же не забываешь про max_search_results)= всего 2.2Gb При этом 300к уникальных запросов это где-то 20M DAU т.е. федеральная система уровня всего СНГ по поиску с запасом влазит на одну машину. У нас, слава богу, не 2005 год и уже завезли кэши в разделяемой памяти, типа hazelcast и ehcache.

Омг, омг. Во-первых, кэшировать нужно, конечно же, весь результат. Потому что иначе совершенно непонятно, как в поиск Ивановых затесался Петров. Или в список билетов до 12000р затесался перелёт за 58000.
Во-вторых, что такое "указатель"? Я так понял, вы положились на то, что все исходные данные загружены в память вашей единственной машины?

M>Во-первых, проверка изменились ли результаты поиска эквивалентна выполнению самого запроса, так что кэширование результатов поиска не имеет смысла и никто им не пользуется.

Вы только что предложили кэшировать результаты запроса, и сами же пишете "никто не пользуется". Веб устроен так, что вы никуда не денетесь от распределённого состояния. Даже когда вы смотрите на страницу RSDN, вы смотрите не на "сервер", а на локальную копию результата запроса, которую вам отображает браузер. Весь вопрос — в том, можно ли склеить "полный" результат из его постраничных представлений.

M>Во-вторых, допустим клиент узнает что результаты изменились, делать-то ему что? Повторять запрос?

Зачем? REST как раз позволяет "обновить кэш" одним запросом безо всяких повторений.

M>Тогда никакой консистентности при переходе между страницами не будет и получится ровно то же самое что и с параметрами offset + limit в запросе. Настроить промежуточный кэширующий сервер, который примет полные результаты поиска, а отдавать будет с учетом range. Ну так то же хранение и получится.

Всё верно. Только это хранение вы реализуете не за счёт своих средств, дорогостоящих и ограниченных, а за счёт средств клиентов, которые масштабируются автоматически и бесплатно.
Наличие "промежуточного" кэшируюшего сервера — не обязательная часть решения. Можно считать, что у вас есть "кэширующий клиент", который способен построить иллюзию согласованной бесшовной картины.
Вы застали до-гуглмэпные времена? Когда основным картографическим сервисом был MapQuest, который как раз реализовывал концепцию "постраничной навигации". Пользователь мог двигать "окно просмотра" по фиксированной сетке, перемещаясь по ней в четырёх направлениях. Гугл сумел придумать и реализовать клиента, который создаёт иллюзию "бесконечного канваса", несмотря на наличие под капотом точно такого же "постраничного" механизма.
Теперь всем очевидно, что именно такой способ навигации по "огромной плоскости" и является нормальной реализацией концепции просмотра большой картинки через маленькое окно. Карты гугла, яндекса, 2гиса, и примерно кого угодно теперь устроены именно так, и никак иначе. Та же концепция — у Miro, Figma, и бесчисленного множества диаграммных сервисов.
И только "табличные данные", которые являются частным случаем ровно той же задачи, до сих пор реализуются методиками девяностых годов прошлого века. Нет никакой причины так делать, кроме "здесь так принято" и "мне лень думать, как сделать нормально".

M>Мы подняли все ресурсы, входящие в сценарий, убедились, что их состояние позволяет реализовать этот сценарий и только после этого начинаем претворять сценарий в жизнь. Понимаешь, когда речь идет про микро сервисы, когда каждый сервис отвечает за свой домен и управляет одним-двумя ресурсами, почти все сценарии захватывают несколько сервисов. При этом подавляющее большинство сценариев не требует строгой консистентности, вполне достаточно eventual consistency. Поэтому нет необходимости любой сценарий превращать в сагу или двухфазный коммит. Более того, сценарии, требующие строгой консистентности встречаются настолько редко, что большинство разработчиков такого не реализовывали ни разу в жизни. В то же время, eventual consistency это все еще consistency, а если у нас сценарии разваливаются через раз, никакой консистентности не будет. Поэтому, дизайнить систему так, чтобы сценарии не разваливались, это хорошая идея. В том числе поддерживать между сервисами контракт, что если мы получили от строннего сервиса ресурс и список связанных ресурсов, то попытка обратиться к этим ресурсам не вызовет ошибки.

Этот "контракт" невозможно надёжно обеспечить в реальной среде. Всё, что можно делать — это притворяться, что он выполняется. Поэтому существенной разницы между hateoas и "компактной" формой ресурсов с точки зрения достигнутого результата я не вижу.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Каких программ вам не хватает?
От: Miroff Россия  
Дата: 08.04.25 12:26
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>2. Делаем два ресурса: "анонимизированное постановление", "полноценное постановление". Анонимный доступ ко второму получает 401, аутентифицированный доступ без прав на данное дело получает 403.


А если у тебя десять независимых полей в ресурсе? Будешь делать 100 ресурсов? Сильно сомневаюсь что это хорошее решение, их же придется потом тестировать.

S>3. Делаем два ресурса: постановление, в "тексте" которого есть ссылки на фигурантов, каждый из которых — самостоятельный ресурс. Постановления отдаём всем желающим, детали фигурантов — только авторизованным пользователям. Остальные получают 403.


Опять же, ИБ не велит) Как только у атакующего появляется возможность идентифицировать анонимизированые ресурсы, деанонимизация становится делом техники.

S>Можно ссылку на источник, который вы цитируете? Я не эксперт по ИБ, с удовольствием ознакомлюсь.


Можно, например, начать с википедии и заполировать OWASP Developer Guide. Современный подход к ИБ построен на модели швейцарского сыра: вместо того чтобы обеспечивать безопасность только в одном слое, мы реализуем достаточный уровень безопасности на каждом слое. Один из аспектов такого подхода это принцип минимальных привилегий (пользователю или сервису выдаются как можно меньшие права на как можно более короткий срок достаточный для выполнения операции) и принцип разделения (пользователю выдается только та информация, которая необходима для выполнения операции). И нет, это не security by obscutiry, потому что безопасность на слое ресурсов никак не отменяет проверки прав на уровне сервисов, а лишь дополняет их. Короче, если ты все еще занимаешься разработкой и тем более принятием архитектурных решений, рекомендую пройти какой-нибудь хороший AppSec тренинг, а то с твоего детства многое изменилось )

S>Я не понимаю, что вы имеете под пунктом а). Да, совершенно верно, причин ошибки много, и их надо обрабатывать. В любом случае.


В времена Нового Царства, каждый египтянин после смерти подвергался суду Осириса, где он должен был долго и нужно перечислять чего в жизни он НЕ делал. Вот и с ошибками та же история ) Позитивный сценарий может завершиться только одним способом, негативный -- бесконечным множеством способов из которых восстановимых считанные единицы: 502, да 401 и то не всегда.

S>Во-вторых, что такое "указатель"? Я так понял, вы положились на то, что все исходные данные загружены в память вашей единственной машины?


Не обязательно, любой идентификатор объекта. Хотя, конечно, кэши на разделяемой памяти выгладят красиво.

S>Всё верно. Только это хранение вы реализуете не за счёт своих средств, дорогостоящих и ограниченных, а за счёт средств клиентов, которые масштабируются автоматически и бесплатно.


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

S>И только "табличные данные", которые являются частным случаем ровно той же задачи, до сих пор реализуются методиками девяностых годов прошлого века. Нет никакой причины так делать, кроме "здесь так принято" и "мне лень думать, как сделать нормально".


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

S>Этот "контракт" невозможно надёжно обеспечить в реальной среде. Всё, что можно делать — это притворяться, что он выполняется. Поэтому существенной разницы между hateoas и "компактной" формой ресурсов с точки зрения достигнутого результата я не вижу.


Так практически вся микросервисная архитектура это история не про гарантии, а про достаточно хорошие допущения.
Re[16]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.04.25 12:48
Оценка:
Здравствуйте, Miroff, Вы писали:

M>А если у тебя десять независимых полей в ресурсе? Будешь делать 100 ресурсов?

Это очень странное предположение. Что значит "независимых"? Независимость и означает, что это не один ресурс, а несколько. А их искусственное склеивание — прямой путь создать себе проблемы.
M>Сильно сомневаюсь что это хорошее решение, их же придется потом тестировать.
А в других вариантах их типа можно не тестировать? Как раз нет: вам нужно протестировать не просто корректность раздачи прав доступа на 10 разных ресурсов, а 210 комбинаций вида "есть права на F1 и F3, нет прав на F2 и прочие".

S>>3. Делаем два ресурса: постановление, в "тексте" которого есть ссылки на фигурантов, каждый из которых — самостоятельный ресурс. Постановления отдаём всем желающим, детали фигурантов — только авторизованным пользователям. Остальные получают 403.


M>Опять же, ИБ не велит) Как только у атакующего появляется возможность идентифицировать анонимизированые ресурсы, деанонимизация становится делом техники.

Необязательно. Если делать криво, то да. А если делать по уму, то никакой возможности не появится.

S>>Можно ссылку на источник, который вы цитируете? Я не эксперт по ИБ, с удовольствием ознакомлюсь.


M>Можно, например, начать с википедии и заполировать OWASP Developer Guide. 4

Спасибо, интересно.

M>Не обязательно, любой идентификатор объекта. Хотя, конечно, кэши на разделяемой памяти выгладят красиво.

Ну, вот "любой идентификатор" — это уже не 8 байт, а как минимум 16 (если мы пользуемся гуидами). А то и больше, если у нас ресурсы размазаны по нескольким неймспейсам.

M>Погоди, ты же только что предлагал в заголовках передавать range. Как у тебя будет работать согласованное кэширование, если часть диапазона клиентом даже не запрашивалась? Не говоря уже о том, что браузеры не поддерживают кэширование совместно с range.

Во-первых, браузер — это не единственный вид клиентов. И даже не основной, если мы говорим о REST API. Во-вторых, некоторые таки пользуются спекой, и умеют делать частичное кэширование.
В-третьих, речь не столько о конкретном механизме, сколько о принципе взаимодействия.

M>Вообще говоря, в 25 году мало кто работает с табличными данными вообще. Сейчас в моде разделяемое состояние между сервером и клиентом и реактивное программирование для двусторонней синхронизации этой модели в реальном времени. Если непонятно сформулировал, посмотри на фейсбук.

Ок, тем лучше. У меня отвалился антизапрет, а включать VPN чтобы почитать фейсбуковый API guide мне лень. Выражу осторожное сомнение в том, что у фейсбука под капотом — пейджинг на limit offset. Скорее всего, там предикатный метки (примерно так же, как сделаны continuation token в многостраничных респонсах MS Graph API) или там какие-нибудь timestamp ranges.

M>Так практически вся микросервисная архитектура это история не про гарантии, а про достаточно хорошие допущения.

Кмк, это не потому, что такова была цель, а потому что "так получилось". Я же говорю — удачных примеров MSA я видел в единичных количествах, а вот неудачных — как говна за баней.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 08.04.25 13:09
Оценка: 8 (1)
Здравствуйте, Sinclair, Вы писали:

S>2. Делаем два ресурса: "анонимизированное постановление", "полноценное постановление". Анонимный доступ ко второму получает 401, аутентифицированный доступ без прав на данное дело получает 403.

Такое экспоненциально рванёт. У тебя 2 ресурса для одного permission "смотреть инфу о фигурантах". Представь у тебя 10 таких permissions, в зависимости от роли пользователя. Потребуется 1024 разных ресурса.
А ещё ты можешь запрашивать список документов. К половине у тебя роль полного доступа, а к половине частичного.

S>3. Делаем два ресурса: постановление, в "тексте" которого есть ссылки на фигурантов, каждый из которых — самостоятельный ресурс. Постановления отдаём всем желающим, детали фигурантов — только авторизованным пользователям. Остальные получают 403.

Получаем список из n документов, и в каждом ещё 10 ссылок. Тут же шлём ещё n*10 запросов, некоторые из которых что-то возвращают, а некоторые дают 403 отлуп... Тучи запросов и тормоза на пустом месте.

S>Как по мне, так первый вариант, очевидно, самый-самый плохой. Он плохо масштабируется, и крайне плохо проверяется на корректность.

Зато работает.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[16]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 08.04.25 15:24
Оценка:
Здравствуйте, ·, Вы писали:

S>>2. Делаем два ресурса: "анонимизированное постановление", "полноценное постановление". Анонимный доступ ко второму получает 401, аутентифицированный доступ без прав на данное дело получает 403.

·>Такое экспоненциально рванёт. У тебя 2 ресурса для одного permission "смотреть инфу о фигурантах". Представь у тебя 10 таких permissions, в зависимости от роли пользователя. Потребуется 1024 разных ресурса.
Это ж не настоящие ресурсы, а виртуальные. В параллельном ответе пояснил, что экспоненциальный взрыв наступает даже тогда, когда ресурс "один", но может быть отдан в 1024 разных конфигурациях.

S>>3. Делаем два ресурса: постановление, в "тексте" которого есть ссылки на фигурантов, каждый из которых — самостоятельный ресурс. Постановления отдаём всем желающим, детали фигурантов — только авторизованным пользователям. Остальные получают 403.

·>Получаем список из n документов, и в каждом ещё 10 ссылок. Тут же шлём ещё n*10 запросов, некоторые из которых что-то возвращают, а некоторые дают 403 отлуп... Тучи запросов и тормоза на пустом месте.
Зато всё безопасно. Причин для тормозов я не вижу: ваш "рабочий" вариант делает всё то же самое "под капотом", т.к. пермишны проверить всё равно надо, и сходить за данными фигуранта тоже надо. Единственная радость — некоторая экономия на хидерах.

S>>Как по мне, так первый вариант, очевидно, самый-самый плохой. Он плохо масштабируется, и крайне плохо проверяется на корректность.

·>Зато работает.
А вы тестировали? Все 1024 комбинации прав и привилегий?

На практике, конечно же, таких мелкогранулярных систем безопасности не бывает. Как правило, всё квадратно-гнездовое, и набор ролей фиксирован в бизнес-модели (и зачастую ещё и продиктован регулятором).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[17]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 08.04.25 16:15
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>>>2. Делаем два ресурса: "анонимизированное постановление", "полноценное постановление". Анонимный доступ ко второму получает 401, аутентифицированный доступ без прав на данное дело получает 403.

S>·>Такое экспоненциально рванёт. У тебя 2 ресурса для одного permission "смотреть инфу о фигурантах". Представь у тебя 10 таких permissions, в зависимости от роли пользователя. Потребуется 1024 разных ресурса.
S>Это ж не настоящие ресурсы, а виртуальные. В параллельном ответе пояснил, что экспоненциальный взрыв наступает даже тогда, когда ресурс "один", но может быть отдан в 1024 разных конфигурациях.
Гы. Практически с таким же успехом можно засунуть bearer-токен в url, вот у тебя по ресурсу для каждой конфигурации.

S>·>Получаем список из n документов, и в каждом ещё 10 ссылок. Тут же шлём ещё n*10 запросов, некоторые из которых что-то возвращают, а некоторые дают 403 отлуп... Тучи запросов и тормоза на пустом месте.

S>Зато всё безопасно. Причин для тормозов я не вижу: ваш "рабочий" вариант делает всё то же самое "под капотом", т.к. пермишны проверить всё равно надо, и сходить за данными фигуранта тоже надо. Единственная радость — некоторая экономия на хидерах.
Поход внутри сервиса может осуществляться в памяти того же процесса сервиса, в крайнем случае добавлением соответствующих JOIN в sql. А так у тебя будет куча сетевых вызовов... и представь это всё с мобилы через инет! Надо считать roundtrips.

S>·>Зато работает.

S>А вы тестировали? Все 1024 комбинации прав и привилегий?
Каждую комбинацию тестировать не нужно. Нужно тестировать каждую привелегию. Два теста: "разрешено всё -> возвращается инфа о фигурантах", "разрешено всё, кроме инфы о фигурантах -> не возвращается инфа о фигурантах". Ну и отдельно матрица роли <-> привилегии.

Анонимный доступ это такая же роль, как и авторизированный внутренний юзер, внешний юзер, юзер из другого подразделения, админ, аудитор и т.п. И у каждой роли своё подмножество привилегий.

S>На практике, конечно же, таких мелкогранулярных систем безопасности не бывает. Как правило, всё квадратно-гнездовое, и набор ролей фиксирован в бизнес-модели (и зачастую ещё и продиктован регулятором).

Ролей может быть, да. А привилегии — их может быть очень много.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[18]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.04.25 06:55
Оценка:
Здравствуйте, ·, Вы писали:

S>>Это ж не настоящие ресурсы, а виртуальные. В параллельном ответе пояснил, что экспоненциальный взрыв наступает даже тогда, когда ресурс "один", но может быть отдан в 1024 разных конфигурациях.

·>Гы. Практически с таким же успехом можно засунуть bearer-токен в url, вот у тебя по ресурсу для каждой конфигурации.
Ну, да. Поэтому я и не назвал этот способ самым лучшим. Он приемлем тогда, когда у нас нет большого разнообразия пермиссий. Скажем, есть инвойс "с точки зрения плательщика", а есть тот же инвойс "с точки зрения получателя".
Вместо того, чтобы искусственно совмещать их в одном ресурсе и отдавать разный контент в зависимости от содержимого bearer token, делается два разных ресурса с похожей структурой.

·>Поход внутри сервиса может осуществляться в памяти того же процесса сервиса, в крайнем случае добавлением соответствующих JOIN в sql. А так у тебя будет куча сетевых вызовов... и представь это всё с мобилы через инет! Надо считать roundtrips.

Можно и считать. В разных задачах — разные приоритеты требований. Безопасность очень часто входит в конфликт с производительностью.

·>Каждую комбинацию тестировать не нужно. Нужно тестировать каждую привелегию. Два теста: "разрешено всё -> возвращается инфа о фигурантах", "разрешено всё, кроме инфы о фигурантах -> не возвращается инфа о фигурантах". Ну и отдельно матрица роли <-> привилегии.

Перед тем, как прийти к таким выводам, придётся как-то доказать независимость code path, которые приводят к появлению тех или иных результатов. Ну, или надеяться на эту независимость, и рисковать пролезанием false negative в каких-то особенных комбинациях привилегий.
·>Анонимный доступ это такая же роль, как и авторизированный внутренний юзер, внешний юзер, юзер из другого подразделения, админ, аудитор и т.п. И у каждой роли своё подмножество привилегий.
Это всё понятно.
S>>На практике, конечно же, таких мелкогранулярных систем безопасности не бывает. Как правило, всё квадратно-гнездовое, и набор ролей фиксирован в бизнес-модели (и зачастую ещё и продиктован регулятором).
·>Ролей может быть, да. А привилегии — их может быть очень много.
Повторюсь: это зависит от задачи. Модель привилегий и ролей — это всего лишь оптимизация процесса "пересмотр ролей". В зарегулированном бизнесе набор привилегий жёстко связан с ролью.
И это не просто так: бездумная раздача привилегий слишком легко позволяет создавать дырки там, где их не ожидаешь. Типа, напрямую посмотреть реквизиты произвольного контрагента я не могу (прав нет), но могу отправить ему 1 рубль через платёж по номеру телефона. А код формирования ресурса "квитанция о платеже" ничего о привилегиях на контрагентов не знает — у него свой набор привилегий, и вот я уже вижу все реквизиты встроенными прямо в тело квитанции.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 09.04.25 09:27
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>>>Это ж не настоящие ресурсы, а виртуальные. В параллельном ответе пояснил, что экспоненциальный взрыв наступает даже тогда, когда ресурс "один", но может быть отдан в 1024 разных конфигурациях.

S>·>Гы. Практически с таким же успехом можно засунуть bearer-токен в url, вот у тебя по ресурсу для каждой конфигурации.
S>Ну, да. Поэтому я и не назвал этот способ самым лучшим. Он приемлем тогда, когда у нас нет большого разнообразия пермиссий. Скажем, есть инвойс "с точки зрения плательщика", а есть тот же инвойс "с точки зрения получателя".
Или нет смешанных пермиссий. Скажем, получить список инвойсов за период, и получится что некоторые инвойсы где ты плательщик, а некоторые получатель. В общем, способ может и красивый, но почти бесполезный на практике.

S>Вместо того, чтобы искусственно совмещать их в одном ресурсе и отдавать разный контент в зависимости от содержимого bearer token, делается два разных ресурса с похожей структурой.

Угу. А потом получится, что сегодня два, завтра внезапно понадобился третий, а через год у нас их уже 1024. Так что ещё и немножечко вредный.

S>·>Поход внутри сервиса может осуществляться в памяти того же процесса сервиса, в крайнем случае добавлением соответствующих JOIN в sql. А так у тебя будет куча сетевых вызовов... и представь это всё с мобилы через инет! Надо считать roundtrips.

S>Можно и считать. В разных задачах — разные приоритеты требований. Безопасность очень часто входит в конфликт с производительностью.
Интересно узнать какой такой магией фрагмент в урле повышает безопасность? Как ты будешь доказывать или тестировать безопасность 1024 конфигураций ресурса, пусть и виртуальных?
По сути ровно те же данные в теле запроса. Просто кусочек инфы переползает из ~третей строчки http запроса (там где Authorization: Bearer хедер) в первую строчку (там где урл). Злоумышленникам по барабану какую часть менять, а программисты с равным успехом могут налажать в проверках любой части запроса.

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

S>·>Каждую комбинацию тестировать не нужно. Нужно тестировать каждую привелегию. Два теста: "разрешено всё -> возвращается инфа о фигурантах", "разрешено всё, кроме инфы о фигурантах -> не возвращается инфа о фигурантах". Ну и отдельно матрица роли <-> привилегии.

S>Перед тем, как прийти к таким выводам, придётся как-то доказать независимость code path, которые приводят к появлению тех или иных результатов. Ну, или надеяться на эту независимость, и рисковать пролезанием false negative в каких-то особенных комбинациях привилегий.
Доказывать эту независимость придётся ровно тем же способом, как и для твоих 1024 виртуальных ресурсов.
Единственное, что может помочь, что есть какой-то уже готовый фреймворк, про который авторы зуб дают, что всё безопасно, а твоя аппликуха на него полагается. Но с т.з. системы в целом — ранзицы никакой.

S>>>На практике, конечно же, таких мелкогранулярных систем безопасности не бывает. Как правило, всё квадратно-гнездовое, и набор ролей фиксирован в бизнес-модели (и зачастую ещё и продиктован регулятором).

S>·>Ролей может быть, да. А привилегии — их может быть очень много.
S>Повторюсь: это зависит от задачи. Модель привилегий и ролей — это всего лишь оптимизация процесса "пересмотр ролей". В зарегулированном бизнесе набор привилегий жёстко связан с ролью.
S>И это не просто так: бездумная раздача привилегий слишком легко позволяет создавать дырки там, где их не ожидаешь. Типа, напрямую посмотреть реквизиты произвольного контрагента я не могу (прав нет), но могу отправить ему 1 рубль через платёж по номеру телефона. А код формирования ресурса "квитанция о платеже" ничего о привилегиях на контрагентов не знает — у него свой набор привилегий, и вот я уже вижу все реквизиты встроенными прямо в тело квитанции.
Как твои виртуальные ресурсы помогут? Ну да, "GET /contragents?id=vasya" тебе запрещён, а "POST /payments?to=vasya" тебе выдаст квиток с инфой конртагента.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 09.04.2025 9:28 · . Предыдущая версия .
Re[20]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.04.25 11:35
Оценка:
Здравствуйте, ·, Вы писали:

·>Или нет смешанных пермиссий. Скажем, получить список инвойсов за период, и получится что некоторые инвойсы где ты плательщик, а некоторые получатель.

Ну, вот на практике есть два разных списка: "инвойсы, которые выставил я", и "инвойсы, которые выставили мне". Всё, никаких чудес. Зачем делать единый список, а потом мужественно бороться с разнотипностью — .
Посмотрите на тот же Paypal API — он, хоть и не-REST, но устроен именно так.

·>Угу. А потом получится, что сегодня два, завтра внезапно понадобился третий, а через год у нас их уже 1024. Так что ещё и немножечко вредный.

Или не получится.

·>Интересно узнать какой такой магией фрагмент в урле повышает безопасность?

Очень просто: у нас нет "частичной безопасности", когда содержимое ресурса зависит от каких-то эфемерных вещей. У нас для запроса есть ровно два возможных ответа: 403 или 200.

·>Как ты будешь доказывать или тестировать безопасность 1024 конфигураций ресурса, пусть и виртуальных?

Очень просто. 2048 тестов, если уж у нас есть 1024 конфигурации ресурса. Но я повторю ещё раз: у нас не будет 1024 конфигураций. Этот способ не подходит для таких API, в которых есть 10 разных привилегий на один и тот же ресурс.

·>Урлы имеют смысл не для безопасности, а для кеширующих прокси (та самая производительность!). Но прокси на практике умеют работать только с анонимными ресурсами, у которых никаких пермов нет и можно смело всё отдавать всем. Только в этом случае есть гарантии не нарушения безопасности, т.к. нарушать собственно нечего.

На практике прокси прекрасно работают и с ресурсами, у которых cache-control: private. Это как раз позволяет каждому клиенту построить у себя частичную реплику распределённого состояния, и эффективно с ней взаимодействовать.

·>Доказывать эту независимость придётся ровно тем же способом, как и для твоих 1024 виртуальных ресурсов.

Ну так для 1024 ресурсов у нас будет 2048 тестов. Вам же кажется, что можно как-то обойтись 20 тестами.
·>Как твои виртуальные ресурсы помогут? Ну да, "GET /contragents?id=vasya" тебе запрещён, а "POST /payments?to=vasya" тебе выдаст квиток с инфой конртагента.
Виртуальные ресурсы помогут избавиться от иллюзии того, что данные Васи видны только тем, у кого есть привилегия "видеть данные Васи".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[21]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 09.04.25 13:21
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ну, вот на практике есть два разных списка: "инвойсы, которые выставил я", и "инвойсы, которые выставили мне". Всё, никаких чудес. Зачем делать единый список, а потом мужественно бороться с разнотипностью — .

S>Посмотрите на тот же Paypal API — он, хоть и не-REST, но устроен именно так.
Я что-то перестал понимать о чём идёт речь. Вроде ты обсуждал возможность, что некий запрос какого-то ресурса, который выдаёт результат, раскрывающий детали других ресурсов. Т.е. когда например результирующий инвойс содержит приватные данные контрагента.
То что Paypal API устроен именно так... ну дык он для того, чтобы человеки хорошо понимали, а не для безопасности.

S>·>Интересно узнать какой такой магией фрагмент в урле повышает безопасность?

S>Очень просто: у нас нет "частичной безопасности", когда содержимое ресурса зависит от каких-то эфемерных вещей. У нас для запроса есть ровно два возможных ответа: 403 или 200.
Частичной нет, верно... да вообще никакой нет. Ну выдал ваш /invoices-for-me?id=123 json 200, в котором внезапно появится секция contragent: {homeAddress: {...}}, хотя разрешено только companyAddress выдавать. А ещё злоумышленник подменит урл на /my-invoices?id=123 и увидит вообще всё.

S>·>Как ты будешь доказывать или тестировать безопасность 1024 конфигураций ресурса, пусть и виртуальных?

S>Очень просто. 2048 тестов, если уж у нас есть 1024 конфигурации ресурса.
Если у тебя уже для такой тривиальной вещи 2048 тестов, то они абсолютно бесполезны, т.к. их никто не сможет проанализировать на безопасность и поддерживать в дальнейшем.

S> Но я повторю ещё раз: у нас не будет 1024 конфигураций. Этот способ не подходит для таких API, в которых есть 10 разных привилегий на один и тот же ресурс.

А пофиг. Привилегии должны проверяться на источнике данных, а не на endpoint-е. Источник данных контрагента — это скорее всего один метод где-то внутрях. И именно он потребует наличие ровно одной конкретной привилегии. И не отдаст данные если привилегии нет, вне зависимости от того как обратились к сервису — через /contragents, через инвойсы или через платежи.
Ещё раз, ресурсы-сервисы-endpoints — это всё о том в каком формате обменяться данными по сети, и отношение к безопасности имеет чисто иллюзорное.

S>·>Урлы имеют смысл не для безопасности, а для кеширующих прокси (та самая производительность!). Но прокси на практике умеют работать только с анонимными ресурсами, у которых никаких пермов нет и можно смело всё отдавать всем. Только в этом случае есть гарантии не нарушения безопасности, т.к. нарушать собственно нечего.

S>На практике прокси прекрасно работают и с ресурсами, у которых cache-control: private. Это как раз позволяет каждому клиенту построить у себя частичную реплику распределённого состояния, и эффективно с ней взаимодействовать.
Не понял. "cache-control: private" — это как раз инструкция отключающая кеш на прокси. Или под "работают" ты тут имел в виду "по идее должен сам отключаться"? И ты так и не пояснил какое это отношение имеет к безопасности.

S>Ну так для 1024 ресурсов у нас будет 2048 тестов. Вам же кажется, что можно как-то обойтись 20 тестами.

S>·>Как твои виртуальные ресурсы помогут? Ну да, "GET /contragents?id=vasya" тебе запрещён, а "POST /payments?to=vasya" тебе выдаст квиток с инфой конртагента.
S>Виртуальные ресурсы помогут избавиться от иллюзии того, что данные Васи видны только тем, у кого есть привилегия "видеть данные Васи".
А откуда такая иллюзия появится в принципе особенно в случае эвфемерных вещей??
Как раз вот илюзия "запретим выдачу деталей контрагента по урлу GET /contragents — значит детали контрагента никому не будут видны без нужной привилегии" и создаётся.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 09.04.2025 13:25 · . Предыдущая версия .
Re[22]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 09.04.25 15:47
Оценка:
Здравствуйте, ·, Вы писали:
·>Я что-то перестал понимать о чём идёт речь. Вроде ты обсуждал возможность, что некий запрос какого-то ресурса, который выдаёт результат, раскрывающий детали других ресурсов. Т.е. когда например результирующий инвойс содержит приватные данные контрагента.
Нет, не содержит он никаких приватных данных контрагента. Инвойс, выставленный мне, ни в каком случае не показывает "закрытые" атрибуты отправителя. Независимо от моих "привилегий".
Инвойс, который выставил я, содержит дополнительные поля, которые на стороне получателя видны не будут. Опять же, мне они видны независимо от моих привилегий.
Доступ к "моим" инвойсам всем остальным пользователям закрыт не на уровне отдельных полей и привилегий, а на уровне всего субресурса
·>То что Paypal API устроен именно так... ну дык он для того, чтобы человеки хорошо понимали, а не для безопасности.
У пейпала с безопасностью всё в порядке.

·>Частичной нет, верно... да вообще никакой нет. Ну выдал ваш /invoices-for-me?id=123 json 200, в котором внезапно появится секция contragent: {homeAddress: {...}}, хотя разрешено только companyAddress выдавать. А ещё злоумышленник подменит урл на /my-invoices?id=123 и увидит вообще всё.

Нет, не увидит. Внутри ресурса /my-invoices/ нет никаких чужих инвойсов.
·>Если у тебя уже для такой тривиальной вещи 2048 тестов, то они абсолютно бесполезны, т.к. их никто не сможет проанализировать на безопасность и поддерживать в дальнейшем.
У меня складывается впечатление, что вы читаете не всё, что я пишу. Давайте вы ещё раз перечитаете всё с самого начала и внимательно посмотрите, с какими тезисами вы спорите.

·>А пофиг. Привилегии должны проверяться на источнике данных, а не на endpoint-е.

Забавная идея. Ну, вот у вас "источник данных" — реляционная БД. Какие вы там привилегии собрались проверять?

·>Ещё раз, ресурсы-сервисы-endpoints — это всё о том в каком формате обменяться данными по сети, и отношение к безопасности имеет чисто иллюзорное.

Ну, иллюзорную так иллюзорную.

·>Не понял. "cache-control: private" — это как раз инструкция отключающая кеш на прокси.

Я неправильно написал. Речь не о прокси, а о кэшировании на стороне клиента. Оно точно так же поднимает производительность, т.к. позволяет нам не отдавать неизменные данные; при этом оно никак не противоречит безопасности.


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

·>А откуда такая иллюзия появится в принципе особенно в случае эвфемерных вещей??
Ну вот у вас она уже возникла.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[23]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 10.04.25 11:20
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>·>Я что-то перестал понимать о чём идёт речь. Вроде ты обсуждал возможность, что некий запрос какого-то ресурса, который выдаёт результат, раскрывающий детали других ресурсов. Т.е. когда например результирующий инвойс содержит приватные данные контрагента.

S>Нет, не содержит он никаких приватных данных контрагента. Инвойс, выставленный мне, ни в каком случае не показывает "закрытые" атрибуты отправителя.
S>Независимо от моих "привилегий".
Закрытые для кого? Закрытость — вещь относительная. На какие-то атрибуты у тебя есть привилегии, на какие-то нет. У других пользователей будет другой доступ к атрибутам.

S>Инвойс, который выставил я, содержит дополнительные поля, которые на стороне получателя видны не будут. Опять же, мне они видны независимо от моих привилегий.

S>Доступ к "моим" инвойсам всем остальным пользователям закрыт не на уровне отдельных полей и привилегий, а на уровне всего субресурса
Каким образом закрыт-то? Заклятие наложено что-ли? Субресурс возвращает джсон, как ты ресурсом гарантируешь отстутствие там какого-нибудь contragent.homeAddress?

S>·>То что Paypal API устроен именно так... ну дык он для того, чтобы человеки хорошо понимали, а не для безопасности.

S>У пейпала с безопасностью всё в порядке.
Верю. Но не потому, что "API устроен именно так".

S>·>Частичной нет, верно... да вообще никакой нет. Ну выдал ваш /invoices-for-me?id=123 json 200, в котором внезапно появится секция contragent: {homeAddress: {...}}, хотя разрешено только companyAddress выдавать. А ещё злоумышленник подменит урл на /my-invoices?id=123 и увидит вообще всё.

S>Нет, не увидит. Внутри ресурса /my-invoices/ нет никаких чужих инвойсов.
Почему ты так решил? Ты так говоришь, что ресурс это какая-то охраняемая зона за колючей проволокой. Нет, это просто несколько байт в определённом месте хедера запроса, а обрабатывает всё это дело тот же самый условно питонячий код, что и для других ресурсов.

S>·>Если у тебя уже для такой тривиальной вещи 2048 тестов, то они абсолютно бесполезны, т.к. их никто не сможет проанализировать на безопасность и поддерживать в дальнейшем.

S>У меня складывается впечатление, что вы читаете не всё, что я пишу. Давайте вы ещё раз перечитаете всё с самого начала и внимательно посмотрите, с какими тезисами вы спорите.
Я спорю с тем, что ресурсы и урлы каким-то образом обеспечивают хоть какую-то безопасность. Что в зависимости от того куда поместить данные — в урл или хедер — вдруг внезапно станет "Зато всё безопасно".

S>·>А пофиг. Привилегии должны проверяться на источнике данных, а не на endpoint-е.

S>Забавная идея. Ну, вот у вас "источник данных" — реляционная БД. Какие вы там привилегии собрались проверять?
А чё так мелко? Сразу уж говори — источник данных — заряд на затворе транзистора. Да, там с привилегиями как-то не очень. Я вообще-то говорил о дизайне самого сервиса. БД — это уже другой сервис.

S>·>Не понял. "cache-control: private" — это как раз инструкция отключающая кеш на прокси.

S>Я неправильно написал. Речь не о прокси, а о кэшировании на стороне клиента. Оно точно так же поднимает производительность, т.к. позволяет нам не отдавать неизменные данные; при этом оно никак не противоречит безопасности.
А, так да. Но собственно тут обсуждалось "Безопасность очень часто входит в конфликт с производительностью", мой вопрос был "Интересно узнать какой такой магией фрагмент в урле повышает безопасность?". И в качестве ответа ты внезапно рассказываешь о "поднимает производительность" "не противоречит безопасности".

S>·>А откуда такая иллюзия появится в принципе особенно в случае эвфемерных вещей??

S>Ну вот у вас она уже возникла.
С чего ты взял? Никогда не было. А вот у тебя иллюзия в полный рост, цитирую: "чтобы границы безопасности совпадали с границами ресурсов. Потому что это и надёжнее,", "Зато всё безопасно". Нет, конечно. Надёжность тут не причём. Так просто удобнее и понятнее для человеков: не видно, что не должно быть видно. Т.е. чисто иллюзорные результаты.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 10.04.2025 11:24 · . Предыдущая версия .
Re[24]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 11.04.25 05:11
Оценка: 2 (1)
Здравствуйте, ·, Вы писали:
S>>Независимо от моих "привилегий".
·>Закрытые для кого? Закрытость — вещь относительная. На какие-то атрибуты у тебя есть привилегии, на какие-то нет. У других пользователей будет другой доступ к атрибутам.
Нет. Вот как раз предлагаемая вами модель чревата дырками и крайне тяжела в поддержке и верификации.
Я вам рассказываю практический замкнутый пример: нет никаких "привилегий на втрибуты". Есть два вида ресурсов. Доступ к каждому их них либо есть, либо нету.

·>Каким образом закрыт-то? Заклятие наложено что-ли? Субресурс возвращает джсон, как ты ресурсом гарантируешь отстутствие там какого-нибудь contragent.homeAddress?

Очень просто: contragent.homeAddress там нет вообще, вне зависимости от привилегий.

·>Верю. Но не потому, что "API устроен именно так".



·>Почему ты так решил? Ты так говоришь, что ресурс это какая-то охраняемая зона за колючей проволокой.

Потому что я так спроектировал, и это легко проверить как методом "белого ящика", так и "чёрного ящика".
·>Нет, это просто несколько байт в определённом месте хедера запроса, а обрабатывает всё это дело тот же самый условно питонячий код, что и для других ресурсов.
Если у вас так, то всё плохо. Попробуйте перепроектировать так, чтобы в одном коде не смешивалась обработка "своих" и "чужих" инвойсов. Человечество изобрело массу способов факторизации кода.

·>Я спорю с тем, что ресурсы и урлы каким-то образом обеспечивают хоть какую-то безопасность. Что в зависимости от того куда поместить данные — в урл или хедер — вдруг внезапно станет "Зато всё безопасно".

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

·>А чё так мелко? Сразу уж говори — источник данных — заряд на затворе транзистора. Да, там с привилегиями как-то не очень. Я вообще-то говорил о дизайне самого сервиса. БД — это уже другой сервис.

Нет, БД — это не "другой сервис", это неотъемлемый компонент сервиса, оборудованного персистентным состоянием.
Впрочем, можно спроектировать и так, как вы предлагаете — вынести БД в отдельный сервис, из которого торчит очень широкий контракт.
И, естественно, у него очень грубый набор привилегий. Ваша модель "давайте мы будем ограничивать доступ путём передачи пользовательского токена вдоль всей иерархии вызовов" работает примерно никогда.
Все практики безопасности как раз так и устроены, что у принципала X нету привилегий к "сырому" ресурсу A, но есть привилегии на доступ к "производному" ресурсу B. Сервис, выполняющий построение ресурса B, выполняется под принципалом Y, который имеет полные привилегии для A, но учитывает привилегии X при отдаче ему производного ресурса B.
Типичный пример применения концепции в рамках SQL99: пользователю нельзя видеть часть строк в таблице X. Мы не можем навесить привилегию на каждую строку. Зато можем сделать следующее:
1. Отбираем у пользователя привилегии на таблицу X
2. Строим на основе X представление Y, в котором добавлен предикат безопасности (типа select * from X where TotalAmount < 100000)
3. Выдаём пользователю привилегии на Y и указываем, что Y исполняется под привилегиями админа, а не пользователя.
Аналогично мы могли бы поступить и с ограничениями на колонки таблицы. Квадратно-гнездовая система, где чётко видна вся схема Y и легко проверить, что туда попадает, а что нет, как методом статического анализа, так и методом выполнения динамических тестов. Вы предлагаете заменить её на некий невнятный код "хранимой процедуры", которая возвращает всякий раз разный набор строк и колонок в зависимости от рантайм-содержимого параметров.
И всё это под тем предлогом, что "какая нам разница, где передаётся информация о привилегиях — всё равно это текст SQL запроса".
Нет, увы. Факторизация кода позволяет нам изолировать разные сценарии.

·>А, так да. Но собственно тут обсуждалось "Безопасность очень часто входит в конфликт с производительностью", мой вопрос был "Интересно узнать какой такой магией фрагмент в урле повышает безопасность?". И в качестве ответа ты внезапно рассказываешь о "поднимает производительность" "не противоречит безопасности".

Фрагмент в урле существует не сам по себе. Структура урла применятся для роутинга — выбора кода, который будет обслуживать поступивший запрос. Правила роутинга — простая, понятная логика, которую легко отладить и гарантировать отсутствие неожиданностей вроде "в ответ на запрос чужих инвойсов внезапно вызвался код по подготовке своих инвойсов".
Следующим шагом мы можем очень легко проверить, что код по подготовке "чужих" инвойсов никогда не возвращает приватных данных. Просто потому, что в этом коде вообще нет такой ветки, которая бы это делала.
Дальше нам остаётся проверить, что мы корректно проверяем claims в токене для того, чтобы понять, что входит в "свои" и в "чужие" инвойсы.
Собственно, на этом всё.

В вашем же подходе в коде какая-то каша, отдаётся примерно произвольный набор атрибутов с соответствии с хитро устроенными предикатами, смешивающими проверку нескольких разных claims. Доказать, что код выдаёт корректное сочетание атрибутов для произвольного сочетания claims — та ещё задача.

·>С чего ты взял? Никогда не было. А вот у тебя иллюзия в полный рост, цитирую: "чтобы границы безопасности совпадали с границами ресурсов. Потому что это и надёжнее,", "Зато всё безопасно". Нет, конечно. Надёжность тут не причём. Так просто удобнее и понятнее для человеков: не видно, что не должно быть видно. Т.е. чисто иллюзорные результаты.

Это оттого, что я плохо объясняю. Разница в подходах есть. Понятно, что достичь приемлемого результата можно в любом подходе, но стоимость получается разной. Когда границы безопасности совпадают с границами ресурсов, это сильно упрощает доказательство корректности. Я выше примерно написал, каким именно способом. Но вы можете мне не верить и писать более дорогостоящие и трудноподдерживаемые системы — у нас же нет архитектурной полиции
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[25]: Каких программ вам не хватает?
От: · Великобритания  
Дата: 11.04.25 12:24
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>·>Закрытые для кого? Закрытость — вещь относительная. На какие-то атрибуты у тебя есть привилегии, на какие-то нет. У других пользователей будет другой доступ к атрибутам.

S>Нет. Вот как раз предлагаемая вами модель чревата дырками и крайне тяжела в поддержке и верификации.
S>Я вам рассказываю практический замкнутый пример: нет никаких "привилегий на втрибуты". Есть два вида ресурсов. Доступ к каждому их них либо есть, либо нету.
Где есть два вида? В спеке?

S>·>Каким образом закрыт-то? Заклятие наложено что-ли? Субресурс возвращает джсон, как ты ресурсом гарантируешь отстутствие там какого-нибудь contragent.homeAddress?

S>Очень просто: contragent.homeAddress там нет вообще, вне зависимости от привилегий.
Как конкретно это гарантируется? Только не говори: "в API нету!". Не слыхал историй, когда какие-нибудь rest-endpoints случайно возвращали json с неожиданными полями. All tests passed, всё у всех работает.

S>·>Почему ты так решил? Ты так говоришь, что ресурс это какая-то охраняемая зона за колючей проволокой.

S>Потому что я так спроектировал, и это легко проверить как методом "белого ящика", так и "чёрного ящика".
Ну о чём и говорю. "Спроектировал" — это написал тонну word-документов и презентаций. И проверить легко, не спорю. А на самом деле json генерится питонячим кодом, который рефлексией вываливает всё что есть. И даже если всё было красиво в начале проекта, то после нескольких лет поддержки, рефакторингов и переписывания вдруг может что-то где-то вылезти.

S>·>Нет, это просто несколько байт в определённом месте хедера запроса, а обрабатывает всё это дело тот же самый условно питонячий код, что и для других ресурсов.

S>Если у вас так, то всё плохо. Попробуйте перепроектировать так, чтобы в одном коде не смешивалась обработка "своих" и "чужих" инвойсов. Человечество изобрело массу способов факторизации кода.
Может такое только в каких-то мелких проектах и пройдёт... И то никакой гарантии, что кто-то куда-то по ошибке не скопипастит. В серьёзных случаях у тебя будет 1024 вида своих и чужих.

S>·>А чё так мелко? Сразу уж говори — источник данных — заряд на затворе транзистора. Да, там с привилегиями как-то не очень. Я вообще-то говорил о дизайне самого сервиса. БД — это уже другой сервис.

S>Нет, БД — это не "другой сервис", это неотъемлемый компонент сервиса, оборудованного персистентным состоянием.
Надо технически смотреть, а не по поверпоинт презентациям. БД — компонент, если embedded, в лучшем случае. А так по сути другой сервис — формируешь запрос (query) и получаешь ответ (recordset). Ничем по факту от какого-нибудь rest не отличается, только протокол общения другой, вместо http у тебя sql.

S>Впрочем, можно спроектировать и так, как вы предлагаете — вынести БД в отдельный сервис, из которого торчит очень широкий контракт.

S>И, естественно, у него очень грубый набор привилегий. Ваша модель "давайте мы будем ограничивать доступ путём передачи пользовательского токена вдоль всей иерархии вызовов" работает примерно никогда.
Что значит "вынести"? Попробуй хоть как-нибудь не "вынести" какой-нибудь оракл из твоего питоячего сервиса.

S>Все практики безопасности как раз так и устроены, что у принципала X нету привилегий к "сырому" ресурсу A, но есть привилегии на доступ к "производному" ресурсу B. Сервис, выполняющий построение ресурса B, выполняется под принципалом Y, который имеет полные привилегии для A, но учитывает привилегии X при отдаче ему производного ресурса B.

S>Типичный пример применения концепции в рамках SQL99: пользователю нельзя видеть часть строк в таблице X. Мы не можем навесить привилегию на каждую строку. Зато можем сделать следующее:
S>1. Отбираем у пользователя привилегии на таблицу X
S>2. Строим на основе X представление Y, в котором добавлен предикат безопасности (типа select * from X where TotalAmount < 100000)
S>3. Выдаём пользователю привилегии на Y и указываем, что Y исполняется под привилегиями админа, а не пользователя.
S>Аналогично мы могли бы поступить и с ограничениями на колонки таблицы. Квадратно-гнездовая система, где чётко видна вся схема Y и легко проверить, что туда попадает, а что нет, как методом статического анализа, так и методом выполнения динамических тестов. Вы предлагаете заменить её на некий невнятный код "хранимой процедуры", которая возвращает всякий раз разный набор строк и колонок в зависимости от рантайм-содержимого параметров.
Я как-то более о практике. Статический анализ, конечно, хорошо... Но если тебе для этого придётся описывать "1024 виртуальных ресурсов" и писать 2048 тестов для них, но это не заработает на практике, хотя в теории, конечно, красота...

S>Нет, увы. Факторизация кода позволяет нам изолировать разные сценарии.

Если у тебя два сценария, то, конечно, это щастье. А вот когда сценариев 1024...

S>·>А, так да. Но собственно тут обсуждалось "Безопасность очень часто входит в конфликт с производительностью", мой вопрос был "Интересно узнать какой такой магией фрагмент в урле повышает безопасность?". И в качестве ответа ты внезапно рассказываешь о "поднимает производительность" "не противоречит безопасности".

S>Фрагмент в урле существует не сам по себе. Структура урла применятся для роутинга — выбора кода, который будет обслуживать поступивший запрос. Правила роутинга — простая, понятная логика, которую легко отладить и гарантировать отсутствие неожиданностей вроде "в ответ на запрос чужих инвойсов внезапно вызвался код по подготовке своих инвойсов".
S>Следующим шагом мы можем очень легко проверить, что код по подготовке "чужих" инвойсов никогда не возвращает приватных данных. Просто потому, что в этом коде вообще нет такой ветки, которая бы это делала.
Ну будет у тебя 1024 кусков кода и неподдерживаемая кодовая база.

S>В вашем же подходе в коде какая-то каша, отдаётся примерно произвольный набор атрибутов с соответствии с хитро устроенными предикатами, смешивающими проверку нескольких разных claims. Доказать, что код выдаёт корректное сочетание атрибутов для произвольного сочетания claims — та ещё задача.

У меня проверка конкретного claim одна же. Я писал выше. Будет что-то
Json getInvoiceForRest(..., securityContext, ...) {
  verifyPrivilegesForTheInvoice(..., securityContext, ...);//тут мы проверяем привилегии для данного инвойса
  return new Invoice {
    date: getInvoiceDate(...)
    contragent: getContragentDetails(..., securityContext, ...)// вот внутри этого метода и проверятся имеющиеся привилегии и вернутся только доступные данные конртагента.
    shipping: getShippingDetails(..., securityContext, ...)// вот внутри этого метода и проверятся имеющиеся привилегии и вернутся только доступные данные о доставке.
  }
}

Конечно, это не отменяет "Правила роутинга" и другие подобные подходы, а дополняет. Как тут Miroff швейцарский сыр упоминал.

S>·>С чего ты взял? Никогда не было. А вот у тебя иллюзия в полный рост, цитирую: "чтобы границы безопасности совпадали с границами ресурсов. Потому что это и надёжнее,", "Зато всё безопасно". Нет, конечно. Надёжность тут не причём. Так просто удобнее и понятнее для человеков: не видно, что не должно быть видно. Т.е. чисто иллюзорные результаты.

S>Это оттого, что я плохо объясняю. Разница в подходах есть. Понятно, что достичь приемлемого результата можно в любом подходе, но стоимость получается разной. Когда границы безопасности совпадают с границами ресурсов, это сильно упрощает доказательство корректности. Я выше примерно написал, каким именно способом. Но вы можете мне не верить и писать более дорогостоящие и трудноподдерживаемые системы — у нас же нет архитектурной полиции
Ну я просто написал когда этот твой способ не работает. Но я, конечно, верю, что в некоторых случаях и твой способ работает. Но это не значит, что он универсальный всемогутер.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[26]: Каких программ вам не хватает?
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.04.25 06:20
Оценка:
Здравствуйте, ·, Вы писали:

·>Где есть два вида? В спеке?

Да, прямо в спеке.

·>Как конкретно это гарантируется? Только не говори: "в API нету!". Не слыхал историй, когда какие-нибудь rest-endpoints случайно возвращали json с неожиданными полями. All tests passed, всё у всех работает.

Я вроде написал, как. Историй про то, как all tests passed, а результат не соответствует — нет, не слышал.
Но вы отклоняетесь: если у вас такие кривые тесты, которые пропускают наличие лишних полей, то в системе с "привилегией на атрибуты" у вас тем более будет бардак.

S>>Потому что я так спроектировал, и это легко проверить как методом "белого ящика", так и "чёрного ящика".

·>Ну о чём и говорю. "Спроектировал" — это написал тонну word-документов и презентаций.
Нет конечно. "Спроектировал" — это построил фреймворк, в котором не так много возможностей накосячить. Архитектура софта не исчерпывается "внешними" требованиями.

·И проверить легко, не спорю. А на самом деле json генерится питонячим кодом, который рефлексией вываливает всё что есть.
Вот это ваше "На самом деле" означает, что вы пытаетесь тестировать код как чёрный ящик. Это не единственный (и не самый эффективный) способ обеспечения качества.
Надо смотреть внутрь, и желающих генерить всё что есть через рефлексию бить палкой на code review.
·>Может такое только в каких-то мелких проектах и пройдёт...
Вот то, что вы предлагаете, как раз и проходит только в мелких проектах. В крупных проектах требуется более строгий контроль, чем "я проверил всю динамику глазами и всё сошлось".
·>И то никакой гарантии, что кто-то куда-то по ошибке не скопипастит.
Гарантия предотвращения ошибочных копипастов достигается юнит-тестированием. Преимущество тут в том, что в коде нет ветвлений — поэтому нам не надо беспокоиться, что "вдруг" в результате образуется сontragent: {homeAddress: {...}}. Достаточно 1 (одного) теста на то, что такого в json нету, и вопрос закрыт.
·>В серьёзных случаях у тебя будет 1024 вида своих и чужих.
Это как раз в несерьёзных случаях. Серьёзные случаи — это как раз какой-нибудь банковский API. И вот там всё именно так, как я сказал. Потому что нельзя позволить ни криворукому девелоперу нечаянно проверить не ту привилегию, так и криворукому админу нечаянно выдать кому-то не ту привилегию.

·>Надо технически смотреть, а не по поверпоинт презентациям. БД — компонент, если embedded, в лучшем случае. А так по сути другой сервис — формируешь запрос (query) и получаешь ответ (recordset). Ничем по факту от какого-нибудь rest не отличается, только протокол общения другой, вместо http у тебя sql.

Верно мыслите, так всё и есть.

·>Что значит "вынести"? Попробуй хоть как-нибудь не "вынести" какой-нибудь оракл из твоего питоячего сервиса.

Ну вот так и не выносим. Оракл является подробностью реализации этого "питонячьего сервиса" и ниоткуда больше не виден. Впрочем, это может быть и не оракл — "питонячьему сервису" с запасом может хватить aqlite.

·>Я как-то более о практике.

Это я о практике, а вы рассказываете какие-то сказки. Ну, точнее вы предлагаете заведомо неудачные решения, через которые мы проходили по нескольку раз начиная ещё с девяностых.
·>Статический анализ, конечно, хорошо... Но если тебе для этого придётся описывать "1024 виртуальных ресурсов" и писать 2048 тестов для них, но это не заработает на практике, хотя в теории, конечно, красота...
Не придётся. Я уже писал причины.
·>Если у тебя два сценария, то, конечно, это щастье. А вот когда сценариев 1024...
Когда у вас 1024 сценария, то деваться некуда. Но чаще это означает, что кто-то не справился с факторизацией сценария, в котором есть 8 отдельных подсценариев, каждый из которых работает независимо и его можно протестировать отдельно, т.к. там вариантов гораздо меньше.

·>Ну будет у тебя 1024 кусков кода и неподдерживаемая кодовая база.

И какая альтернатива?

·>У меня проверка конкретного claim одна же. Я писал выше. Будет что-то

·>
·>Json getInvoiceForRest(..., securityContext, ...) {
·>  verifyPrivilegesForTheInvoice(..., securityContext, ...);//тут мы проверяем привилегии для данного инвойса
·>  return new Invoice {
·>    date: getInvoiceDate(...)
·>    contragent: getContragentDetails(..., securityContext, ...)// вот внутри этого метода и проверятся имеющиеся привилегии и вернутся только доступные данные конртагента.
·>    shipping: getShippingDetails(..., securityContext, ...)// вот внутри этого метода и проверятся имеющиеся привилегии и вернутся только доступные данные о доставке.
·>  }
·>}
·>

Прекрасно. Видна некоторая попытка факторизации. Которая, к слову, совершенно бесполезна в вашем подходе с чёрным ящиком: а вдруг завтра кто-то заменит всю вашу кунсткамеру на "питонячий код, который по рефлексии вываливает сразу всё"?
Ну, и вредна конечно тоже: потому что завтра кто-то в эксплуатации не нарулит кому-то такой набор привилегий, который не даёт выполнить реальный сценарий. Зачем так делать — непонятно. Ну, кроме "нам было лень проектировать, и мы свалили ответственность на кого-то другого.

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

Скорее наоборот: бывают задачи с низкой ответственностью, где можно игнорировать best practices и писать с надеждой на авось.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.