Múltiples DC Activo - Pasivo (Stand-by en caliente), una base de datos
Por motivos de resiliencia, puede que quieras desplegar múltiples instancias de tu aplicación en varios centros de datos (regiones). En este escenario, puedes tener un centro de datos "primario" que esté "activo" y sirviendo tráfico, y un centro de datos "secundario" que esté "pasivo" y en espera. Si el centro de datos primario se cae, el centro de datos secundario tomará el control y empezará a servir tráfico. En este escenario, el centro de datos "activo/primario" servirá tráfico y el centro de datos "pasivo/secundario" estará en espera. Si el centro de datos primario se cae, el centro de datos secundario tomará el control y empezará a servir tráfico. La base de datos debe ser compartida entre los dos centros de datos.
Problema
El patrón descrito arriba requiere que el centro de datos secundario (pasivo) tenga instancias de la aplicación ejecutándose (en espera), pero no deben comunicarse con/ni intentar unirse al clúster IPF en el centro de datos primario (activo) ni servir ningún tráfico/procesar transacciones. Esto se puede conseguir usando el MongoDB Discovery Plugin, que habilita el descubrimiento de instancias de la aplicación tanto en el centro de datos primario como en el secundario, asegurando al mismo tiempo que solo se forme un clúster dentro del centro de datos primario.
Nota: El plugin requiere que la base de datos sea compartida entre los dos centros de datos.
A continuación se proporciona una guía sobre cómo configurar el plugin.
Paso 0: Añadir dependencia
Añade la dependencia akka-discovery-mongodb-management al pom.xml, que contiene la lógica del plugin y algunos endpoints útiles para gestionar el clúster.
<dependency>
<groupId>com.iconsolutions.ipf.core.discovery</groupId>
<artifactId>akka-discovery-mongodb-management</artifactId>
</dependency>
Paso 1: Configurar el plugin
Toda la configuración descrita en esta sección Configurar Cluster Bootstrap con descubrimiento MongoDB debe añadirse al archivo de configuración; aquí solo listaremos lo que difiere de la configuración por defecto.
Así, en todos los nodos del DC 1 (Activo) deberíamos especificar:
akka.discovery.akka-mongodb.enabled = true
akka.discovery.akka-mongodb.collection = "akka-discovery-mongodb-dc1"
Y en todos los nodos del DC 2 (Pasivo) deberíamos especificar:
akka.discovery.akka-mongodb.enabled = false
akka.discovery.akka-mongodb.collection = "akka-discovery-mongodb-dc2"
El nombre de la colección debe ser diferente para cada centro de datos, ya que la base de datos es compartida.
Esto resultará en la siguiente topología:
Verifícalo accediendo a la URL /cluster/members de Akka Management Cluster HTTP Management para observar la configuración correcta de los clústeres en cada DC.
Paso 2: Desactivar nodos en el DC activo
IMPORTANTE: Solo debes tener un clúster de Akka activo a la vez. Si no es así, todos los clústeres activos intentarán procesar las mismas transacciones. Esto resultará en resultados de transacción impredecibles.
Si el clúster primario sigue activo, pero quieres cambiar el procesamiento al clúster pasivo, debes detener/pasivar el clúster de Akka activo antes de activar el clúster pasivo.
Esto se puede hacer de la siguiente manera:
Paso 2.1: Marcar nodos como no activos
Marca los nodos de Akka activos como inactivos a través del endpoint /discovery/cluster-status.
POST http://hostname:server_port/discovery/cluster-status
Accept: application/json
{
"active": false
}
Esto marca los nodos activos como inactivos, pero no detiene el procesamiento. Este valor se persiste y se usa como el valor de configuración para la propiedad akka.discovery.akka-mongodb.enabled, si la aplicación se reinicia. Al iniciar la aplicación, esta intentará obtener el valor persistido. Si el valor persistido no existe, se usará el valor del archivo de configuración.
Paso 2.2: Detener el procesamiento de transacciones
Para detener el procesamiento de transacciones, los nodos en el clúster activo deben apagarse de forma ordenada o reiniciarse. Si se reinician, formarán un clúster pasivo, porque la configuración de la propiedad akka.discovery.akka-mongodb.enabled se cambió a false y se persistió. Tras reiniciar el nodo, leerá el nuevo valor de configuración y no formará un clúster de Akka activo.
Akka HTTP Management puede usarse para apagar de forma ordenada todos los nodos:
Puedes obtener una lista de todos los nodos de Akka con
GET http://hostname:akka_management_port/cluster/members
Para todos los nodos recuperados de la petición anterior (reachables y unreacheables), el apagado puede desencadenarse con
DELETE http://akka_node_hostname:akka_management_port/cluster/members/<akka_node_address>
Más sobre los endpoints de Akka Http Management puede encontrarse aquí API Definition
Paso 3: Activar nodos en el DC pasivo
IMPORTANTE: El ‘clúster previamente activo’ debe estar deshabilitado/apagado/pasivado antes de habilitar el clúster pasivo.
Cuando el DC primario cae (o ha sido apagado/pasivado), los nodos en el DC secundario deben activarse. Esto puede hacerse mediante el endpoint /discovery/cluster-status.
POST http://hostname:server_port/discovery/cluster-status
Accept: application/json
{
"active": true
}
Esto activa los nodos en el DC pasivo, y comenzarán a servir tráfico. El valor de configuración para la propiedad akka.discovery.akka-mongodb.enabled se persiste y se usa si la aplicación se reinicia. Al iniciar la aplicación, esta intentará obtener el valor persistido. Si el valor persistido no existe, se usa el valor del archivo de configuración.
Paso 4: Configuración de health checks en Kubernetes
Cuando la liveness probe se configura con los endpoints /actuator/health/readiness o /actuator/health, los pods en el clúster pasivo —que no está procesando trabajo actualmente— se reiniciarán repetidamente porque el endpoint de liveness seleccionado nunca devolverá éxito.
Esto podría dar como resultado el resultado indeseable de que, al llegar una solicitud de activación del clúster, esta se envíe mientras los nodos se están reiniciando, causando que la solicitud de activación se pierda.
Este problema puede mitigarse configurando una startup probe. La startup probe puede configurarse para usar el endpoint de health check de Akka Http Management
/health/ready.
Este health check solo conoce el estado del clúster de Akka (y no el estado de los conectores de IPF, el estado de la conexión a MongoDB, etc.)
Esto es lo que necesitamos en este caso. La startup probe esperará (durante un periodo de tiempo configurado) a que se forme el clúster de Akka.
Cuando esto ocurra, entregará el monitoreo de la aplicación a las readiness y liveness probes.
Si el clúster de Akka no se ha formado (en el periodo de tiempo configurado), la aplicación se reiniciará y la startup probe
empezará a monitorizar la aplicación recién iniciada desde el principio.
La startup probe se probó durante periodos que van de 1h a 24h. La elección de un intervalo apropiado se deja al usuario según sus requisitos específicos.
A continuación se proporciona un ejemplo de configuración de probes de salud en K8S:
livenessProbe:
failureThreshold: 6 # 30s
httpGet:
path: /actuator/health/readiness
port: http
scheme: HTTP
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3 # 15s
httpGet:
path: /actuator/health/readiness
port: http
scheme: HTTP
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 2
startupProbe:
failureThreshold: 720 # 1h
httpGet:
path: /health/ready
port: akka-management
scheme: HTTP
initialDelaySeconds: 15
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 2