Uno de los grandes retos al que nos podemos enfrentar cuando una aplicación crece, es la expansión a otras regiones, implicando nuevos retos tecnológicos a nivel de infraestructura. El problema es que si tu infraestructura está en una región y tus clientes acceden a la aplicación desde otra, la latencia se incrementa cuanto mayor sea la distancia… Esto hace que se incremente a su vez el tiempo de carga y merme la “experiencia” de uso de dicha aplicación. Cuando usas clouds públicos como AWS, Azure o Google Cloud realmente no es muy complejo pues los mismos te dan las herramientas necesarias para lograrlo, en cambio cuando tienes una infraestructura hidrida o simplemente cuentas con servidores propios debes crear dicha infraestructura
Para ello muchas empresas optan por dos opciones principales a la hora de expandir su aplicación por el mundo:
- Colocar CDNs y nodos en otras regiones los cuales hacen que el contenido cargue mucho más rápido, que si tienen que conectarse a la infraestructura de la región de origen. El problema de esto reside en que al final, si tienen que interaccionar con una base de datos muy frecuentemente el tiempo de carga sigue siendo bastante lento, ya que las consultas tienen que atravesar diversas regiones.
- Para solventar el problema anterior con las bases de datos, lo que se suele hacer es desplegar otra infraestructura nueva en la nueva región y «forzar» a los clientes de esa región que utilicen esa infraestructura, por ejemplo:
- Si resides en Cuba, utilizarás el nombre de dominio aplicación.cu que corresponderá a la infraestructura de Cuba.
- Si resides en España, utilizarás el nombre de dominio aplicación.es que corresponderá a la infraestructura de España.
Los grandes inconvenientes en estos casos podrían ser:
- Mantenimiento y operatividad en ambas regiones; al tener varias infraestructuras el coste de mantener actualizada ambas es mayor, así como toda la monitorización y gestión de las mismas para que funcionen en “paralelo”.
- En caso de que un cliente se moviese de región por trabajo volvería a tener el problema de la latencia y mala experiencia de uso.
Para ello existen muchas soluciones en el mercado, pero a mi parecer me centraré en una que me ha dado muy buen resultado y es la combinación de varias tecnologías como:
Percona XtraDB Cluster como solución principal junto con ProxySQL + Kubernetes + Percona XtraDB + Percona Management & Monitoring como complementos para hacer perfecta la operatividad.
Es por ello que la solución planteada sería la siguiente:
- Utilizar Percona XtraDB Cluster como solución principal para crear un cluster de bases de datos de tipo maestro-maestro, consiguiendo replicar la información entre todas ellas en tiempo real. Haciendo todos los nodos primarios tanto de lectura como de escritura.
- Utilizar ProxySQL para las peticiones y distribución de las consultas SQL, este software nos permite una escalabilidad inmensa si se utiliza con Kubernetes llegando a soportar más de 100k peticiones, pudiendo clasificar las consultas para mandarlas a un servidor u otro, alta disponibilidad y con un firewall adicional de acceso.
- Utilizar Percona XtraDB Backup como solución a realizar backups en cada uno de los nodos, ya que esta solución permite el no bloquear las bases de datos en producción y lo hace óptimo para poder automatizar backups sobre la misma.
- Por último para una correcta monitorización de toda esta nueva infraestructura haremos uso de PMM, el cual consiste en disponer de unos servicios que se conectan a cada uno de los clusters de Percona y podemos representar lo que está sucediendo utilizando Grafana.
Este sería el esquema de arquitectura empleado para la solución:
Para preparar este entorno sugiero usar k3s ya a su poco consumo y fácil despliege, supongamos que tenemos cuatro servidores que queremos usar para nuestras implementaciones de Kubernetes: un nodo master y tres nodos workers. En mi caso:
beast-node1-ubuntu (master)
beast-node2-ubuntu
beast-node3-ubuntu
beast-node4-ubuntu
En el master ejecutamos:
curl -sfL https://get.k3s.io | sh -
Para el paso dos, necesitamos preparar un script y necesitamos dos parámetros: la dirección IP del master y el token del mismo. Encontrar el token es probablemente la parte más complicada de esta configuración y está almacenado en el archivo /var/lib/rancher/k3s/server/node-token.
Teniendo estos parámetros, el script para otros nodos es:
k3s_url="https://10.30.2.34:6443" k3s_token="K109a7b255d0cf88e75f9dcb6b944a74dbca7a949ebd7924ec3f6135eeadd6624e9::server:5bfa3b7e679b23c55c81c198cc282543" curl -sfL https://get.k3s.io | K3S_URL=${k3s_url} K3S_TOKEN=${k3s_token} sh -
Luego de ejecutar este script en otros nodos ya tendremos nuestro Kubernetes ejecutándose:
kubectl get nodes NAME STATUS ROLES AGE VERSION beast-node4-ubuntu Ready 125m v1.24.6+k3s1 beast-node1-ubuntu Ready control-plane,master 23h v1.24.6+k3s1 beast-node2-ubuntu Ready 23h v1.24.6+k3s1 beast-node3-ubuntu Ready 23h v1.24.6+k3s1
Esto es suficiente para una configuración básica de Kubernetes, para instalar el Percona usaremos kubectl.
Instalar Percona XtraDB Cluster en Kubernetes
Para instalar el Operador de Percona en Kubernetes usaremos el siguiente comando, pero antes crearemos un namespace para que toda la informacion del mismo este en dicho lugar
kubectl create namespace percona
kubectl apply -f https://raw.githubusercontent.com/percona/percona-xtradb-cluster-operator/v1.13.0/deploy/bundle.yaml -n percona
Una vez operativo el Operador desplegamos entonces el Percona XtraDB Cluster:
kubectl apply -f https://raw.githubusercontent.com/percona/percona-xtradb-cluster-operator/v1.13.0/deploy/cr.yaml -n percona
Nota: si vez que tu cluster no inicia revisa que CPU tengas puesto pues algunas veces da este problema
Una vez que arregles el CPU reinicias las instancias y procedes a comprobar el cluster.
Como comprobar el Percona XtraDB Cluster en Kubernetes
Es posible que el clúster tarde diez minutos en iniciarse. Cuando el comando kubectl get pxc -n percona finalmente le muestre el estado del clúster como listo, puede intentar conectarse al clúster.
Necesitará el nombre de usuario y la contraseña para que el usuario administrador acceda al clúster. Utilice el comando kubectl get secrets para ver la lista de objetos Secrets (de forma predeterminada, el objeto Secrets que le interesa tiene el nombre cluster1-secrets). Puede utilizar el siguiente comando para obtener la contraseña del usuario root:
kubectl get secrets cluster1-secrets -n percona -o yaml -o jsonpath='{.data.root}' | base64 --decode | tr '\n' ' ' && echo " "
Ejecute un contenedor con la herramienta mysql y conecte la salida de su consola a su terminal. El siguiente comando hará esto, nombrando al nuevo Pod percona-client:
kubectl run -i --rm --tty percona-client -n percona --image=percona:8.0 --restart=Never -- bash -il
Ejecutarlo puede requerir algo de tiempo para implementar el Pod correspondiente.
Ahora ejecute la herramienta mysql en el shell de comandos de percona-client usando la contraseña obtenida del secreto. El comando tendrá un aspecto diferente dependiendo de si su clúster proporciona equilibrio de carga con HAProxy (la opción predeterminada) o ProxySQL:
HAProxy:
mysql -h cluster1-haproxy -uroot -p
ProxySQL:
mysql -h cluster1-proxysql -uroot -p
Una vez dentro si quieres comprobar cuantos instancias o replicas tiene el cluster puedes hacerlo con el siguiente comando dentro del mysql
SHOW STATUS LIKE 'wsrep_cluster_size';
Dado que este operador es un recurso personalizado, podemos manipular el recurso perconaxtradbcluster para que le guste el recurso estándar de Kubernetes:
kubectl get perconaxtradbcluster -n percona NAME ENDPOINT STATUS PXC PROXYSQL HAPROXY AGE cluster1 cluster1-haproxy.percona ready 3 3 31h
Al observar el conjunto de cargas de trabajo, podemos ver que el operador ha creado dos StatefulSets:
kubectl get statefulsets -o wide -n percona NAME READY AGE CONTAINERS IMAGES cluster1-haproxy 3/3 31h haproxy,pxc-monit percona/percona-xtradb-cluster-operator:1.13.0-haproxy cluster1-pxc 3/3 31h logs,logrotate,pxc percona/percona-xtradb-cluster-operator:1.13.0-logcollector
El operador también creará los servicios correspondientes que equilibrarán la carga de las conexiones a los respectivos pods:
kubectl get service -n percona NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE cluster1-haproxy ClusterIP 10.43.246.29 3306/TCP,3309/TCP,33062/TCP,33060/TCP 31h cluster1-haproxy-replicas ClusterIP 10.43.32.187 3306/TCP 31h cluster1-pxc ClusterIP None 3306/TCP,33062/TCP,33060/TCP 31h cluster1-pxc-unready ClusterIP None 3306/TCP,33062/TCP,33060/TCP 31h percona-xtradb-cluster-operator ClusterIP 10.43.221.199 443/TCP 33h
Bibliografia
Si deseas personalizar y mejorar mejor su cluster puedes seguir la guia oficial de percona ygual recomiendo este articulo de Irontec donde pueden obtener varias optimizaciones.
Dejar una contestacion