#asp.net #sql-server #database-design #fluent-nhibernate #multi-tenant
#asp.net #sql-сервер #проектирование базы данных #свободно-nhibernate #многопользовательский
Вопрос:
Мне нужно принять сложное решение по проектированию базы данных в отношении мультитенантности для растущего числа филиалов веб-CRM-системы моего клиента, которую я активно поддерживаю.
Я заранее принял решение использовать отдельные приложения с отдельными базами данных для каждой ветви, потому что это был самый простой способ обслуживать три разные ветви с разрозненными требованиями к данным и коду. Я также хотел избежать управления идентификаторами клиентов в каждом запросе, как это было с устаревшим классическим приложением ASP (cringe), которое я создал в 2007 году…ужас.
Но сейчас требования к данным для филиалов сходятся, и по мере расширения бизнеса мне нужно иметь возможность быстро развертывать новые филиалы и обмениваться глобальными артикулами продуктов.
Поскольку таблицы и представления одинаковы для всех филиалов, а для управления мультитенантными приложениями теперь доступны более совершенные инструменты ORM, я задаюсь вопросом, было бы лучше иметь общую базу данных для нескольких филиалов.
Соображения, касающиеся централизованной базы данных:
- Глобальные артикулы продукта
- Упрощенные заявки на инвентаризацию
- Проще создавать резервные копии
- Развертывание один раз, а не для каждой ветви
Соображения против централизованной базы данных:
- Легче дифференцировать требования к филиалам с помощью отдельных баз данных
- Модульное развертывание (одна удаленная ветвь не прерывает все)
- Сложнее управлять и разрабатывать для общей базы данных
- Мне нужно изменить нумерацию счетов-фактур (последовательность, сгенерированная seed)
- Меньше предложений WHERE везде
- Восстановление одной поврежденной ветви имеет множество последствий для других ветвей
Маловероятно, что когда-либо будет столько филиалов 10. На данный момент их 3.
Разработчики с реальным опытом в этой области, что бы вы сделали в моей ситуации? Разделять приложения и базы данных или объединить в одну гигантскую систему?
Редактировать: Отличная статья в Microsoft о плюсах и минусах многопользовательской аренды. Я должен отметить, что изоляция данных между ветвями не является серьезной проблемой.
Комментарии:
1. 1 за отличную статью Microsoft. Я нашел это очень полезным.
2. Обновление: спустя три года использование отдельных баз данных оказалось плохим решением, и технический долг растет с каждым днем. Теперь мне приходится потратить несколько месяцев на переписывание кода и перемещение оперативных данных, чтобы централизовать данные всех наших филиалов, чтобы мы могли обмениваться разрешениями, артикулами, создавать отчеты по филиалам и развертывать один и тот же код один раз вместо двенадцати.
3. Я использовал отдельные базы данных (по одной на клиента) на своей предыдущей работе более 10 лет и ни разу не рассматривал возможность их объединения. Что именно в этом было плохим решением? Как именно увеличивается технический долг каждый день? Бьюсь об заклад, мы решили те же самые болевые точки.
4. @AaronBertrand когда я писал этот вопрос несколько лет назад, под арендатором я подразумевал разные отрасли одного и того же бизнеса.
Ответ №1:
Наберитесь смелости и объедините их. Добавьте свой идентификатор клиента туда, где он должен быть, и измените свои запросы.
Для настройки ознакомьтесь с архитектурой типа плагина, которая позволила бы вам развертывать определенные экраны для конкретных клиентов.
У нас есть программный продукт, построенный именно таким образом. Иногда он развертывается на клиентском сайте, иногда мы размещаем его. По сути, на порядок проще иметь дело с одной базой кода, которая имеет клиентские расширения, чем иметь дело с несколькими ветвями кода.
Во-первых, когда мы решаем проблему, мы решаем ее для всех. Конечно, если мы нарушаем его, мы нарушаем его для всех, но для этого и существуют модульные тесты. И чертовски намного проще поддерживать набор модульных тестов для одной базы кода, чем поддерживать их для нескольких ветвей.
Мы занимаемся мультитенантным более 10 лет, и я ни разу не оглядывался назад. Вообще говоря, запросы не так уж сильно отличаются, если вы уже заботитесь о безопасности, проверяя, действительно ли пользователю, извлекающему запись, разрешено ее получать.
Я не согласен с проблемами, поднятыми Корбином. Проблема, связанная с управлением версиями, уже должна быть решена путем создания структуры безопасности на основе атрибутов. Таким образом, вы можете включать / выключать функции с помощью конфигурации пользователя или арендатора. Кроме того, я нахожу очень редким, что клиенту A не нужна та же новая функция, о которой просил клиент B.
Второй вопрос о смешивании данных также не является проблемой. Просто посмотрите на salesforce.com или любому другому крупномасштабному сайту. Они абсолютно используют мультитенантную архитектуру, и, судя по огромному количеству клиентов, которые их используют, это, похоже, не проблема. Главное здесь — быть в состоянии гарантировать вашим клиентам, что их данные защищены.
Ответ №2:
Если вы говорите о 10 филиалах, многопользовательская аренда кажется большой стоимостью с небольшой выгодой.
Существуют сложности с многопользовательской арендой, о которых вы не упоминаете:
- Управление версиями становится затруднительным. Клиентам X, Y и Z может потребоваться новая функция, в то время как клиентам A, B и C — нет. Многопользовательское приложение затрудняет размещение всех пользователей, особенно если новая функция требует изменений схемы базы данных. Это не невозможно, это просто сложнее.
- Некоторым клиентам очень неудобно, когда их данные смешиваются в тех же таблицах, что и у других клиентов. Несмотря на то, что мы знаем лучше, для них это выглядит как угроза безопасности. Юридические отделы ненавидят это. Кроме того, если вы когда-либо выгружаете необработанные данные для клиента, общая база данных требует осторожности.
Вы можете устранить некоторые из ваших болевых точек с помощью лучших практик:
- Автоматизируйте развертывание. Это должно упростить добавление нового клиента или обновление / понижение статуса существующего клиента. Обслуживание базы данных (резервное копирование, перестройка индексов) также должно быть настроено автоматически.
- Храните общие данные (SKU, inventory) в центральной базе данных и предоставляйте каждому экземпляру приложения доступ к ним либо напрямую, либо через службу.
Не поймите меня неправильно, одно из наиболее интересных приложений, над которым я работал, было мультитенантным. В этом могут быть огромные преимущества, но вы, скорее всего, увидите их с тысячами клиентов, а не с десятью.
Комментарии:
1. Я сильно склоняюсь к отдельным базам данных. Задав этот вопрос, я вспомнил, почему я принял решение в первую очередь.
Ответ №3:
Честно говоря, это деловой вопрос. Вы либо сможете предоставлять более настраиваемые функции меньшей группе пользователей в многопользовательской настройке, но с большими затратами на ИТ. То есть вам понадобится больше людей и оборудования (руководство читает это как «деньги»), но вы обеспечите большую гибкость.
Если вы находитесь в ситуации с одним ГИГАНТСКИМ боргом, то вы снижаете накладные расходы на ИТ (опять же, на людей и вещи, на деньги руководства), но вашим конечным пользователям приходится использовать меньшую гибкость в своем программном обеспечении. Все ошибки — это проблемы для всех пользователей, поэтому большие из них быстро устраняются. Однако новые функции также влияют на всех пользователей, поэтому они выполняются медленнее.
Если у вас лично хватит духу сделать этот звонок, а бизнесу просто нужно прислушаться к тому, что вы говорите, или вы можете так или иначе подтолкнуть руководство, я бы посоветовал задать себе ряд вопросов о том, какой сценарий вы предпочитаете:
А) Хотите ли вы, чтобы этим управляло больше людей и разделяли зарплату / ответственность Б) Насколько вам известно, скоро ли появится 4-я группа пользователей? C) Как долго вы хотите остаться в этой компании?
Если вы ответите «да» на первые два, то, вероятно, вам нужен мультитенантный.
Ответ №4:
Я работаю в ситуации, когда по нормативным / юридическим причинам мы должны хранить данные каждого клиента в отдельной базе данных. Однако существует определенная информация, которой необходимо поделиться, в основном связанная с такими вещами, как таблица поиска, URL-адрес клиента для которой соответствует базе данных. Кроме того, клиент может выбрать несколько баз данных, если он хочет разделить свои данные каким-либо логическим способом. Итак, для каждого из наших продуктов у нас действительно есть три типа баз данных:
- ApplicationData, который содержит всего несколько таблиц, содержащих информацию о самих клиентах, например, какую базу данных MasterData (см. Ниже) использовать при переходе по определенному URL и какие функции доступны этому клиенту. Каждый продукт имеет только один ApplicationData, независимо от того, сколько разных клиентов использует этот продукт.
- MasterData, который содержит специфичную для клиента информацию, такую как пользователи, роли и разрешения (в нашем случае, таблицы, которые создает aspnet_regsql, находятся здесь). Среди указанных здесь разрешений указано, какие базы данных clientData доступны данному пользователю (см. Ниже). Схема для всех баз данных MasterData (для одного и того же продукта) одинакова.
- clientData, который содержит данные, с которыми взаимодействует пользователь. В одном продукте это данные, которые клиент может искать на основе большого количества критериев, создавать отчеты и т.д. В другом продукте это содержит динамические данные, которые клиент может загружать, чтобы другие пользователи могли связываться с людьми для проведения опросов по телефону и т.д. Схема для всех баз данных clientData для одного и того же продукта одинакова.
Теперь одно предостережение: мы фактически используем одну и ту же схему и часто одну и ту же фактическую базу данных для MasterData и clientData. Это объясняется историческими причинами, поскольку возможность разрешить клиенту иметь одну базу данных аутентификации (MasterData), соответствующую нескольким базам данных clientData, является относительно новой функцией, которая применима только к одному из наших продуктов. Кроме того, эта структура упрощает развертывание, поскольку большинство клиентов используют только одну базу данных clientData. Однако MasterData и clientData имеют отдельные модели сущностей в рамках Entity Framework в наших проектах, и мы должны убедиться, что между MasterData и clientData нет прямых взаимосвязей, таких как внешние ключи.
Эта настройка работает для нас довольно хорошо. Одним из основных преимуществ является то, что нет проблем с размещением разных баз данных clientData на разных серверах. Это значительно помогает в балансировке нагрузки и обеспечивает естественный способ разделения данных. По сути, мы можем предложить клиенту с огромным объемом данных выделенный сервер базы данных, если он готов за это заплатить.
Еще одна вещь, которая действительно помогла нам в этой ситуации, — это инструменты Red Gate, в частности такие инструменты, как мультискрипт, управление версиями SQL и сравнение схем. Когда мы что-то обновляем и схема меняется, мы должны развернуть изменения во всех соответствующих базах данных. Эти инструменты с лихвой окупили себя за сэкономленное время. Обратите внимание, что я не имею никакого отношения к Red Gate, кроме как как довольный пользователь.
Редактировать: (в ответ на комментарий)
ApplicationData — это одна база данных для каждого продукта. Три имеющихся у нас веб-продукта используют одну и ту же схему для ApplicationData, поскольку они записывают в основном одни и те же типы информации. Однако нет никаких причин, по которым это должно было бы оставаться таким образом. Все базы данных ApplicationData находятся на одном сервере. Одна из таблиц в ApplicationData указывает на правильный сервер и имя базы данных для MasterData клиента, поэтому MasterData для данного клиента может находиться на любом сервере.
MasterData содержит информацию об именах сервера и базы данных для каждой базы данных clientData, поэтому, опять же, базы данных могут находиться на любом сервере. На практике на данный момент у нас всего два производственных сервера баз данных для этих продуктов. Схема MasterData аналогична для каждого продукта, но я не думаю, что они точно такие же (я должен был бы проверить). У каждого клиента есть свои собственные MasterData. Если клиент покупает несколько продуктов, для каждого продукта для этого клиента есть MasterData; продукты взаимодействуют другими способами (в основном через веб-службы), если клиент приобрел эту функцию (или запрашивает пользовательскую разработку такой функции. Данные клиента для данного продукта всегда имеют одну и ту же схему.
Итак, вкратце:
- ApplicationData для каждого продукта и, оказывается, имеет одну и ту же схему в каждом продукте.
- MasterData для каждого клиента для продукта.
- Для клиента в продукте имеется один или несколько экземпляров clientData.
Я немного упростил, поскольку только один из наших продуктов поддерживает несколько экземпляров clientData для каждого клиента. Для второго продукта это, вероятно, будет реализовано в конечном итоге. Для третьего продукта это вообще не имело бы смысла как функция и, скорее всего, просто останется как есть.
Я надеюсь, что это отвечает на ваш вопрос!
Комментарии:
1. Приятный отзыв. Можете ли вы уточнить, какие из ваших баз данных
ApplicationData
,MasterData
иClientData
являются общими для продуктов / клиентов / серверов? Как небольшой разработчик, я пока не могу позволить себе инструменты Red Gate, хотя они мне очень нужны для моих частых приключений с базами данных.2. @FreshCode Отредактирован, чтобы ответить на ваш вопрос.
Ответ №5:
Что ж, если существует тенденция к совместному использованию информации и данных между различными филиалами, вам, вероятно, лучше иметь одну центральную базу данных.
В противном случае этапы, через которые вам придется пройти, чтобы получить возможность совместного использования данных, будут намного хуже, чем дополнительные предложения WHERE, необходимые для общей базы данных.
Вы могли бы, конечно, иметь по базе данных на филиал и дополнительную базу данных (на данный момент четвертую базу данных) в качестве централизованного хранилища для информации, которой требуется совместное использование. Хотя вам нужно было бы посмотреть, делает ли чрезмерное усложнение это лучшим или худшим решением из обоих миров 🙂
Комментарии:
1. Я новичок в NHibernate. Как бы я сделал это прозрачно, если центральный ASP.NET Приложение MVC имеет отличительный параметр {branch}?
2. Вы меня на минуту потеряли, как здесь вступает в игру NHibernate? Я просто давал советы по возможному рассмотрению подхода, у меня нет опыта работы с NHibernate. Не могли бы вы немного более четко ответить на этот последний вопрос?
3. извините — я должен опубликовать отдельный вопрос.
Ответ №6:
Если мы говорим о CRM, то каковы шансы того, что один клиент находится в нескольких базах данных? Если есть хоть малейший шанс, что вас попросят объединить данные клиентов по филиалам, я бы определенно выбрал одну централизованную базу данных.
Ответ №7:
Децентрализация IMO становится арендатором поддерживаемого и масштабируемого дизайна. Единственная централизованная база данных, которую я использую, предназначена для обеспечения безопасности при аутентификации, которую я в настоящее время превращаю в децентрализованную базу данных для авторизации. Таким образом, вся авторизация может оставаться на том же самом краю, где физически находится приложение, без обхода сети, поскольку авторизация не является отличным кандидатом для кэширования.
Читая, что вы конкретно заинтересованы в нескольких ветвях одного и того же приложения, в отличие от действительно разнородных приложений, кажется, что отличным вариантом было бы построить вашу базу данных вокруг процесса заполнения (Entity Framework поддерживает это), который позволил бы вам просто развернуть ваш новый код ветви в ASP.NET , а затем во время первоначальной сборки базы данных, когда таблицы физически созданы, вы опрашиваете «благословенный» сервер и сбрасываете все необходимые данные на пограничный сервер.
После этого вам потребуется некоторая настройка репликации, если новые продукты добавляются в основное хранилище данных и ожидается, что они попадут в каждое пограничное хранилище. Вы могли бы выполнить это с помощью прямой репликации вашей базы данных или обратиться к таким инструментам, как Microsoft Sync framework.
Ответ №8:
Сегодня вы можете думать, что у вас будет всего несколько клиентов, но через несколько лет вы, возможно, поймете, что продукт потенциально может быть продан сотням клиентов. Если это произойдет, вы пожалеете, что использовали подход с одним арендатором.
Сравните затраты на:
- Преобразование производственной системы из однопользовательской в многопользовательскую, в которой базы данных заполняются данными клиентов
- Разработка многопользовательской системы, несмотря на то, что вы думали, что вам не понадобятся преимущества
Преобразование производственной системы — сложная и очень дорогостоящая задача. Использование второго подхода может обойтись вам дороже на начальном этапе, но это дает вам очень ценную возможность добавлять больше клиентов в будущем по низкой цене. Цена этой опции может стоить того, чтобы ее заплатить.