Как расширить однопользовательский WebApp для нескольких пользователей
Есть похожие темы без конкретного решения, и я подумал, что лучше начать новую.
Я сталкиваюсь с ситуацией, когда у меня есть веб-приложение, размещенное в RESIN (точно так же, как Tomcat, я думаю). До сих пор я разрабатывал приложение с использованием db4o, так как я один, и мне нужно было завершить приложение как можно скорее, у меня есть БД для пользователей и еще одна БД для данных приложения для одного пользователя (меня), теперь, когда приложение почти Готово Я собираюсь перейти к postgresql и серьезно подумываю о БД на пользователя, даже если БД хранит данные для нескольких приложений, так как она будет обрабатывать довольно конфиденциальные данные, и я подумал, что лучше использовать отдельную БД (с точки зрения безопасности). Уже есть элементарное управление сессиями, которое хранит пользовательские данные, такие как идентификатор, в браузере. Но мне было интересно, как я могу расширить его до нескольких пользователей / дБ.
Я думал о расширении класса слушателя, который хранит данные контекста для передачи нужного объекта БД в экземпляр приложения, или, возможно, для этой цели установил фильтр.
.ОБНОВИТЬ.
Я хотел бы дать немного больше понимания того, что у меня есть.
Я имею:
Контекст, который содержит ссылку на некоторые объекты, один из этих объектов подключается к БД и проверяет пользователя и пароль.
Сервлет представления (HttpServlet), сопоставленный с "/", который имеет форму входа в систему, которую POST вводит в /login.
Сервлет входа в систему (HttpServlet), сопоставленный с "/login", который проверяет атрибуты пароля пользователя httpSession по отношению к соответствующему объекту, который находится в контексте, при наличии совпадения устанавливает атрибут httpSession, который содержит USERID, и перенаправляет пользователя на само приложение, расположенное в /index-debug.html, если нет, он снова создает новую HTML-страницу с формой входа.
Фильтры авторизации и аутентификации сопоставлены с /index-debug.html, который проверяет httpServletRequest для атрибута USERID и проверяет, имеет ли пользователь разрешение на доступ к приложению.
Наконец, bean-компонент, отвечающий за чтение и запись в базу данных пользовательских данных webApp. Когда я выполняю определенный метод в webApp, CP2JAVAWS сопоставляет этот метод с соответствующим методом в бине, проблема заключается в том, что у этого бина есть статическая база данных, и на данный момент он допускает только одного пользователя.
Что я хотел бы сделать, так это как-то позволить этому компоненту БД создавать экземпляр один раз для каждого пользователя и читать и сохранять соответствующие данные в зависимости от текущего зарегистрированного пользователя.
Идея одной БД на пользователя в настоящее время отбрасывается, но я не знаю, как именно это осуществить.
2 ответа
Вы упомянули Postgres в качестве бэкэнда базы данных, у которого есть функция, называемая схемами. Это то, где у вас есть одна физическая база данных и несколько схем внутри базы данных. Мой опыт работы с этим связан с Rails, но концепции те же. Этот метод позволяет избежать объединения данных людей в одном наборе таблиц, что звучит как ваша основная задача. Я знаю, что вы используете Java, но посмотрите этот доклад о мультитенантных приложениях в Rails, чтобы получить представление от Гая Наора о том, как это работает, компромиссах и т. Д.
Вот несколько конкретных шагов, которые помогут вам начать использовать схемы Postgres:
- В Postgres есть общедоступная схема, которая используется по умолчанию. Это место, где вы размещаете свои таблицы аутентификации пользователя и любые другие общие таблицы метаданных о входах пользователей и т. Д. См. Документацию Postgres для получения дополнительной информации о том, как работают схемы.
Придумайте соглашение об именах для каждой создаваемой схемы (например, user_001, user_002 и т. Д.). Предварительно выделите кучу пустых схем со всеми настройками таблиц, и когда пользователь регистрируется или входит в систему в первый раз, вы назначаете им схему и сохраняете имя схемы в своей записи пользователя в общедоступной схеме и в объекте пользователя, который у вас в HttpSession. Не будет необходимости запускать сценарии создания таблиц для первого пользователя - это приведет к снижению производительности в веб-приложении. Вам просто нужно опередить скорость новых пользователей. Например, у вас может быть куча пустых схем user_standby_1 ... user_standby_100, а затем, когда кто-то входит в систему или регистрируется, вы запускаете этот sql:
myquery = "ALTER SCHEMA user_standby_? RENAME TO user_?"; myquery.setString(1,standby_id); myquery.setString(2,user_id);
Когда вы создаете ваш bean-компонент (используйте для этого суперкласс, см. Ниже), передайте имя схемы из объекта User из HttpSession, затем выполняйте этот SQL перед каждой операцией, чтобы изолировать их только от их схемы:
myquery2 = "SET search_path TO ?";
myquery2.setString(1,user.search_path);Если у вас есть пустая полная публичная схема, то вы хотите исключить публичную из пути поиска, иначе у вас будет 2 таблицы с одинаковыми именами в пути поиска. Если вы хотите, чтобы путь поиска пользователей включал
SET search_path TO user_001,public
затем, после создания таблиц, удалите все таблицы данных из общедоступных, кроме пользователей, и любую мета-информацию, которая вам нужна.- Для обслуживания напишите сценарий, который вы можете запустить из командной строки, чтобы отбросить пустые схемы user_standby, создать новые схемы user_standby и сделать эквивалент Rails Migrations for Java для незначительных изменений в таблице.
- Для больших операций обслуживания может быть лучше создать новые схемы, например, user_v2_001, для каждого пользователя, а затем написать сценарии для переноса их данных. Это зависит от того, насколько сложны изменения в ваших таблицах.
Если вы идете альтернативным путем и все данные о пользователях представлены в одном наборе таблиц, то лучший способ - это указать user_id в каждой таблице и написать свой SQL, чтобы использовать его каждый раз. Если вы используете традиционную нормализацию и выполняете объединения, чтобы получить свой user_id, лучше убедиться, что вы случайно не пропустили объединение, иначе пользователи начнут видеть данные друг друга.
Функция схемы Postgres позволяет блокировать пользователям доступ только к их собственным данным. После выяснения основ, используйте суперкласс в Java, чтобы написать шаг 3 выше, чтобы каждый MyTableDBBean расширялся от MasterDBBean и использовал конструктор суперкласса, чтобы изолировать путь поиска к схеме пользователя. Тогда у вас есть только 1 место в вашем коде, где это делается, и вам не нужно помнить, чтобы каждая таблица или запрос делали что-то большее, чем бизнес-логика.
Смола! Я давно не слышал и не работал с Ресином. знак равно
Я видел идею, что одна база данных на пользователя системы довольно часто появляется при переполнении стека. Реакция, как правило, одинакова - это не очень хорошая идея.
Причин много, но я буду придерживаться масштаба, ремонтопригодности и изменчивости.
Масштаб
Некоторые базы данных имеют ограничения на количество баз данных, которые они могут иметь. Я не знаю, сколько баз данных может иметь один экземпляр Postgres.
По этой ссылке ( https://dba.stackexchange.com/questions/23971/maximum-number-of-databases-for-single-instance-of-postgresql-9) говорится, что кто-то получил 10000 баз данных в одном экземпляре.
Я бы сказал, что со временем можно получить миллион пользователей для сайта (конечно, не все активные). Другими словами, я бы поспорил, что количество ваших пользователей в какой-то момент сломает Postgres с одной базой данных на пользователя.
Ремонтопригодность
Предположим, что вам нужно всего 10000 пользователей, и вы можете создать 10000 баз данных. Что происходит, когда вы хотите обновить таблицу в каждой базе данных? Больно выкатывать эти изменения.
Обычно случается, что вы пишете сценарий для каждой базы данных, и хотя вы его тестировали, сценарий наполовину умирает, и теперь вы застряли на несколько отчаянных минут с половиной таблиц в одном состоянии и половиной в каком-то другом. государство.
Или, что еще хуже, база данных перестает синхронизироваться и имеет другую схему, чем остальные базы данных. Теперь у вас есть потенциально более одной действующей версии пользовательской базы данных.
летучесть
Пользователи непостоянны. Они подпишутся сегодня и никогда не вернутся. Они зарегистрируются, а затем снова войдут в систему через два года. Они будут создавать несколько учетных записей, потому что они забыли свой пароль.
Это быстро приведет к появлению осиротевших баз данных. Вам нужно (или захотеть) написать скрипт, чтобы периодически их очищать.
Также некоторые более современные базы данных (такие как MongoDB и Couchbase) фактически предварительно выделяют большие части диска / памяти при создании базы данных. Я не верю, что Postgres делает это, но это то, что нужно учитывать.
Безопасность
Если кто-то взломает ваш почтовый ящик, разделение пользователей по базе данных не поможет вам. Они могут перемещаться между базами данных так же легко, как и между записями в таблице. Лучше просто хорошо заблокировать машину базы данных, а затем позволить пользователям жить вместе в одной таблице. Это легче масштабировать, легче поддерживать и вы можете управлять волатильностью.