Лучшие практики для разработки мультитенантного приложения с Symfony2 и Doctrine2 - PullRequest
19 голосов
/ 24 сентября 2011

Я работаю над приложением, которое должно поддерживать мультитенантную модель.Я использую Symfony2 php framework и doctrine2.

Я не уверен, что лучший способ разработать это требование.Предоставляет ли функциональность Symfony ACL часть решения?

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

Моя первая мысль - использовать столбец tenant_id во всех таблицах, и это относится к объекту учетной записи в приложении.Однако я не уверен, что ACL должен позаботиться о том, что я хочу сделать, или вы все еще отвечаете за все запросы к вашим объектам, чтобы они не возвращали несанкционированные данные.

Если бы я не использовал Doctrine, было бы легко сказать просто добавить Where tenant_id = @accountid к каждому запросу, но я не уверен, что это правильный подход.

Спасибо

Ответы [ 6 ]

5 голосов
/ 07 февраля 2012

Мы занимаемся этим уже некоторое время (хотя не с symfony и доктриной, но проблемы остаются теми же) - мы начали с одной огромной базы данных и внедрили «идентификатор среды» для каждой строки в каждой из таблиц.Таким образом, миграция схемы была простой: весь код был унифицирован, поэтому изменение схемы было одним изменением кода и схемы.

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

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

Мой совет: создайте одно ядро, которое будет распространяться на разных арендаторов, и сохраняйте локальную настраиваемую конфигурацию базы данных для каждого арендатора.(в структуре, похожей на app.ini)

то есть

/
    apps/
        tentant1/
            models/ <--- specific to the tenant
            libraries/ <--- specific to the tenant
            config/
                app.ini <--- specific configuration
        tentant2/
        /**/ etc
    core/
        models/ <--- system wide models
        libraries/ <--- system wide libraries (i.e. doctrine)
        core.ini <--- system wide configuration

Это может держать все организованно.Мы даже дошли до того, что на палатку у нас есть готовая структура ядра.Таким образом, возможность переопределить все аспекты «ядра», специфичные для арендатора.

3 голосов
/ 03 апреля 2012

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

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

Мы также обнаружили, что Doctrine 2 имеет некоторые довольно серьезные проблемы, если она не находится под полным контролем. Хотя это может быть побочным эффектом плохо структурированного кода и логики базы данных, я чувствую, что для ORM есть какая-то дыра в возможности добраться до точки, где он выдает фатальную ошибку, потому что использует слишком много памяти - особенно когда единственная причина, по которой он использует столько памяти, заключается в том, что он группирует запросы SQL, чтобы их можно было сделать «более эффективными».

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

1 голос
/ 08 марта 2017

Я думаю, что для управления мультитенантной мульти-базой данных с Symfony 2/3.Мы можем настроить auto_mapping: false для ORM доктрины.file: config.yml

doctrine:
    dbal:
        default_connection: master
        connections:
            master:
                driver:   pdo_mysql
                host:     '%master_database_host%'
                port:     '%master_database_port%'
                dbname:   '%master_database_name%'
                user:     '%master_database_user%'
                password: '%master_database_password%'
                charset:  UTF8
            tenant:
                driver:   pdo_mysql
                host:     '%tenant_database_host%'
                port:     '%tenant_database_port%'
                dbname:   '%tenant_database_name%'
                user:     '%tenant_database_user%'
                password: '%tenant_database_password%'
                charset:  UTF8

    orm:
        default_entity_manager: master
        auto_generate_proxy_classes: "%kernel.debug%"
        entity_managers:
            master:
                connection: master
                auto_mapping: false
                mappings:
                    AppBundle:
                        type: yml
                        dir: Resources/master/config/doctrine
            tenant:
                connection: tenant
                auto_mapping: false
                mappings:
                    AppBundle:
                        type: yml
                        dir: Resources/tenant/config/doctrine

После этого мы не можем обрабатывать соединение каждого арендатора путем переопределения информации о соединении в request_listener, например, в статье: http://mohdhallal.github.io/blog/2014/09/12/handling-multiple-entity-managers-in-doctrine-the-smart-way/ Я надеюсь, что эта практика может помочь кому-то работатьмультитенант

С уважением,

Вуонг Нгуен

1 голос
/ 05 февраля 2012

Почему бы не попробовать разные базы данных для каждого клиента, чтобы разделить данные и дать им уникальную точку входа в ваше приложение.Пример: http://client1.project.net, который с системой маршрутизации будет сопоставляться с базой данных client1. Недостаток этого: более сложные изменения базы данных, потому что все базы данных для каждого клиента должны быть обновлены.

1 голос
/ 29 сентября 2011

ЛУЧШИЙ строит разные уведомления по-разному.Пожалуйста, будьте более конкретны, задавайте вопросы.Одним из способов разработки мультитенантной системы является использование общего первичного ключа во всех таблицах для построения отношений.Тип и характер первичного ключа являются надежными в зависимости от проекта.

0 голосов
/ 30 марта 2013

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

Я запустилчерез эту ссылку, которая описывает способ сделать это для простого старого MySQL (не с Symfony / Doctrine).

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

Теперь это решение не совсем подходит для Symfony / Doctrine.Я смог пройти очень быстрый и элементарный тест этого бега раньше;Doctrine была в состоянии использовать представления базы данных очень хорошо (она могла вставлять, редактировать и удалять записи из представления без проблем).Однако, когда вы делаете такие вещи, как создание / обновление схемы, это не весело.Конечно, Symfony / Doctrine кажется достаточно расширяемым, поэтому я уверен, что есть способ автоматизировать его, но этот тип установки не поддерживается "из коробки".Доктрине нужно было бы сообщить обновить таблицы, всегда добавлять столбец для хранения имени пользователя к создаваемым им таблицам сущностей, обновлять представления и т. Д. (Вам также понадобится способ загрузить правильную конфигурацию базы данных в свойПриложение Symfony, в основном различные учетные записи в качестве сервера и других элементов, будут одинаковыми.) Но, если это удастся преодолеть, само ваше приложение может запустить этих нескольких арендаторов, полностью «не зная» того факта, что данные других людей находятся вбазы данных.

...