У нас есть веб-приложение, архитектура которого требует, чтобы любой зарегистрированный пользователь (на самом деле компания) был изолирован от другого, то есть я запускаю одно и то же веб-приложение с теми же моделями данных, но с разными наборами данных для каждого клиента.
Итак, мы подумали о создании отдельной базы данных в Postgres для каждого клиента. Можно ли масштабировать это решение, скажем, до 10-20 тысяч баз данных? Как хорошо?
Есть ли у кого-нибудь лучшее решение для этого?
Заранее спасибо.
Что касается нижнего предела, это в основном сводится к следующему: «Можете ли вы точно сказать, что у вас нет общих данных?» В отличие от mysql, база данных является абсолютной границей в postgresql. Ты не можешь SELECT zip_code FROM common.city_zip WHERE city=...
если вы идете с отдельными базами данных (по крайней мере, не без dblink
).
Если у вас вообще есть общие данные, «Схема» postgresql похожа на то, что mysql называет «базой данных». Ты можешь CREATE SCHEMA clienta; CREATE TABLE clienta.customer (...);
. Вы должны создать схему для каждого клиента, пользователь этого клиента будет сначала иметь свою схему в пути поиска, и будут предоставлены разрешения, чтобы пользователь клиента A имел доступ к clienta
и public
схемы (и их таблицы).
Ваша проблема будет заключаться в том, что на верхнем уровне # клиентов каждая таблица хранится в виде файла, поэтому независимо от того, используете ли вы одну базу данных для каждого клиента, одну схему для каждого клиента или используете что-то вроде ${client}_customer
для имен ваших таблиц вы, скорее всего, столкнуться с ограничениями файлового дескриптора с 10 тыс. клиентов, даже если у вас была только одна таблица на каждого клиента (плюс один файловый дескриптор на соединение). Конечно, вы можете настроить максимальное количество файловых дескрипторов ядра "на лету" с помощью sysctl, но ограничение на процесс (ulimit) потребует перезапуска postgresql, если вы установите его слишком низким в первый раз.
Альтернативой является создание «одной большой таблицы» со столбцом client, который определяет, какому клиенту принадлежит эта строка (в идеале, по имени пользователя, если у вас есть один пользователь на клиента, это значительно упрощает работу ниже). Не предоставляя клиентам никакого доступа к этой таблице, вы можете создавать клиентские представления (или использовать session_user
для идентификации текущего клиента). Однако обновления нельзя выполнять напрямую через представление. Вам потребуются определенные функции для вставки / обновления / удаления в таблице (один набор функций для каждого клиента или с использованием session_user
) с функциями, использующими SECURITY DEFINER
для выполнения в качестве специального пользователя с разрешением вставлять / обновлять / удалять таблицы (примечание: session_user
используется потому что user
и current_user
основаны на текущем контексте, и в функции SECURITY DEFINER это всегда будет пользователь, который определил функцию).
С точки зрения производительности, помимо проблемы с fd, я, честно говоря, не знаю, что произойдет с 10000 базами данных в postgresql по сравнению с одной большой таблицей с данными 10000 клиентов в ней. Правильный дизайн индекса должен предотвращать медленное выполнение запросов в большой таблице.
Я скажу, что здесь я использовал отдельные базы данных для каждого клиента (мы добавляем серверы, чтобы система оставалась работоспособной, при необходимости перемещая клиентские базы данных на новые серверы, поэтому мы никогда не доберемся до 10 тысяч баз данных на одном сервере). Мне приходилось регулярно восстанавливать данные отдельных клиентов из резервных копий для отладки или из-за пользовательских ошибок, что было бы абсолютным кошмаром для дизайна «одной большой таблицы». Кроме того, если вы намереваетесь продавать настройку своего продукта своим клиентам, дизайн «одной большой таблицы» может в конечном итоге помешать вам в возможности настройки модели данных.
Не имея более подробной информации о вашем приложении, трудно сказать, что вы получите дополнительную безопасность от такой настройки. Если каждый клиент подключается к веб-приложению и есть общий пользователь из веб-приложения с базой данных, значит, вы не изолировали свои данные способом, отличным от использования одной монолитной базы данных. Доступ к вашим данным с помощью правильно параметризованных хранимых процедур обеспечит вам уровень изоляции, который вы ищете, без административной головной боли, связанной с управлением 10 000+ базами данных на любом количестве серверов.
Я лично запускал аналогичную настройку на одном сервере базы данных, используя не что иное, как параметризованные хранимые процедуры, обращающиеся к одной базе данных. Если вы можете гарантировать, что единственный доступ к базе данных осуществляется через хранимые процедуры, нет опасности смешивания данных в результатах.
Если вы хотите развить свой дизайн, вот мои основные проблемы:
ulimit -n
) на вашей ОС