Обработка растущего числа арендаторов в архитектуре мультитенантной базы данных

26

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

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

Кроме того, всем арендаторам и их пользователям будет представлен общий процесс входа в систему (т. Е. Каждый арендатор не может иметь свой собственный URL). Для этого мне нужен централизованный процесс входа в систему и средства для динамического добавления баз данных в систему и регистрации пользователей.

  • Как можно автоматизировать процесс регистрации и создания базы данных?

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

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

  • Если мне нужно «масштабировать» путем добавления нескольких серверов баз данных, может ли кто-нибудь подсказать, какие проблемы могут возникнуть при управлении идентификаторами пользователей на разных серверах (олицетворение и т. Д.) И каким образом можно смягчить эти проблемы?

coddey
источник
1
Мне не приходилось иметь дело с подобной ситуацией, но моя интуиция заключалась бы в том, чтобы справиться с развертыванием арендаторов, предварительно сконфигурировав серверы с таким количеством баз данных арендаторов, которое, как вы думаете, они могут обработать, а затем просто назначив предварительно созданные базы данных арендаторов в качестве новых арендаторов. Зарегистрироваться. Таким образом, вам не нужно беспокоиться о конфликте ресурсов при развертывании БД-арендаторов.
Джоэл Браун
1
Вы уверены, что вы получите где-то близко к 5000-10000 арендаторов? И что все ваши арендаторы будут в диапазоне 2000 пользователей? Я думаю, что в моей системе наибольшее количество пользователей нашего приложения для одного арендатора составляло около 100. И из них только 20 или около того были последовательно активны. Могу я спросить, что такое индустрия / приложение?
Аарон Бертран
@AaronBertrand Это система управления обучением, где услуги будут частично бесплатными и частично платными.
Кодди

Ответы:

25

На нижнем уровне (500 арендаторов / 10000 пользователей) я так и сделал. Во-первых, у вас есть «контрольная» база данных, которая является глобальной, центральной и содержит всю информацию об арендаторах и пользователях (я действительно не думаю, что вы хотите управлять ими как аутентификационными логинами SQL). Итак, представьте базу данных с именем «Control» со ​​следующими таблицами:

CREATE TABLE dbo.Instances
(
  InstanceID INT PRIMARY KEY,
  Connection VARCHAR(255)
  --, ...
);

INSERT dbo.Instances SELECT 1, 'PROD1\Instance1';
INSERT dbo.Instances SELECT 1, 'PROD2\Instance1';
-- ...

CREATE TABLE dbo.Tenants
(
  TenantID INT PRIMARY KEY,
  Name NVARCHAR(255) NOT NULL UNIQUE,
  InstanceID INT -- Foreign key tells which instance this tenant's DB is on
  --, ...
);

INSERT dbo.Tenants SELECT 1, 'MyTenant', 1;
-- ...

CREATE TABLE dbo.Users
(
  UserID INT PRIMARY KEY,
  Username VARCHAR(320) NOT NULL UNIQUE,
  PasswordHash VARBINARY(64), -- because you never store plain text, right?
  TenantID INT -- foreign key
  --, ...
);

INSERT dbo.Users SELECT 1, 'foo@bar.com', 0x43..., 1;

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

Базы данных были созданы с использованием схемы имен, Tenant000000xxгде они xxпредставлены Tenants.TenantID. Это сделало работу по обслуживанию довольно легко, вместо того , чтобы все виды баз данных по имени BurgerKing, McDonalds, и KFCт.д. Не то , чтобы мы были в фаст - фуд, просто используя его в качестве примера.

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

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

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

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

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

SELECT i.Connection
  FROM dbo.Instances AS i
  INNER JOIN dbo.Tenants AS t
  ON i.InstanceID = t.InstanceID
  INNER JOIN dbo.TenantUsers AS u
  ON i.TenantID = u.TenantID
  WHERE u.UserID = @UserID;

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

Если вы попадаете в эту 10-миллиметровую пользовательскую область, которую вы предлагаете, вам определенно нужно, чтобы она была лучше сбалансирована. Возможно, вы захотите объединить приложение так, чтобы они имели разные точки входа, подключающиеся к разным управляющим базам данных. Если вы дадите каждому арендатору субдомен (например, TenantName.YourApplicationDomain.com), то вы можете сделать это негласно с помощью DNS / маршрутизации, не прерывая их, когда вам необходимо продолжить масштабирование.

В этом есть много чего другого - например, @Darin. Я здесь только царапаю поверхность. Дайте мне знать, если вам нужна несвободная консультация. :-)

Аарон Бертран
источник
Спасибо за то, что поделились своим опытом. На самом деле это просветило меня. Но ты уже написал Non-free. :(
coddey
1
Моя точка зрения заключалась в том, что у меня есть только столько времени, чтобы выделить бесплатные консультации. :-)
Аарон Бертран
+1 - почти такой же подход, как и раньше. Одинаковое количество арендаторов тоже работало очень хорошо.
AdaTheDev
Как обрабатывать отношения между основной базой данных и базой данных арендаторов? (без использования триггеров и т. д.)
Джитендра Панчоли
У @jitendra не так много вариантов - сколько данных у вас действительно есть в базе данных арендаторов, которая должна относиться к данным в основной базе данных? Я также не уверен, что понимаю популярный страх перед триггерами - правильно написанный триггер не стоит бояться ...
Аарон Бертран
10

У вас есть довольно интересный проект. Я никогда не видел, чтобы кто-то пытался реализовать что-то такое большое, по крайней мере, на SQL Server. Чем больше я читаю ваш пост, тем больше вопросов я задаю ...

В худшем случае в инфраструктурном сценарии (который на самом деле является наилучшим сценарием для бизнеса), вам нужно 10 тыс. Баз данных на 2 тыс. Пользователей. Это 20 000 000 пользователей. Вы не добьетесь успеха в попытке управлять 20 М именами входа SQL Server. ИМО. Только их огромное количество, касающееся перемещения их с сервера на сервер, отслеживания коллизий идентификаторов и несовпадения идентификаторов, плюс я не уверен, как SQL Server будет вести себя с 20 миллионами строк в sys.server_principals. Кроме того, ваше веб-приложение, вероятно, захочет подключиться как один или очень небольшое количество пользователей. IIS не может объединять соединения, если их строки DSN не идентичны. Одним из атрибутов строки уведомления о доставке является имя пользователя. Разные пользователи означают отсутствие объединения.

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

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

Еще один быстрый вопрос: если я скажу вам, что работаю в FuBar, Inc., откуда вы это знаете? Собирается ли FuBar предоставить вам список пользователей, а вы возвращаете им список имен пользователей, или они собираются самостоятельно?

Вам нужно будет перейти на несколько экземпляров. Если хотя бы небольшая часть этих пользователей решит сразу же запустить приложение, один экземпляр исчезнет. У него не будет достаточно рабочих потоков для одновременного выполнения всех этих запросов. Если только 1000 пользователей одновременно ударили по вашему экземпляру, он, вероятно, исчерпает рабочие потоки, и запрос начнет складываться и ждать. Я видел, как это произошло; Непосредственный признак состоит в том, что новые соединения не смогут войти в экземпляр, потому что нет доступных рабочих потоков для их обслуживания. Если это очень недолгое поведение, ваше приложение может выжить. Если нет, или ваше приложение суетливо, пользователи получат ошибки.

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

Вам понадобится способ перемещения баз данных с перегруженных серверов на слегка загруженные (или новые) серверы. То, сможете ли вы получить окно простоя, зависит от вашего SLA.

Вы предоставляете конкретное приложение, такое как SalesForce, или эти базы данных являются просто контейнерами для того, что ваши арендаторы хотят добавить?

Насколько велики базы данных? Если они не очень большие, вы можете просто восстановить из файла резервной копии, которая предоставляет шаблон. (Это не сильно отличается от того, что делает база данных модели, но я не видел, чтобы кто-то действительно хорошо использовал модель с тех пор, как я работал с SQL 6.5.) Как только шаблон был восстановлен с новым именем базы данных, вы могли бы затем настройте новую базу данных по мере необходимости для конкретного арендатора. Очевидно, вы не можете выполнить настройку до того, как получите арендатора. Если база данных большая, вы можете выполнить ту же самую базовую процедуру, за исключением того, что вы выполняете восстановление заранее, прежде чем любому новому арендатору понадобится место. Вы можете хранить несколько таких баз данных, возможно, по одной на экземпляр. Если вы держите слишком много, это может заставить вас купить больше оборудования и / или хранилища, чем вам нужно,

Если это ваше собственное приложение, как вы собираетесь обрабатывать обновления схем? Как вы собираетесь хранить версии базы данных в одном месте с версиями кода, если вы используете один URL, который попадает в ваше веб-приложение?

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

Если арендаторы управляют разрешениями, это подразумевает, что они имеют некоторое представление о внутренней работе приложения или что ваше приложение имеет очень простую структуру ролей. Используя что-то вроде Blogger в качестве грубого примера, пользователи могут (читать сообщения), (читать сообщения и оставлять комментарии), (... и создавать сообщения), (... и редактировать сообщения других пользователей), (... и могут сбросить настройки пароли других пользователей) или (... и что угодно). Наличие роли для каждого из этих различных наборов прав и назначение пользователю той или иной роли не должно быть слишком сложным, но вы не хотите, чтобы ваше приложение выполняло операторы «GRANT». Следите за ролями, которые имеют иерархию и зависят от наследования, это может запутать. Если вы продвигаете или понижаете пользователя, я бы сказал, что вытащите его из всех связанных ролей, а затем добавьте обратно к той роли, которая ему нужна. Ой,

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

пролив дарина
источник
Спасибо за комментарии. На самом деле проект интересный. Из-за ограниченности слова я оставлю комментарий очень точным. Это система управления обучением, в которой у каждого арендатора будет около 120-150 столов. Ни у одного пользователя не будет одинакового имени пользователя, независимо от арендатора. Для дальнейшего снижения сложности DNS-сопоставления CNAME будет использован пример tenant1.abc.com. Точка кипения - это правильное проектирование, чтобы оно отвечало всем предложениям, которыми вы поделились, и я беспокоюсь за них. Получение whitepaper будет достойно похвалы, но это не так просто, возможно. Нужно больше информации, если вы можете. !!!!
Кодди