Indexación de Cassandra: Lo Bueno, lo Malo y lo Feo

Dentro de NoSQL, las operaciones de indexación, obtención y búsqueda de información están íntimamente vinculadas a los mecanismos de almacenamiento físico. Es importante recordar que las filas se almacenan entre hosts, pero una sola fila se almacena en un único host. (con réplicas) Las familias de columnas se almacenan en orden, lo que hace que la consulta de un conjunto de columnas sea eficiente (siempre que esté abarcando filas).

La Mala : Particionamiento

Una de las cosas difíciles a las que acostumbrarse al principio es que sin ningún índice, las consultas que abarcan filas pueden (muy) ser malas. Sin embargo, pensar en nuestro modelo de almacenamiento no es sorprendente. La estrategia que utiliza Cassandra para distribuir las filas entre los hosts se denomina Particionamiento.

Partición es el acto de dividir el rango de rowkeys la asignación en el «token ring», que también asigna la responsabilidad de un segmento (es decir, la partición) de la rowkey rango a cada host. Probablemente haya visto esto cuando inicializó su clúster con un «token». El token le da al host una ubicación a lo largo del anillo de tokens, que asigna la responsabilidad de una sección del rango de tokens. El particionamiento es el acto de asignar la clave de fila al rango de tokens.

Hay dos particionadores principales: Aleatorio y Preservación de Orden. Tienen un nombre apropiado. El RandomPartitioner convierte las teclas de fila en tokens. Con RandomPartitioner, el token es un hash de la rowkey. Esto hace un buen trabajo al distribuir uniformemente sus datos a través de un conjunto de nodos, pero hace que consultar un rango del espacio de las teclas de fila sea increíblemente difícil. De solo un valor de «llave de fila inicial» y un valor de «llave de fila final», Cassandra no puede determinar qué rango del espacio de token necesita. Esencialmente necesita realizar un » escaneo de tabla «para responder a la consulta, y un» escaneo de tabla » en Cassandra es malo porque necesita ir a cada máquina (lo más probable es que TODAS las máquinas si tiene una buena función hash) para responder a la consulta.

Ahora, con el gran costo de la distribución uniforme de datos, puede emplear OrderPreservingPartitioner (OPP). No estoy de acuerdo con OPP. El OPP conserva el orden al traducir las teclas de fila en tokens. Ahora, dado un valor de clave de fila inicial y un valor de clave de fila final, Cassandra * puede * determinar exactamente qué hosts tienen los datos que está buscando. Calcula el valor inicial a un token, el valor final a un token, y simplemente selecciona y devuelve todo lo intermedio. PERO, al preservar el orden, a menos que las teclas de fila se distribuyan uniformemente por todo el espacio, los tokens tampoco lo estarán y obtendrá un clúster desequilibrado, lo que aumenta en gran medida el costo de configuración y administración del clúster. (no vale la pena)

Lo bueno : Índices secundarios

Cassandra proporciona un mecanismo de indexación nativo en Índices Secundarios. Los índices secundarios funcionan fuera de los valores de las columnas. Se declara un índice secundario en una familia de columnas. Datastax tiene buena documentación sobre el uso. Bajo el capó, Cassandra mantiene una» familia de columnas ocultas » como el índice. (Vea la presentación de Ed Anuff para detalles específicos) Dado que Cassandra no mantiene la información del valor de columna en ningún nodo, y los índices secundarios están en el valor de las columnas (en lugar de las teclas de fila), aún debe enviarse una consulta a todos los nodos. Además, no se recomiendan índices secundarios para conjuntos de alta cardinalidad. Todavía no he mirado, pero asumo que esto se debe al modelo de datos utilizado dentro de la «familia de columnas ocultas». Si la familia de columnas ocultas almacena una fila por valor único (con teclas de fila como columnas), significaría escanear las filas para determinar si están dentro del rango de la consulta.
De la presentación de Ed:

  • No se recomienda para valores de cardinalidad altos(es decir, marcas de tiempo,fechas de nacimiento, palabras clave, etc.)
  • Requiere al menos una comparación de igualdad en una consulta
  • Sin clasificar: los resultados están en orden de tokens, no en orden de valor de consulta
  • Limitado a buscar en tipos de datos, Cassandra entiende de forma nativa

Con todo lo dicho, los índices secundarios funcionan fuera de la caja y hemos tenido un buen éxito usándolos en valores simples.

Lo feo: Hágalo usted mismo ( Bricolaje) / Filas anchas

Ahora, la belleza está en el ojo del espectador. Una de las cosas hermosas de NoSQL es la simplicidad. Las construcciones son simples: Espacios de claves, Familias de Columnas, Filas y Columnas. Sin embargo, mantenerlo simple significa que a veces necesita tomar las cosas en sus propias manos.

Este es el caso de los índices de filas anchas. Utilizando el modelo de almacenamiento de Cassandra, es fácil crear sus propios índices donde cada clave de fila se convierte en una columna en el índice. Esto a veces es difícil de entender, pero imaginemos que tenemos un caso en el que queremos seleccionar a todos los usuarios en un código postal. La familia de columnas de usuarios principales está marcada en userid, el código postal es una columna en cada fila de usuarios. Podríamos usar índices secundarios, pero hay bastantes códigos postales. En su lugar, podríamos mantener una familia de columnas con una sola fila llamada «idx_zipcode». Entonces podríamos escribir columnas en esta fila de la forma «zipcode_userid». Dado que las columnas se almacenan en orden ordenado, es rápido consultar todas las columnas que comienzan con «18964» (por ejemplo, podríamos usar 18964_ y 18964_ZZZZZZ como valores de inicio y fin).

Una desventaja obvia de este enfoque es que las filas son autónomas en un host. (de nuevo a excepción de las réplicas) Esto significa que todas las consultas van a golpear un solo nodo. Aún no he encontrado una buena respuesta para esto.

Además, y en mi humilde opinión, la parte más fea de la indexación de filas anchas de bricolaje es desde la perspectiva del cliente. En nuestra implementación, hemos hecho todo lo posible para ser independientes del lenguaje en el lado del cliente, permitiendo a las personas elegir la mejor herramienta para el trabajo para interactuar con los datos en Cassandra. Con esa mentalidad, los índices de bricolaje presentan algunos problemas. Las filas anchas a menudo usan claves compuestas(imagínese que tuviera un idx_state_zip, que le permitiría consultar por estado y luego comprimir). Aunque hay soporte «nativo» para claves compuestas, todas las bibliotecas cliente implementan su propia versión de ellas (Hector, Astyanax y Thrift). Esto significa que el cliente que necesita consultar datos necesita tener la lógica agregada para consultar primero el índice y, además, todos los clientes necesitan construir la clave compuesta de la misma manera.

Mejorándolo…

Por esta misma razón, hemos decidido lanzar dos proyectos de código abierto que ayudan a llevar esta lógica al lado del servidor. El primer proyecto es Cassandra-Triggers. Esto le permite adjuntar actividades asincrónicas a las escrituras en Cassandra. (una de estas actividades podría ser la indexación) También hemos lanzado Cassandra-Indexing. Esto está recién salido de la imprenta y todavía está en su infancia (por ejemplo, solo admite tipos UT8 en el índice), pero la intención es proporcionar un mecanismo genérico del lado del servidor que indexe los datos tal como se escribieron a Cassandra. Empleando la misma técnica del lado del servidor que usamos en Cassandra-Indexing, simplemente configura las columnas que desea indexar, y el código AOP hace el resto mientras escribe en el CF de destino. Como siempre, preguntas, comentarios y pensamientos son bienvenidos. (especialmente si estoy fuera de la base en algún lugar)

Deja una respuesta

Tu dirección de correo electrónico no será publicada.