# Implementando Multi-Tenencia en MyScale
A medida que los LLMs son cada vez más reconocidos y adoptados, más desarrolladores están explorando la pila CVP (ChatGPT, base de datos vectorial, prompt) para construir aplicaciones para varios usuarios o grupos de usuarios. Es crucial habilitar el soporte de multi-tenencia en las bases de datos vectoriales para cumplir con este requisito. Esta guía te ayudará a comprender e implementar la multi-tenencia en MyScale.
# Comprendiendo la Multi-Tenencia
La multi-tenencia en una base de datos vectorial (aplicación) se refiere a la capacidad de la base de datos para atender a múltiples inquilinos o usuarios (o grupos de usuarios) manteniendo sus datos lógicamente aislados entre sí. Los datos de cada inquilino se almacenan y gestionan por separado en una arquitectura multi-inquilino, aunque comparten la misma infraestructura física y recursos.
La implementación de la multi-tenencia en aplicaciones de bases de datos vectoriales debe abordar cuatro requisitos principales:
- Neutralidad de rendimiento: Un concepto que enfatiza mantener un rendimiento consistente y comparable en todas las cargas de trabajo multi-inquilino y de un solo usuario, incluyendo todas las operaciones CRUD (Crear, Leer, Actualizar, Eliminar).
- Aislamiento de datos: Los datos pertenecientes a cada inquilino deben almacenarse por separado.
- Escalabilidad: La aplicación debe admitir un gran número de inquilinos.
- Facilidad de incorporación y desincorporación: Agregar o eliminar un inquilino no debe afectar a otros inquilinos.
# Estrategias para Implementar la Multi-Tenencia
La implementación de la multi-tenencia en MyScale requiere una planificación y consideración cuidadosas para garantizar el aislamiento de datos, la seguridad y el rendimiento.
Aquí tienes algunas estrategias y mejores prácticas para implementar la multi-tenencia de manera efectiva:
# Multi-Tenencia Orientada a Tablas
En MyScale, cada tabla se almacena por separado, lo que facilita la creación de múltiples tablas dentro de un solo clúster. Para cada inquilino, puedes crear una tabla dedicada. Por ejemplo, esta declaración SQL crea una tabla para un inquilino de chatbot:
CREATE TABLE db.message_chatbot1
(
user_id FixedString(16),
message_id FixedString(16),
timestamp DateTime,
message_embedding Array(Float32),
CONSTRAINT check_length CHECK length(message_embedding) = 768
) ENGINE = MergeTree
ORDER BY message_id
La búsqueda vectorial para esta estrategia es similar a la de un solo inquilino. Puedes eliminar un inquilino eliminando su tabla, lo cual no afectará a otros inquilinos. Sin embargo, esta estrategia puede llevar al desperdicio de recursos y no es adecuada para la multi-tenencia a gran escala. Por lo tanto, no se recomienda tener más de 100 tablas en un clúster de MyScale con un tamaño de pod x1.
Esta estrategia también permite el Control de Acceso Basado en Roles (RBAC), lo que permite un control de acceso detallado asignando diferentes usuarios y roles a cada tabla.
# Multi-Tenencia Orientada a Filtrado de Metadatos
La multi-tenencia orientada a filtrado de metadatos es un enfoque para implementar la multi-tenencia en un sistema de bases de datos donde los datos de múltiples inquilinos se almacenan dentro de las mismas tablas. El acceso a los datos se controla y aísla en función de metadatos o atributos asociados a cada registro de datos, lo que permite un almacenamiento eficiente al tiempo que proporciona un sólido aislamiento y seguridad de los datos.
En la práctica, la multi-tenencia orientada a filtrado de metadatos utiliza el campo de inquilino como filtro y se puede lograr de tres formas: basada en clave de partición, basada en clave primaria o una combinación de ambas.
# Multi-Tenencia Basada en Clave de Partición
El aislamiento de datos se logra asignando una partición única a cada inquilino. La siguiente declaración SQL describe la creación de una tabla particionada por el ID de usuario, donde cada usuario corresponde a un inquilino (partición):
CREATE TABLE db.message_app
(
user_id FixedString(16),
message_id FixedString(16),
timestamp DateTime,
message_embedding Array(Float32),
CONSTRAINT check_length CHECK length(message_embedding) = 768
) ENGINE = MergeTree
ORDER BY message_id
PARTITION BY user_id
Al ejecutar una búsqueda vectorial, utiliza el campo de inquilino como filtro para localizar la partición adecuada, como en la siguiente declaración SQL:
SELECT message_id, distance(data, [...]) AS dist
FROM db.message_app
WHERE user_id = 'xxxxxxxxxxxxxxxx'
ORDER BY dist LIMIT 10
Además, puedes eliminar fácilmente una partición (inquilino) con este comando:
ALTER TABLE db.message_app DROP PARTITION 'xxxxxxxxxxxxxxxx'
TIP
Para un rendimiento óptimo de INSERT
y consultas, se recomienda mantener el número total de particiones en una tabla por debajo de 100 para un clúster de MyScale con un tamaño de pod x1.
# Multi-Tenencia Basada en Clave Primaria
El campo de inquilino es la clave primaria en esta estrategia, lo que acelera la recuperación de datos del inquilino.
Esta estrategia no limita el número de inquilinos. Los datos de todos los diferentes inquilinos se almacenan en una sola partición. Por ejemplo, la siguiente declaración SQL describe cómo crear una tabla tratando a cada usuario como un inquilino:
CREATE TABLE db.message_app
(
user_id FixedString(16),
timestamp DateTime,
message_id FixedString(16),
message_embedding Array(Float32),
CONSTRAINT check_length CHECK length(message_embedding) = 768
) ENGINE = MergeTree
ORDER BY (user_id, message_id)
Una búsqueda vectorial en esta estrategia es similar a la estrategia basada en clave de partición.
Sin embargo, como muestra la siguiente declaración SQL, eliminar un inquilino es más lento y requiere una instrucción DELETE FROM
:
DELETE FROM TABLE db.message_app WHERE user_id = 'xxxxxxxxxxxxxxxx'
# Multi-Tenencia Basada en Clave de Partición + Clave Primaria
Puedes equilibrar el aislamiento de recursos y la escalabilidad de inquilinos combinando las estrategias de multi-tenencia basadas en clave de partición y clave primaria. Este método almacena datos de varios inquilinos en la misma partición, lo que permite una multi-tenencia a gran escala manteniendo un aislamiento moderado.
Por ejemplo, la siguiente declaración SQL destaca cómo crear una tabla distribuyendo los datos de los inquilinos en diez particiones:
CREATE TABLE db.message_app
(
user_id FixedString(16),
timestamp DateTime,
message_id FixedString(16),
message_embedding Array(Float32),
CONSTRAINT check_length CHECK length(message_embedding) = 768
) ENGINE = MergeTree
ORDER BY (user_id, message_id)
PARTITION BY sipHash64(user_id) % 10
La ejecución de búsquedas vectoriales y la eliminación de inquilinos es igual que en la estrategia basada en clave primaria. Sin embargo, el rendimiento de inserción puede ser más lento, especialmente al manejar múltiples particiones dentro de un solo bloque de inserción. Por lo tanto, la mejor práctica para esta estrategia es insertar datos con la misma partición en un solo bloque.
# En Conclusión...
Aquí tienes un resumen de las estrategias de multi-tenencia que recomendamos y utilizamos:
Modelo de Multi-Tenencia | Sobrecarga de Rendimiento | Nivel de Aislamiento | Escala de Inquilinos | Facilidad de Incorporación/Desincorporación |
---|---|---|---|---|
Orientada a Tablas | Alta | Fuerte | Media | Alta |
Basada en Clave de Partición | Alta | Media | Media | Alta |
Basada en Clave Primaria | Baja | Débil | Grande | Media |
Basada en Clave de Partición + Clave Primaria | Media | Débil | Grande | Media |