лучшая стратегия базы данных для клиентского сайта (Ruby on Rails) - PullRequest
5 голосов
/ 08 декабря 2008

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

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

Все остальное точно так же, или должно быть ... Теперь, когда у меня развернуто около 20 таких сайтов, становится все труднее держать их все в одном и том же коде. И эта проблема только усугубится.

Я думаю, что мне следует провести рефакторинг этой системы, чтобы я мог использовать один набор развернутого кода ruby, динамически выбирать правильную базу данных и т. Д. По URL-адресу входящего запроса.

Кажется, что есть два способа обработки базы данных:

  • с использованием нескольких баз данных, по одной для каждого клиента
  • с использованием одной базы данных, с полем client_id в каждой таблице и дополнительной таблицей 'client'

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

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

С другой стороны, у каждого клиента будет 20–50 тыс. Элементов в таблице «элементы». Меня беспокоит скорость полнотекстового поиска, когда в таблице предметов содержится полмиллиона или миллион предметов. Я подозреваю, что даже при наличии индекса в поле client_id поиск будет быстрее, если элементы будут разделены на разные клиентские базы данных.

Если у кого-то есть осознанное мнение о наилучшем способе решения этой проблемы, я бы очень хотел услышать его. Большое спасибо заранее ...

- Джон

Ответы [ 3 ]

4 голосов
/ 09 декабря 2008

Спасибо за замечательные комментарии. Я решил пойти с подходом нескольких баз данных. Это самый простой путь для меня, поскольку мне не нужно переделывать все приложение.

Что я собираюсь сделать, это добавить before_filter в application_controller, чтобы он применялся ко всем контроллерам ... примерно так:

before_filter :client_db         # switch to client's db

Затем в application_controller.rb я добавлю что-то вроде этого:

 def client_db
    @client = Client.find(params[:client_id]) 
    spec = Client.configurations[RAILS_ENV] 
    new_spec = spec.clone 
    new_spec["database"] = @client.database_name
    ActiveRecord::Base.establish_connection(new_spec) 
  end

Затем URL, например example.com?client_id=12345, выберет правильную базу данных.

Поскольку я использую Apache в качестве прокси-сервера перед Mongrel, Apache добавит правильный client_id ко всем запросам на основе URL-адреса веб-сайта клиента. Таким образом, client_id на самом деле не будет частью URL, который видят пользователи. Он будет передаваться только между Apache и Mongrel. Я не уверен, правильно ли я объясняю это, но это работает и делает вещи чистыми и простыми.

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

Кто-нибудь видит какие-либо проблемы с этим подходом?

- Джон

2 голосов
/ 08 декабря 2008

Существуют преимущества использования отдельных БД (включая те, которые вы уже перечислили):

  • Полнотекстовый поиск замедляется (в зависимости от возможностей вашего сервера), когда у вас есть миллионы больших текстовых объектов для поиска.
  • Разделение БД обеспечит более быструю скорость индексации таблицы для каждого клиента. В частности, это может расстроить некоторых из ваших ранее усыновленных клиентов, если вы возьмете нового крупного клиента. Внезапно их приложения пострадают (для них) без видимой причины. Опять же, если вы остаетесь без возможностей вашего оборудования, это может не быть проблемой.
  • Если вы когда-нибудь отбросите клиента, было бы немного проще просто упаковать их БД, чем удалять все связанные с ними строки с помощью client_id. И в равной степени чист, чтобы восстановить их, если они передумают позже.
  • Если какие-либо клиенты запрашивают дополнительные функциональные возможности, за которые они готовы платить, вы можете разветвить их структуру БД, не изменяя чужие.
  • Для пессимистов: меньше шансов, что вы случайно уничтожите все данные клиента по ошибке, а не только данные одного клиента. ;)

С учетом всего сказанного, решение для единой БД, вероятно, лучше подойдет:

  • Возможности вашего сервера БД делают большую единую таблицу не проблемной.
  • Базы данных вашего клиента гарантированно остаются идентичными.
  • Вы не беспокоитесь о том, что можете хранить все данные по частям для целей архивирования / восстановления или в случае аварии.
1 голос
/ 08 декабря 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...