Должна ли мультитенантная система с SQL Server 2016, Shard или иметь изоляцию арендатора через отдельную базу данных на каждого арендатора?


12

Учитывая вариант использования:

  • Данные арендатора не должны пересекаться, одному арендатору не нужны данные другого арендатора.
  • Каждый арендатор может иметь большой объем исторических данных.
  • SQL Server размещен в экземпляре AWS EC2.
  • Каждый арендатор географически отдален.
  • Предполагается использовать сторонние инструменты визуализации, такие как PowerBI Embedded.
  • Ожидается, что объем данных будет расти со временем
  • Стоимость системы ограничена.
  • Решение должно обслуживаться без 24/7 производственного администратора базы данных.
  • Решение должно быть в состоянии масштабироваться горизонтально.
  • Общее количество арендаторов меньше 50

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

Я думаю, что это ситуация, отличная от обработки растущего числа арендаторов в архитектуре мультитенантной базы данных . Упомянутый в этом вопросе вариант использования касается большего числа арендаторов, что сильно отличается от очень небольшого (50) крупного арендатора. Упомянутая архитектура могла бы быть решением здесь, о чем я хочу знать больше.

Ответы:


16

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

Когда вы создаете приложение для большого количества клиентов, есть два распространенных способа проектирования баз данных:

  • Вариант А: Поместите всех клиентов в одну базу данных.
  • Вариант 2: создать одну базу данных для каждого клиента

Поместить всех клиентов в одну базу данных

Все просто: просто добавьте таблицу Client в верхней части схемы, добавьте таблицу ClientUsers, чтобы люди могли видеть только свои данные, и все, и мы начнем.

Преимущества этого подхода:

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

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

Проще построить внешний API. Если нам нужно предоставить доступ ко всей нашей базе данных для посторонних для создания продуктов, мы можем сделать это проще, если все данные находятся в одной базе данных. Если API имеет дело с группировкой данных из нескольких баз данных на нескольких серверах, это увеличивает время разработки и тестирования. (С другой стороны, эта вещь «несколько серверов» начинает намекать на ограничение для сценария «одна база данных - правило их всех»: одна база данных обычно означает, что вся наша нагрузка влияет только на один сервер базы данных.) В вашем случае Благодаря PowerBI все в одной базе данных значительно упростят управление соединениями.

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

Помещение каждого клиента в его собственную базу данных или шард

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

Преимущества этого подхода:

Более простое восстановление для одного клиента. Клиенты ненадежные мясные пакеты. (За исключением моего - они надежные мешки с мясом.) У них есть все виды «упс», когда они хотят получить все свои данные в определенный момент времени, и это огромная боль в тылу, если их данные смешаны с другие данные клиента в тех же таблицах. Восстановление в сценарии с базой данных с одним клиентом невероятно просто: просто восстановите базу данных клиента. Никто не затронут.

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

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

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

Более простое управление безопасностью. Пока мы правильно заблокировали безопасность с одним пользователем на базу данных, нам не нужно беспокоиться о клиенте X, обращающемся к данным клиента Y. Однако, если мы просто используем один логин для всех, тогда мы не решаем эту проблему.

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

Какой из них подходит вам?

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

Компания А выделяется в настройке производительности оборудования. Они действительно очень хороши в том, чтобы выжать из оборудования самую последнюю часть производительности, и они не возражают против замены своего оборудования SQL Server в течение 12-18 месяцев. (Они обновляют веб-серверы каждые 4-6 месяцев!) Их ахиллесова пята - экстремальные требования к соблюдению требований и безопасности. У них невероятные потребности в аудите, и им просто легче реализовать пуленепробиваемые элементы управления на одном сервере, в одной базе данных, чем управлять этими требованиями в тысячах баз данных на десятках серверов. Они выбрали одну базу данных, один сервер, много клиентов.

Компания 2 отлично справляется с разработками. Управление изменениями схемы и развертыванием кода в тысячах баз данных для них не является проблемой. У них есть клиенты по всему миру, и они круглосуточно обрабатывают транзакции по кредитным картам для этих клиентов. Им нужна возможность распределять нагрузку географически, и они не хотят заменять серверы по всему миру каждые 12-18 месяцев. Они выбрали одну базу данных для каждого клиента, и это окупается, когда они начинают устанавливать SQL Server в Азии и Европе для своих оффшорных клиентов.


«В вашем случае, с PowerBI, наличие всех в одной базе данных значительно облегчит управление соединениями». Сейчас PowerBI Embedded не имеет безопасность на уровне строк и , таким образом , имея каждый жилец в одной базе данных вызывает некоторые сомнения по поводу этого случая использования, см: community.powerbi.com/t5/Developer/... , в свете этой информации могли бы Вы перефразировать это или предложить альтернативу или исправить мое понимание?
DS

Кроме того, «Поместив каждого клиента в свою собственную базу данных или осколок», вы могли бы
DS

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

5

Еще одно соображение я еще не видел в других ответах.

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

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


4

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

* Это не всегда нарушает нормализацию, но может. Например, если у вас есть Personи PersonAddressтаблица. PersonТаблица будет иметь в TenantID, PersonIDкачестве первичного ключа. PersonAddressТаблица будет иметь в TenantID, PersonID, AddressTypeIDкачестве первичного ключа с тем, что я предлагаю.

Обычно PersonIDэтого будет достаточно, потому что вы можете присоединить это к Personтаблице и найти Tenant. Я предлагаю вам перенести TenantIDна каждую последующую таблицу, даже когда сработает более тонкий ключ.

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


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

3
Но даже если вы решите перенести TenantID в дочерние таблицы, что не нужно делать, более широкая клавиша не означает, что нормализация "нарушена". Подобно тому, как выбор GUID вместо IDENTITY (более широкий ключ) не нарушает нормализацию, так и выбор более широкого естественного ключа вместо использования суррогатов вообще.
Аарон Бертран
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.