
Regularmente encontramos la base de datos Apache Cassandra y la necesidad de operarla dentro del marco de la infraestructura basada en Kubernetes. En este artículo, compartiremos nuestra visión de los pasos necesarios, los criterios y las soluciones existentes (incluida una descripción general de los operadores) para la migración de Cassandra a K8.
"Quién puede controlar a una mujer hará frente al estado"
Quien es Cassandra Es un sistema de almacenamiento distribuido diseñado para administrar grandes cantidades de datos mientras proporciona alta disponibilidad sin un solo punto de falla. El proyecto apenas necesita una larga introducción, por lo que solo daré las características principales de Cassandra, que serán relevantes en el contexto de un artículo específico:
- Cassandra está escrita en Java.
- La topología de Cassandra incluye varios niveles:
- Nodo: una instancia desplegada de Cassandra;
- Rack: un grupo de instancias de Cassandra, unidas por cualquier atributo, ubicadas en un centro de datos;
- Centro de datos: la totalidad de todos los grupos de instancias de Cassandra ubicadas en un centro de datos;
- Cluster: una colección de todos los centros de datos.
- Cassandra usa una dirección IP para identificar al host.
- Para la velocidad de las operaciones de lectura y escritura, Cassandra almacena parte de los datos en la RAM.
Ahora para el movimiento potencial real a Kubernetes.
Lista de verificación para la migración
Hablando de la migración de Cassandra a Kubernetes, esperamos que sea más conveniente administrarlo con la mudanza. ¿Qué se requerirá para esto, qué ayudará en esto?
1. Almacenamiento de datos
Como ya se especificó, parte de los datos que Cassanda almacena en la RAM, en
Memtable . Pero hay otra pieza de datos que se guarda en el disco, en forma de
SSTable . A estos datos se agrega la entidad
Log Log : registros de todas las transacciones que también se guardan en el disco.
Esquema de transacciones de escritura de CassandraEn Kubernetes, podemos usar PersistentVolume para almacenar datos. Gracias a mecanismos bien desarrollados, trabajar con datos en Kubernetes se vuelve más fácil cada año.
Para cada pod con Cassandra asignaremos nuestro volumen persistenteEs importante tener en cuenta que Cassandra implica la replicación de datos, ofreciendo mecanismos integrados para esto. Por lo tanto, si está creando un clúster Cassandra a partir de una gran cantidad de nodos, entonces no es necesario utilizar sistemas distribuidos como Ceph o GlusterFS para almacenar datos. En este caso, será lógico almacenar datos en el disco host utilizando discos
locales persistentes o montando
hostPath
.
Otra pregunta es si desea crear un entorno de desarrollo separado para cada rama de características. En este caso, el enfoque correcto sería generar un nodo Cassandra y almacenar los datos en almacenamiento distribuido, es decir Ceph y GlusterFS mencionados serán su opción. Luego, el desarrollador estará seguro de que no perderá los datos de prueba, incluso si se pierde uno de los nodos del clúster de Kuberntes.
2. Monitoreo
Una opción virtualmente no alternativa para el monitoreo en Kubernetes es Prometheus
(hablamos de esto en detalle en el informe correspondiente ) . ¿Cómo le va a Cassandra con los exportadores métricos de Prometheus? Y, ¿qué es aún más importante de alguna manera, con paneles adecuados para Grafana?
Un ejemplo de la aparición de gráficos en Grafana para CassandraSolo hay dos exportadores:
jmx_exporter y
cassandra_exporter .
Elegimos el primero para nosotros, porque:
- JMX Exporter está creciendo y desarrollándose, mientras que Cassandra Exporter no ha podido obtener el apoyo adecuado de la comunidad. Cassandra Exporter todavía no es compatible con la mayoría de las versiones de Cassandra.
- Puede ejecutarlo como javaagent agregando el
-javaagent:<plugin-dir-name>/cassandra-exporter.jar=--listen=:9180
. - Para él hay un tablero de instrumentos adecuado que es incompatible con Cassandra Exporter.
3. Selección de primitivas de Kubernetes
De acuerdo con la estructura anterior del grupo Cassandra, intentaremos traducir todo lo que se describe allí a la terminología de Kubernetes:
- Cassandra Node → Pod
- Cassandra Rack → StatefulSet
- Cassandra Datacenter → grupo de StatefulSets
- Cassandra Cluster → ???
Resulta que falta alguna entidad adicional para administrar todo el clúster Cassandra a la vez. Pero si algo no está allí, ¡podemos crearlo! Kubernetes tiene un motor de definición de recursos dedicado llamado
Definiciones de recursos personalizados .
Anuncio de recursos adicionales para registros y alertasPero el recurso personalizado por sí solo no significa nada: necesita un
controlador para ello. Puede que tenga que recurrir a la ayuda de un
operador de Kubernetes ...
4. Identificación de las vainas.
En el punto anterior, acordamos que un nodo Cassandra sería igual a un pod en Kubernetes. Pero las direcciones IP del pod serán diferentes cada vez. Y la identificación del nodo en Cassandra se produce precisamente en función de la dirección IP ... Resulta que después de cada eliminación del pod, el clúster Cassandra agregará un nuevo nodo.
Hay una salida, y ni siquiera una:
- Podemos mantener registros por identificadores de host (UUID que identifican de manera única instancias de Cassandra) o por direcciones IP y guardar todo esto en algunas estructuras / tablas. El método tiene dos desventajas principales:
- El riesgo de una condición de carrera cuando dos nodos caen a la vez. Después de la actualización, los nodos Cassandra irán simultáneamente a solicitar una dirección IP de la tabla y competirán por el mismo recurso.
- Si el nodo Cassandra ha perdido sus datos, ya no podremos identificarlo.
- La segunda solución parece un pequeño truco, pero no obstante: podemos crear un Servicio con ClusterIP para cada nodo de Cassandra. Problemas con esta implementación:
- Si hay muchos nodos en un clúster Cassandra, tendremos que crear muchos Servicios.
- La característica ClusterIP se implementa a través de iptables. Esto puede ser un problema si el clúster Cassandra tiene muchos (¿1000 ... o incluso 100?) Nodos. Aunque el equilibrio basado en IPVS puede resolver este problema.
- La tercera solución es utilizar una red de nodos para los nodos de Cassandra en lugar de una red de pod dedicada al habilitar
hostNetwork: true
configuración hostNetwork: true
. Este método impone ciertas restricciones:
- Para reemplazar los nodos. Es necesario que el nuevo host tenga la misma dirección IP que la anterior (en nubes como AWS, GCP, esto es casi imposible de hacer);
- Usando la red de nodos de clúster, comenzamos a competir por los recursos de la red. Por lo tanto, poner en un nodo de clúster más de un pod con Cassandra será problemático.
5. Copias de seguridad
Queremos mantener la versión completa de los datos para un nodo Cassandra en un horario. Kubernetes ofrece una oportunidad conveniente usando
CronJob , pero aquí Cassandra inserta los palos en las ruedas.
Déjame recordarte que parte de los datos que Cassandra almacena en la memoria. Para realizar una copia de seguridad completa, debe transferir datos de la memoria (
Memtables ) al disco (
SSTables ). En este punto, el nodo Cassandra deja de aceptar conexiones, cerrándose completamente del clúster.
Después de eso, se elimina una copia de seguridad (
instantánea ) y se
guarda el esquema (
espacio de teclas ). Y luego resulta que solo una copia de seguridad no nos da nada: debe guardar los identificadores de datos de los que fue responsable el nodo Cassandra; estos son tokens especiales.
Distribución de tokens para identificar qué datos son responsables de los nodos CassandraPuede encontrar un script de ejemplo para eliminar Cassandra de Google en Kubernetes en
este enlace . El único punto que el script no tiene en cuenta es volcar datos en el nodo antes de eliminar la instantánea. Es decir, la copia de seguridad se realiza no para el estado actual, sino para el estado un poco antes. Pero esto ayuda a no dejar el nodo sin trabajo, lo que parece muy lógico.
set -eu if [[ -z "$1" ]]; then info "Please provide a keyspace" exit 1 fi KEYSPACE="$1" result=$(nodetool snapshot "${KEYSPACE}") if [[ $? -ne 0 ]]; then echo "Error while making snapshot" exit 1 fi timestamp=$(echo "$result" | awk '/Snapshot directory: / { print $3 }') mkdir -p /tmp/backup for path in $(find "/var/lib/cassandra/data/${KEYSPACE}" -name $timestamp); do table=$(echo "${path}" | awk -F "[/-]" '{print $7}') mkdir /tmp/backup/$table mv $path /tmp/backup/$table done tar -zcf /tmp/backup.tar.gz -C /tmp/backup . nodetool clearsnapshot "${KEYSPACE}"
Ejemplo de script bash para eliminar la copia de seguridad de un solo nodo CassandraSoluciones preparadas para Cassandra en Kubernetes
¿Qué están utilizando actualmente para implementar Cassandra en Kubernetes, y cuál de estos es el más adecuado para los requisitos dados?
1. Soluciones StatefulSet o Helm Chart
Usar los StatefulSets básicos para iniciar un clúster Cassandra es una buena opción. Utilizando el gráfico Helm y las plantillas Go, puede proporcionar al usuario una interfaz flexible para implementar Cassandra.
Por lo general, esto funciona bien ... hasta que sucede algo inesperado, por ejemplo, un nodo se cae. Las herramientas estándar de Kubernetes simplemente no pueden tener en cuenta todas las características anteriores. Además, este enfoque es muy limitado en cuanto a cómo se puede expandir para un uso más complejo: reemplazo de nodos, copia de seguridad, restauración, monitoreo, etc.
Representantes:
Ambas tablas son igualmente buenas, pero son propensas a los problemas descritos anteriormente.
2. Soluciones basadas en el operador Kubernetes
Dichas opciones son más interesantes porque brindan amplias capacidades de administración de clúster. Para diseñar una declaración Cassandra, como cualquier otra base de datos, un buen patrón se parece a Sidecar <-> Controller <-> CRD:
Diagrama de gestión de nodos en una declaración Cassandra diseñada correctamenteConsidere los operadores existentes.
1. Cassandra-operator por instaclustr
- Github
- Voluntad: Alfa
- Licencia: Apache 2.0
- Implementado en: Java
Este es de hecho un proyecto muy prometedor y de rápido desarrollo de una compañía que ofrece implementaciones administradas por Cassandra. Como se describió anteriormente, utiliza un contenedor de sidecar que acepta comandos a través de HTTP. Está escrito en Java, por lo que a veces carece de la funcionalidad de biblioteca cliente-go más avanzada. Además, el operador no admite diferentes bastidores para un centro de datos.
Pero el operador tiene ventajas tales como soporte de monitoreo, administración de clústeres de alto nivel utilizando CRD e incluso documentación sobre cómo eliminar copias de seguridad.
2. Navigator de Jetstack
- Github
- Voluntad: Alfa
- Licencia: Apache 2.0
- Implementado en: Golang
Una declaración para implementar DB-as-a-Service. Actualmente es compatible con dos bases de datos: Elasticsearch y Cassandra. Tiene soluciones tan interesantes como el control de acceso a la base de datos a través de RBAC (para esto, se plantea su propio navegador-apiserver separado). Un proyecto interesante, que merecería una mirada más cercana, pero el último compromiso se realizó hace un año y medio, lo que claramente reduce su potencial.
3. Cassandra-operador de vgkowski
- Github
- Voluntad: Alfa
- Licencia: Apache 2.0
- Implementado en: Golang
No lo consideraron "en serio", ya que el último compromiso con el repositorio fue hace más de un año. El desarrollo del operador se abandona: la última versión de Kubernetes, declarada como compatible, es 1.9.
4. Cassandra-operador de Rook
- Github
- Voluntad: Alfa
- Licencia: Apache 2.0
- Implementado en: Golang
Un operador cuyo desarrollo no va tan rápido como nos gustaría. Tiene una estructura CRD bien pensada para administrar el clúster, resuelve el problema de identificar nodos usando el Servicio con ClusterIP (el mismo "pirateo") ... pero por ahora eso es todo. No hay monitoreo y copias de seguridad fuera de la caja en este momento (por cierto, comenzamos
a monitorearnos a
nosotros mismos ). Un punto interesante es que con este operador también puede implementar ScyllaDB.
NB: Utilizamos uno de nuestros operadores con modificaciones menores en uno de nuestros proyectos. No hubo problemas en el trabajo del operador durante toda la operación (~ 4 meses de operación).5. CassKop de Orange
- Github
- Voluntad: Alfa
- Licencia: Apache 2.0
- Implementado en: Golang
El operador más joven de la lista: la primera confirmación se realizó el 23 de mayo de 2019. Ya tiene en su arsenal una gran cantidad de características de nuestra lista, más detalles de los cuales se pueden encontrar en el repositorio del proyecto. El operador se basa en el popular operator-sdk. Soporta monitoreo fuera de la caja. La principal diferencia con respecto a otros operadores es el uso del
complemento CassKop , implementado en Python y utilizado para la comunicación entre los nodos de Cassandra.
Conclusiones
El número de enfoques y posibles opciones para llevar a Cassandra a Kubernetes habla por sí mismo: el tema está en demanda.
En esta etapa, puede probar uno de los anteriores bajo su propio riesgo y riesgo: ninguno de los desarrolladores garantiza el 100% del trabajo de su solución en el entorno de producción. Pero ahora, muchos productos parecen prometedores para intentar usarlos en stands de desarrollo.
¡Creo que en el futuro esta mujer en el barco tendrá que irse!
PS
Lea también en nuestro blog: