Как стать автором
Обновить

Как устроена наша PIM-система, и почему мы не используем ни реакт, ни микросервисы

Уровень сложностиСредний
Время на прочтение12 мин
Количество просмотров9.9K
Всего голосов 31: ↑29 и ↓2+33
Комментарии38

Комментарии 38

  1. Зашел на ваш сайт на телефоне, прокрутил пальцем полэкрана, чтобы прочитать второй абзац/предложение, и на него тут же сверху наехала плашка, закрыв большую часть текста. Всё, первое впечатление испорчено. Неужели нельзя сделать самую первую страницу, самые первые секунды нормально?) Потом там ниже появляется текст ну очень большим шрифтом. Зачем? Или ваши потенциальные клиенты заходят только с компа и там всё красиво? (лень проверять самому)

  2. Как человеку далёкому от продаж, мне непонятно, как система сама считает остатки. Откуда она берет эту инфу? Продавцы вводят продажи? Цены она пересчитывает, беря последние цены у конкурентов, наверное, а вот с остатками непонятно. С остатками это вообще получается "складской учёт"?

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

  2. Для этого есть интеграции с другими системами. Остатки мы можем забирать из API маркетплейсов, выгружать из 1С, забирать из произвольных файлов в соответствии с тем, как это настроил пользователь. Например, типичный случай: продавец не весь ассортимент держит у себя на складе, часть - берет у поставщиков или партнеров. Те регулярно присылают ему на почту файл с информацией, что у них есть, в каком количестве, по какой цене. Наша система автоматически проверяет почту, разбирает новые файлы и обновляет информацию о ценах и наличии товаров. Я бы не сказал, что это именно складской учет, он сложнее. Скорее - единое окно для работы с максимумом доступной информации.

Все-таки, профессиональные дизайнеры делали. 

Это явно не так. Тут и с визуалом проблемы ("не вкусные" карточки товарав), и с версткой (чего только стоит огромный скролл на полупустой странице), и скрипты ваши на jQuery глючат (например, можно "съесть" гамбургер). И подобных проблем там очень много. Но работает всё очень шустро - это классно.

Спасибо, устраняем проблемы. Часть уже исправили, часть еще в процессе.

Уж лучше эту плашку вообще оставить статически всегда вверху, что ли.

Спасибо за честный рассказ, было интересно.

Много написано про организацию бд, но ни слова про бэкапы, надеюсь они у вас уже делаются )

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

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

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

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

Когда что-то идет не так, пишем скрипт по откату. К счастью, такого опыта пока реально мало, ни одной базы мы пока что не убили. К несчастью, на этот случай нет четкого плана. Что-то типа "Откатим, если что. Если совсем все плохо будет, будем поднимать бекап".

Скрипты можно генерировать автоматически, для этого есть параметр -script для команды update-database. Со стороны разработчика сначала применяем миграцию вперед с этим флагом для создания файла миграции up. Потом откатываем миграцию на предыдущую с этим флагом - получаем файл скрипта отката миграции.

Если нужно в крипт миграции внедрить скл-код мутации данных, то оный можно написать вызвав метод Sql(string sql) в любом нужном месте как в методе up, так и в методе down.

Могу предположить, что такой подход мог использоваться, но почему-то от него отказались.

Спасибо. Я знал про эту возможность, но почему-то не пользовался. Попробуем на практике.

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

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

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

Добро пожаловать в мир WorldWide или корпоративных проектов, где 1000 одновременно работающих клиентов - просто ничто. Нет, не спорю, можно вертикально масштабировать систему и покупать всё более дорогое железо, чтобы поддерживать растущую нагрузку. А когда вы упретесь в пределы возможностей монолитных решений, то, надеюсь сообразите, что все эти брокеры сообщений и микросервисы придуманы вовсе не для того чтобы затруднить вам отладку. Скорее наоборот - вы можете приписать каждому микросервису контракт и протестировать его на соответствие контракту. Чем хороши микросервисы - вы их можете запустить в любом количестве экземляров - для горизонтального масштабирования. И, кроме того, вы можете работать в команде, где у каждого есть своя доля работы и никто никого локтями не толкает, работая над одним клубком.

Но на разработку вы потратили бы в несколько раз меньше времени, не были бы привязаны к платформе

Не могли бы раскрыть подробнее? Дотнет уже много лет как кроссплатформенный.

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

По поводу платформ - хорошо, я объясню. Для вас вся кроссплатформенность сводится к 2м плафтормам - Windows и Linux? А не деле существует масса других платформ, например FreeBSD. Вы собирали .NET под FreeBSD? Наверное нет, потому что совместимые бинарники можно получить только в линукс-эмуляторе. Никаких других способов пока нет / мне не известны / не найдено. Нет способов получить под RT операционными системами, нет для NetBSD, OpenBSD, нет для Solaris и т.п.

Риск в том, что Микрософт - это коммерческая компания, движимая коммерческими интересами и в любой момент может пересмотреть свое отношение к своим продуктам. Это происходило уже не раз - продукты выпускались и прекращались. Кроме того, иногда коммерческие компании идут в суд и отстаивают свои лицензии, как например Oracle идет в суд против Google/android в отношении Java. Это добавляет риск, а не снижает его.

Mono в этом смысле выглядит более практичным выбором, но для ее развития нужен консорциум. Это бы придало большую стабильность продукту и позволило бы планировать в терминах LTS и кроссплатформенность в этом случае совершенно натуральная, как мы наблюдаем в случае open jdk.

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

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

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

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

Про пентесты - не понял, если честно. Речь про DOS с возможным повреждением памяти и выполнением произвольного кода? Но .NET - виртуальная машина, её задача - такого не допускать, и про такие атаки я не слышал. Мы же не на плюсах пишем.

Что касается джавы, то соглашусь отчасти. Все-таки .NET для веба лучше подходит по моему субъективному мнению, а C# как язык приятнее. Что касается тайпскрипта и пайтона, то у них преимуществ для решения наших задач я не вижу. Я реально много времени провел в DotTrace, и, боюсь, что в случае с пайтоном и тайпскриптом приемлемой скорости я бы не добился. В общем, сделайте скидку на то, что C# - мой основной язык, а с перечисленными вами у меня гораздо меньше опыта.

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

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

Сначала клиенты и продажи, потом микросервисы и шины данных.

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

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

Если что, под "предсказуемой памятью" я подразумевал следующее: нам нужно в памяти иметь дерево на, скажем, 100 миллионов узлов. Тогда мы точно знаем, сколько оно займет памяти,

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

Про пентесты - не понял, если честно

Ничего страшного. Не все знают всё. Но почитайте на всякий случай как проводят тестирование https://en.wikipedia.org/wiki/Penetration_test

Речь про DOS с возможным повреждением памяти и выполнением произвольного кода? Но .NET - виртуальная машина, её задача - такого не допускать

Ох. Почитайте сколько CVE с RCE в .NET приложениях было открыто. Вот вам просто один пример https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-36788 Не делаейте таких bold утверждений.

 Что сначала нужно найти бизнес-модель, а потом - масштабироваться

Бизнес модель и дизайн системы идут в начале, и дизайн отвечает требованиям бизнес модели и диктует как должно быть построено приложение. Если у вас 1 пользователь и нет и никогда не прдевидится 1000 или больше, то наверное монолитное решение ок. Но если и вдруг масштабирование предвидится в какой-то пусть и отдаленной перспективе, то монолитное решение не годится и нужно заново делать дизайн и заново переписывать почти всё. Поэтому "а потом масштабироваваться" - это ошибка. Дизайн закладывает как вы будете масштабироваться.

И что с поиском бизнес-модели и места на рынке микросервисы никак не помогают, а сложность вносят

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

и ресурсы тратят.

Всё тратит ресурсы. И монолит тоже. Если нагрузки нет, то монолит может дать преимущество. Если есть, то это большой вопрос. С микросервисами вы имеете возможность масштабировать нагруденные участки (сервивисы) и остальное не масштабировать, а с монолитом вы вынуждены масштабировать весь монолит, запуская его целиком на всех нодах, даже если узкое место в какой-то его конкретной части. Пример на пальцах - допустим у вас 1 узкое место. Чтобы работало под нагрузкой вам нужно иметь 10 запушенных экземпляров . 10 запущенных монолиров потребуют больше ресурсов, чем если вы разрежете монолит на, допустим 5 микросервисов, так что то узкое место будет лишь в одном из них и отмастштабируете это 1 место в 10 раз.

Я реально много времени провел в DotTrace, и, боюсь, что в случае с пайтоном и тайпскриптом приемлемой скорости я бы не добился

Возможно. Возражений против С# у меня нет и не было. Были лишь высказаны опасения про платформу .NET, если вы на ней, а не на Mono или какой-то другой альтернативе, которая в меньшей степени привязана к бизнеспрактикам коммерческих компаний.

Скорость системы зависит от многих факторов - не только от языка. Язык важен лишь если у вас CPU-bound или Memory-bound задача. Если у вас именно такой случай, то да, не спорю, С# может быть хорошим выбором. И да, если вы не хотите тратить время на изучение других языков, то и единственным. А я бы посмотрел в сторону GoLang и Rust в таком случае, оставив пайтон или тайпскрипт для задач по data-moving с минимальными трансформациамяи.

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

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

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

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

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

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

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

Что касается отказа от очередей, решение не принципиальное - не нужны нам очереди, и все тут. Скорее ситуативное - пока нет необходимости, не усложняем. Увидим, что приплыли, пора - будем внедрять.

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

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

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

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

Это к чему: тоже иногда приходится использовать велосипеды, в надежде скроить/сэкономить, но еще не было случая, чтобы об этом позже не пожалел. Каждый раз в итоге оказывается, что дешевле было потратить еще немножко времени, и разобраться с общедоступными инструментами, и сделать сразу как нужно, по-человечески

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

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

С этой подводной лодки я никуда не денусь, это мой проект, и все риски на мне, если что.

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

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

Что касается того, почему это не отдельный сервис:

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

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

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

Задач относительно немного, и с таким набором требований оказалось проще самим написать логику очереди, чем использовать готовое решение. Когда эта часть станет узким местом, будем внедрять готовый MQ.

А, ну это называется "интеграция через БД". Тоже писал нечто подобное, правда не в таких масштабах. И у меня тоже был модульный монолит, но на Java.

Теперь я знаю что это паттерн разработки "так тоже делают" :)

А еще бизнес может никогда не вырости до необходимости всего этого. Несколько лет назад была неплохая статья, типа вы не в google и с вероятностью 99% ваша компания не будет такой. Поэтому тащить все наработки гигантов в любой проект это так себе идея. Думаю как раз Ваш подход правильный

В докуберные времена многие системы выглядели примерно так же. Одна-две базовых технологий, классические SQL-базы, файловые хранилища, балансировщик. Всё простое и понятное. До чего же тёплые воспоминания...

Зашёл на сайт с мобилки, нажал два раза на гамбургер - он исчез =)

Хорошая статья, важно не забывать о том что не надо оверинженирить со старта без необходимости. А можете рассказать подробнее про UI? Что там используется? Razor, Blazor (WASM/SERVER) ?

Ничего из перечисленного, олд скул: сервер генерирует html, на клиенте - jquery, пара плагинов, самописные скрипты.

Blazor Server и Razor Pages тоже генерирует HTML на сервере.
Или у вас свое какое то свое самописное решение? Файлики в *.cshtml / *.razor - это то что есть из коробки (razor/blazor)

Ой, Razor конечно. Не знаю, как прочитал прошлый ваш комметнарий, и почему Razor не увидел.

Как я вас понимаю :) У меня тоже сейчас задача обработки сотни миллионов документов... И все правильные "чистые архитектуры", "чистый код" и прочее подобное идут лесом. Я боюсь даже в функции лишний раз код выносить, а не то что нагромождение из иерархии классов делать, ибо всего одна лишняя миллисекунда выльется в часы или даже дни дополнительной обработки.

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

День добрый.

  1. А что за провайдер/хостинг такой что дает вам MsSQL с лицензией? Насколько я слышал для России лицензии закрыли.

  2. Из текста непонятно в итоге где храните логи. Поделитесь?

Вопрос с хостингом закрывает человек в ЕС.

Логи хранятся в sql базе данных, поскольку работа с ними производится через Entity Framework, СУБД может быть любой.

Всё правильно сделали - запустили продукт, сфокусировавшись на самом важном. Да, дизайн устаревший и местами с ошибками - ничего, допилите. В качестве конструктивной критики, про вёрстку https://catalog.app/lite:

У заголовка H1 на мобилках слишком большой шрифт - вылезает за границы. Для английского языка "Boost your sales" всё помещалось бы в экран. Русские "Управленческий" или "Спецпредложение" часто портят покупные темы с бутстрапа.

Дальше текст с центрированием. 2 коротких предложения будут смотреться нормально. 2 абзаца текста с рваным левым краем очень неудобны для чтения.

Для input "запросить демо" можно применить ввод только телефона, чтобы клавиатура на мобильных была с крупными цифрами.

Разрядка текста визуально прыгает в .commun-card H5 - line-height: 1.1 явно маловато.

Но всё равно - молодцы!

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории