2008-12-08 11 views
5

He creado un buen sistema de sitio web que atiende las necesidades de un pequeño nicho de mercado. He estado vendiendo estos sitios web durante el último año mediante la implementación de copias del software usando Capistrano en mi servidor web.mejor estrategia de base de datos para un sitio web basado en el cliente (Ruby on Rails)

Se me ocurre que la única diferencia en estos sitios web es la base de datos, el archivo CSS y un pequeño conjunto de imágenes utilizadas para el diseño gráfico del cliente individual.

Todo lo demás es exactamente igual, o debería ser ... Ahora que tengo alrededor de 20 de estos sitios implementados, es una molestia mantenerlos actualizados con el mismo código. Y este problema solo empeorará.

Estoy pensando que debería refactorizar este sistema, de modo que pueda usar un conjunto de código de ruby ​​desplegado, seleccionando dinámicamente la base de datos correcta, etc., por la URL de la solicitud entrante.

Parece que hay dos maneras de manejar la base de datos:

  • el uso de múltiples bases de datos, uno para cada cliente
  • utilizando una base de datos, con un campo client_id en cada mesa, y un cliente extra' 'tabla

El enfoque de la base de datos múltiple sería el más simple para mí en este momento, ya que no tendría que refactorizar cada modelo en mi aplicación para agregar el campo client_id a todas las operaciones CRUD.

Sin embargo, sería una molestia tener que ejecutar 'rake db: migrate' para decenas o cientos de bases de datos diferentes, cada vez que quiera migrar la (s) base (s) de datos. Obviamente, esto podría hacerse mediante un script, pero no huele muy bien.

Por otro lado, cada cliente tendrá 20K-50K elementos en una tabla de 'artículos'. Me preocupa la velocidad de las búsquedas de texto completo cuando la tabla de elementos tiene medio millón o millones de elementos. Incluso con un índice en el campo client_id, sospecho que las búsquedas serían más rápidas si los artículos se separaran en diferentes bases de datos de clientes.

Si alguien tiene una opinión informada sobre la mejor manera de abordar este problema, me gustaría mucho escucharlo. Gracias de antemano ...

- John

Respuesta

2

Hay ventajas de utilizar por separado DB (incluyendo los que ya en la lista):

  • búsquedas Texto completo llegarán a ser lenta (dependiendo de las capacidades de su servidor) cuando tienes millones de grandes blobs de texto para buscar.
  • La separación de los DB mantendrá la velocidad de indexación de su tabla más rápida para cada cliente. En particular, podría molestar a algunos de sus clientes adoptivos anteriores si acepta un cliente nuevo y grande. De repente, sus aplicaciones sufrirán por (para ellos) una razón aparente. De nuevo, si permanece bajo la capacidad de su hardware, esto podría no ser un problema.
  • Si alguna vez deja caer un cliente, sería marginalmente más limpio empacar su DB que eliminar todas sus filas asociadas por client_id. E igualmente limpios para restaurarlos si cambian de opinión más tarde.
  • Si algún cliente solicita funcionalidades adicionales que están dispuestas a pagar, puede bifurcar su estructura de base de datos sin modificar la de ningún otro.
  • Para los pesimistas: hay menos posibilidades de que destruya accidentalmente todos los datos del cliente por un error en lugar de solo los datos de un cliente. ;)

dicho todo esto, la única solución DB es probablemente mejor dado: capacidades

  • su servidor de base de datos hace que la gran mesa sola no sea un problema.
  • Se garantiza que las bases de datos de sus clientes serán idénticas.
  • No le preocupa ser capaz de mantener los datos de todos compartimentados para fines de archivo/restauración o en caso de desastre.
1

Me gustaría ir a una base de datos única, usando ID de cliente: debería poder hacer la refactorización menos dolorosa utilizando algún tipo de modelo base y un alcance con nombre para extender las acciones al ID de ese cliente.

Puede utilizar una biblioteca de indización, como Hurón, o algo similar, para tratar el problema de la lentitud de las búsquedas de texto completo. De todos modos, eso será un problema una vez que la base de datos de un solo cliente sea grande, por lo que es posible que deba implementarla de cualquier manera.

4

Gracias por los buenos comentarios. He decidido ir con el enfoque de base de datos múltiple. Esta es la ruta más fácil para mí, ya que no tengo que volver a procesar toda la aplicación.

Lo que voy a hacer es añadir un before_filter en application_controller, por lo que se aplica a todos los controladores ... algo como esto:

before_filter :client_db   # switch to client's db

Luego, en application_controller.rb, incluiré algo como esto:

 
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 

Entonces, una URL como example.com?client_id=12345 seleccionará la base de datos correcta.

Dado que estoy usando Apache como un proxy frente a Mongrel, Apache agregará el client_id correcto a todas las solicitudes, basado en la URL del sitio web del cliente. Entonces, client_id no será parte de la URL que ven los usuarios. Solo se pasará entre Apache y Mongrel. No estoy seguro si estoy explicando esto correctamente, pero funciona y mantiene las cosas limpias y simples.

Si decido que necesito usar una única base de datos en el futuro, entonces puedo refactorizar todo el código. Por el momento, este parece ser el enfoque más simple.

¿Alguien tiene algún problema con este enfoque?

- John

+0

Lo enrutaría de manera diferente, pero así soy yo. Me gusta, ": user_id /: controller /: action /: id" en routes.rb; de esta manera, siempre tendrá la ID del cliente en las direcciones URL sin algo que el cliente pueda eliminar (como el bit "cliente ="). –

Cuestiones relacionadas