Есть 2 вопроса по архитектуре сервиса.
1 - выделенный(псевдовыделенный) сервис для некоторых заказчиков желающих работать в поддомене(якобы своей отдельной инсталяции)
2 - разделение нагрузки в зависимости от страны/компании/кол-ва сотрудников
Что касается первого вопроса - необходимо сделать отдельный инстанс сервиса под заказчика, либо эмулировать его выделенность, все зависит от приемуществ/безопасности подходов, но на вскидку приведу те до которых догадался(подсказали):
1.1 - использовать во всех таблицах касающихся ресурсов заказчика кроме идентификатора заказчика еще и порядковый номер строки конкретно для данного заказчика (метод по моему самый костыльный и к нагрузке не приспособленный)
1.2 - использовать для каждого заказчика свою таблицу с идентификатором в качестве постфикса для каждой таблицы (метод менее нагрузочный, но нет уверенности в безопасности такого кол-ва таблиц)
1.3 - использовать в пределах одного сервиса для каждого заказчика свою базу именно под информацию касающуюся этого заказчика (как пример используются в сервисе 20 таблиц из них 10 под хранение данных заказчика, поэтому 10 таблиц используются в базе сервиса, а под каждого заказчика заводится своя база на 10 таблиц). Есть ощущение что это будет работать быстрее предыдущих решений, но такая громоздкость очень пугает, есть ощущение оказаться под лавиной.
1.4 - использовать в пределах одного сервера с основным доменом поддомен для заказчика который имеет аналогичный основному набор таблиц в своей базе, только отличается тем что располагается в домене третьего уровня и в нем могут работать лишь сотрудники заказчика. Кажется мне наиболее верным решением, но смущает возможность столкнуться с пределом серверных ресурсов и не понимание как потом поступить.
1.5 - для каждого поддомена использовать свою отдельную виртуальную машину. В данном решении нет проблем с ресурсами, но возникает проблема с автоматическим поднятием экземпляра и поддержанием всех экземпляров в актуальном состоянии.
Возможно есть еще решения, буду рад их услышать.
Что касается второго вопроса, то есть не малая вероятность в предыдущем вопросе пойти по пути 1.5, но ко всему прочему в планах есть связать все экземпляры общим функционалом (как минимум перепиской). А это повлечет за собой необходимость связывать сообщения пользователя с одной виртуалки с пользователями другой. В данном случае вижу пока лишь 3 решения
2.1 - заводится централизованный сервер который держит всю переписку (учитывая как часто люди любят писать, мне кажется что одна таблица с перепиской очень скоро начнет тормозить)
2.2 - заводится централизованный сервер в качестве рутера который должен направлять в зависимости от какого-то фактора клиента на другой сервер где хранится связанное с ним сообщение(он может быть автором либо получателем). Этот вариант более правдоподобен, но не понятна реализация такого рутера и на сколько это будет оперативно работать.
2.3 - при отправлении сообщение хранится у отправителя, а так же копия сохраняется у получателя. Мне кажется это самое легкое решение, но опять же смущает что в определенный момент в пределах одного сервера этих сообщений станет невыносимо много, что скажется на быстродействии.
По первому: наиболее секурно все же отдельные виртуальные машины.
Однако если вопрос только в БД, при условии нормальной архитектуры самого приложения и бд скажем PostgreSQL/Oracle То я бы остановился на схемах. Причем каждый поддомен работает от своего пользователя/схемы с четко разграниченными грантами.
С управляющей схемой контактируют только системы полностью изолированные от пользователя.
Начальное копирование баз для posgre, скажем: от простого дампа основной схемы/create table like до create table of type / inherits
По второму пункту: при грамотной реализации ничего тормозить не будет, во всяком случае у меня 250млн сообщений при 2тысячах активных пользователей не тормозили абсолютно. Тут больше думать нужно над реализаций самих сообщений. Если скажем мы можем удалять свое сообщение из переписки то его копия не нужна, если не можем то табличка вида
-message_id
-message_text
-message_theme (если нужно)
-parent_id (для иерархии ответов, если нужно),
-folder_id (если нужны папочки)
-author_id
-author_name
-recipient_id
-recipient_name
-keeper_id
Решает все проблемы. На каждое сообщение создается два экземпляра и соответственно если keeper_id==author_id то это исходящее, если keeper_id==recipient_id - входящее. Имена отправителя/получателя кешируем в соответствующих полях дабы не выполнять на каждый чих лишний джоин а так же дабы не потерять адресата если вам захочется потереть пользователя из бд (что само по себе плохая идея). Определяемся нужны ли темы,папки итд и составляем индексы под наши запросы - все: радость и счастье, бабочки летают.
А можно узнать хар-ки сервера и среднее время выборки сообщений для одного пользователя при 250млн сообщений?
Кстати с какой целью делалось дублирование сообщений для отправителя и получателя если идентификаторы обоих присутствуют в строке каждой записи(или я не так понял)?
3ton: ibm x346, покупал 8-9 лет назад: 2xXeon 3.4, 8-16 (в зависимости от сервера) GB DDR, 10-15k RPM Raid 1
Среднее время выборки не превышало 300мс, при том что на этом сервере было много чего еще интересного.
Дублирование сообщений делалось с целью возможности хранения независимых историй: отправитель трет у себя все сообщения, получатель имеет их копию, или наоборот. Немного непонял причем тут идентификаторы)
Вопрос очень простой - когда либо данные одного заказчика могут быть использованы у другого? Нет? Тогда чем меньше зависимостей, тем лучше.
Отдельные базы отдельным заказчикам - это и упростит их внутреннюю структуру и решит вопросы с разделением доступа. Что касается балансирования нагрузки - это решается применением виртуальных машин или контейнеров.
Так у вас и полная изоляция будет, и снимки на ходу, и другие радости.
Инструменты для контроля за экземплярами ВМ, кластеризации и балансировки нагрузки на кластер - есть, бесплатны, и весьма удобоваримы.
Мой личный пример - Xen - Pacemaker/Heartbeat - OCFS2
Про виртуальные машины согласен, но вот азчем отдельные базы? Схемы внутри одной бд решают вопрос с разделением доступа, но позволят хоть крос запросы между ними делать если нужно будет.