Réplica para la disponibilidad

La duplicación proporciona tolerancia a anomalías y aumenta el rendimiento para una topología de eXtreme Scale distribuida. La réplica se habilita asociando correlaciones de respaldo con un conjunto de correlaciones.

Acerca de los conjuntos de correlaciones

Un conjunto de correlaciones es una colección de correlaciones que se categorizan por clave de partición. Esta clave de partición se obtiene de la clave de la correlación individual tomando el módulo hash para el número de particiones. Si un grupo de correlaciones del conjunto de correlaciones tiene la clave de partición X, esas correlaciones se almacenan en una partición X correspondiente en la cuadrícula de datos. Si otro grupo tiene la clave de partición Y, todas las correlaciones se almacenan en una partición Y y así sucesivamente. Los datos de las correlaciones se replican en función de la política definida en el conjunto de correlaciones. La réplica se produce en topologías distribuidas.

A los conjuntos de correlaciones se les asigna el número de particiones y una política de réplica. La configuración de réplica de conjunto de correlaciones identifica el número de fragmentos de réplica síncronos y asíncronos que el conjunto de correlaciones debe tener además del fragmento primario. Por ejemplo, si existe una réplica síncrona y una réplica asíncrona, en todas las BackingMaps asignadas al conjunto de correlaciones se distribuye automáticamente un fragmento de réplica en el conjunto de servidores de contenedor disponibles para la cuadrícula de datos. La configuración de réplica también puede permitir que los clientes lean datos de servidores duplicados de forma síncrona. Esto puede esparcir la carga de las solicitudes de lectura entre servidores adicionales en eXtreme Scale. La réplica sólo tiene un impacto de modelo de programación cuando se realiza la precarga de las correlaciones de respaldo.

Precarga de correlaciones

Las correlaciones se pueden asociar a cargadores. Un cargador se utiliza para captar objetos cuando no se pueden encontrar en la correlación (una falta de coincidencia) así como para grabar los cambios en un programa de fondo cuando se confirma una transacción. Los cargadores también se pueden utilizar para cargar previamente datos en una correlación. Se llama al método preloadMap de la interfaz Loader en cada correlación cuando la partición correspondiente del conjunto de correlaciones se convierte en primario. El método preloadMap no se llama en las réplicas. Intenta cargar todos los datos referenciados previstos del programa de fondo en la correlación utilizando la sesión proporcionada. La correlación pertinente se identifica mediante el argumento BackingMap que se pasa al método preloadMap.
void preloadMap(Session session, BackingMap backingMap) throws LoaderException;

Precarga en conjunto de correlaciones particionado

Las correlaciones puede particionarse en N particiones. Por lo tanto, las correlaciones pueden extenderse por varios servidores, con cada entrada identificada por una clave que sólo se almacena en uno de esos servidores. Las correlaciones muy grandes pueden mantenerse en un eXtreme Scale porque la aplicación ya no está limitada por el tamaño del almacenamiento dinámico de una sola JVM para mantener todas las entradas de una correlación. Las aplicaciones que desea cargar previamente con el método preloadMap de la interfaz del cargador deben identificar el subconjunto de datos que carga previamente. Siempre existe un número fijo de particiones. Puede determinar este número utilizando el siguiente ejemplo de código:

int numPartitions = backingMap.getPartitionManager().getNumOfPartitions();
int myPartition = backingMap.getPartitionId();
Este ejemplo de código muestra que una aplicación puede identificar el subconjunto de los datos que se deben precargar de la base de datos. Las aplicaciones siempre deben utilizar estos métodos incluso cuando la correlación no está particionada inicialmente. Estos métodos permiten una cierta flexibilidad: si posteriormente los administradores particionan la correlación, el cargador sigue funcionando correctamente.

La aplicación debe emitir consultas para recuperar el subconjunto myPartition del programa de fondo. Si se utiliza una base de datos, puede ser más fácil tener una columna con un identificador de partición para un registro dado salvo que haya alguna consulta natural que permita a los datos de la tabla particionarse fácilmente.

Rendimiento

La implementación de la precarga copia datos del programa de fondo en la correlación almacenando varios objetos en la correlación de una única transacción. El número óptimo de registros para almacenar por transacción depende de varios factores, incluidos la complejidad y el tamaño. Por ejemplo, después de que la transacción incluya bloques de más de 100 entradas, se reduce la ventaja del rendimiento a medida que aumenta el número de entradas. Para determinar el número óptimo, empiece con 100 entradas y, a continuación, aumente el número hasta que no se detecte más aumento en el rendimiento. Las transacciones de mayor tamaño dan como resultado un mayor rendimiento de duplicación. Recuerde que sólo el fragmento primario ejecuta el código de precarga. Los datos cargados previamente se duplican desde el fragmento primario hasta todas las réplicas que están en línea.

Precarga de conjuntos de correlaciones

Si la aplicación utiliza un conjunto de correlaciones con varias correlaciones, cada correlación tiene su propio cargador. Cada cargador tiene un método de carga previa. eXtreme Scale carga cada correlación en serie. Será más eficaz precargar todas las correlaciones designando una única correlación como la correlación de precarga. Este proceso es un convenio de aplicación. Por ejemplo, dos correlaciones, departamento y empleado, podrían utilizar el cargador de departamento para cargar previamente las correlaciones de departamento y de empleado. Este procedimiento asegura que, transaccionalmente, si una aplicación desea un departamento los empleados de dicho departamento están en la memoria caché. Cuando el cargador de departamento precarga un departamento desde el programa de fondo, también capta los empleados de dicho departamento. El objeto de departamento y sus objetos de empleados asociados se añadirán a la correlación utilizando una sola transacción.

Precarga recuperable

Algunos clientes tienen conjuntos de datos de gran tamaño que necesitan almacenarse en la memoria caché. La precarga de estos datos puede requerir mucho tiempo. A veces, la precarga debe finalizar para que la aplicación pueda ir en línea. Puede sacar provecho de que la precarga sea recuperable. Suponga que hay un millón de registros que se deben precargar. El fragmento primario los precarga y falla al llegar al registro número 800.000. Normalmente, la réplica elegida como el nuevo fragmento primario borra los estados duplicados y empieza desde el principio. eXtreme Scale puede emplear una interfaz ReplicaPreloadController. El cargador de la aplicación también necesitará implementar la interfaz ReplicaPreloadController. Este ejemplo añade un solo método al cargador: Status checkPreloadStatus(Session session, BackingMap bmap);. Este método lo invoca el tiempo de ejecución de eXtreme Scale antes de que se llame al método de carga previa de la interfaz del cargador. eXtreme Scale comprueba el resultado de este método (estado) para determinar su comportamiento siempre que una réplica pasa a ser un fragmento primario.

Tabla 1. Valor de estado y respuesta
Valor de estado devuelto Respuesta de eXtreme Scale
Status.PRELOADED_ALREADY eXtreme Scale no llama al método de precarga porque su valor de estado indica que la correlación se ha precargado completamente.
Status.FULL_PRELOAD_NEEDED eXtreme Scale borra la correlación y llama de forma normal al método de precarga.
Status.PARTIAL_PRELOAD_NEEDED eXtreme Scale deja la correlación tal cual y llama a la precarga. Esta estrategia permite al cargador de aplicación seguir realizando la precarga a partir de ese momento.

Evidentemente, mientras un fragmento primario está precargando la correlación, debe dejar algún estado en una correlación del conjunto de correlaciones que se está replicando para que la réplica determine qué estado debe devolver. Puede utilizar una correlación adicional llamada, por ejemplo, RecoveryMap. Esta RecoveryMap debe formar parte del mismo conjunto de correlaciones que se está precargando para asegurar que la correlación se replica coherentemente con los datos que se están precargando. A continuación se muestra una implementación sugerida.

Cuando la precarga confirma cada bloque de registros, el proceso también actualiza un contador o valor en la RecoveryMap como parte de esa transacción. Los datos precargados y los datos de RecoveryMap se duplican de forma atómica en las réplicas. Cuando la réplica se promociona a fragmento primario, puede comprobar la RecoveryMap para ver qué ha pasado.

RecoveryMap puede mantener una sola entrada con la clave de estado. Si no existe ningún objeto para esta clave, necesita una precarga completa (checkPreloadStatus devuelve FULL_PRELOAD_NEEDED). Si existe un objeto para esta clave de estado y el valor es COMPLETE, la precarga se completa y el método checkPreloadStatus devuelve PRELOADED_ALREADY. De lo contrario, el objeto de valor indica dónde se inicia la precarga y el método checkPreloadStatus devuelve: PARTIAL_PRELOAD_NEEDED. El cargador puede almacenar el punto de recuperación en una variable de instancia para el cargador de forma que, cuando se invoque la precarga, el cargador sepa el punto de partida. RecoveryMap también puede mantener una entrada por correlación si cada correlación se precarga independientemente.

Manejo de recuperación en modalidad de réplica síncrona con un cargador

El tiempo de ejecución de eXtreme Scale se ha diseñado para que no pierda datos confirmados cuando el fragmento primario falla. En la siguiente sección se muestran los algoritmos utilizados. Estos algoritmos sólo se aplican cuando un grupo de réplicas utiliza la réplica síncrona. Un cargador es opcional.

El tiempo de ejecución de eXtreme Scale puede configurarse de modo que duplique de forma síncrona todos los cambios de un fragmento primario en las réplicas. Cuando se coloca una réplica síncrona, recibe una copia de los datos existentes en el fragmento primario. Durante este tiempo, el primario continúa recibiendo transacciones y las copia en la réplica de forma asíncrona. La réplica no se considera en línea en este momento.

Después de que la réplica capte el primario, la réplica entra en la modalidad de igual y se inicia la réplica síncrona. Cada transacción confirmada en el primario se envía a las réplicas síncronas y el primario espera una respuesta de cada réplica. Una secuencia de confirmación síncrona con un cargador en el primario se parece al siguiente conjunto de pasos:

Tabla 2. Secuencia de confirmación del fragmento primario
Paso con cargador Paso sin cargador
Obtener bloqueos para entradas igual
Desechar cambios para el cargador no operativo
Guardar cambios en la memoria caché igual
Enviar cambios a réplicas y esperar el reconocimiento igual
Confirmar en el cargador a través del plug-in TransactionCallback Se llama a la confirmación de plug-in, pero no sucede nada
Liberar bloqueos para entradas igual

Tenga en cuenta que los cambios se envían a la réplica antes de que se confirmen en el cargador. Para determinar cuando se confirman los cambios en la réplica, revise esta sentencia: en el momento de la inicialización, inicializar las listas tx en el fragmento primario tal como se indica a continuación.

CommitedTx = {}, RolledBackTx = {}

Durante el proceso de confirmaciónsíncrono, utilice la siguiente secuencia:

Tabla 3. Proceso de confirmación síncrona
Paso con cargador Paso sin cargador
Obtener bloqueos para entradas igual
Desechar cambios para el cargador no operativo
Guardar cambios en la memoria caché igual
Enviar cambios con una transacción confirmada, retrotraer la transacción a la réplica y esperar el reconocimiento igual
Borrar lista de transacciones confirmadas y transacciones retrotraídas igual
Confirmar en el cargador a través del plug-in TransactionCallback Se sigue llamando a la confirmación del plug-in TransactionCallBack, pero normalmente no sucede nada
Si la confirmación es satisfactoria, añada la transacción a las transacciones confirmadas, de lo contrario, añádala a las transacciones retrotraídas no operativo
Liberar bloqueos para entradas igual

Para el proceso de réplicas, utilice la siguiente secuencia:

  1. Recibir cambios
  2. Confirmar todas las transacciones recibidas en la lista de transacciones confirmadas
  3. Retrotraer todas las transacciones recibidas en la lista de transacciones retrotraídas
  4. Iniciar una transacción o sesión
  5. Aplicar cambios en la transacción o sesión
  6. Guardar la transacción o sesión en la lista de pendientes
  7. Devolver respuesta

Tenga en cuenta que en la réplica, no se produce ninguna interacción de cargador mientras la réplica está en modalidad de réplica. El fragmento primario debe pasar todos los cambios a través del cargador. La réplica no pasa ningún cambio. Un efecto secundario de este algoritmo es que la réplica siempre tiene las transacciones, pero éstas no se confirman hasta que la siguiente transacción primaria envía el estado de confirmado de estas transacciones. A continuación, las transacciones se confirman o retrotraen en la réplica. Hasta entonces, las transacciones no están confirmadas. Puede añadir un temporizador en el primario que envía el resultado de la transacción después de un breve periodo (unos pocos minutos). Este temporizador limita, pero no elimina, cualquier obsolescencia a este periodo de tiempo. Esta obsolescencia sólo es un problema si se utiliza la modalidad de lectura de réplica. Si no, la obsolescencia no tiene ningún impacto en la aplicación.

Cuando el fragmento primario falla, es probable que haya unas pocas transacciones confirmadas o retrotraídas en el fragmento primario, pero el mensaje nunca llega a la réplica con estos resultados. Cuando una réplica se promociona y pasa a ser el nuevo fragmento primario, una de las primeras acciones es manejar esta condición. Cada transacción pendiente se vuelve a procesar respecto al conjunto de correlaciones del nuevo fragmento primario. Si hay un cargador, cada transacción se ofrece al cargador. Estas transacciones se aplican estrictamente en el orden primero en entrar, primero en salir (FIFO). Si una transacción falla, se ignora. Si hay tres transacciones pendientes, A, B y C, es posible que A se confirme, B se retrotraiga y C también se confirme. Ninguna transacción tiene ningún impacto en las demás. Suponga que son independientes.

Un cargador puede que desee utilizar una lógica un poco distinta cuando está en modalidad de recuperación de migración tras error comparada con la modalidad normal. El cargador puede saber fácilmente cuando está en modalidad de recuperación de migración tras error implementando la interfaz ReplicaPreloadController. El método checkPreloadStatus sólo se invoca cuando se completa la recuperación de la migración tras error. Por lo tanto, si el método de aplicación de la interfaz del cargador se invoca antes del método checkPreloadStatus, se trata de una transacción de recuperación. Después de llamar al método checkPreloadStatus, la recuperación de migración tras error está completa.

Equilibrio de carga entre réplicas

eXtreme Scale, salvo que se configure de otra manera, envía todas las solicitudes de lectura y grabación al servidor primario para un grupo de réplicas determinado. El fragmento primario debe atender todas las solicitudes de los clientes. Es posible que desee permitir que las solicitudes de lectura se envíen a las réplicas del fragmento primario. Si envía solicitudes de lectura a las réplicas la carga de las solicitudes de envío se podrá compartir entre varias JVM (Java Virtual Machines). No obstante, el uso de réplicas para las solicitudes de lectura puede generar repuestas incoherentes.

El equilibrio de carga entre réplicas normalmente se utiliza sólo cuando los clientes almacenan en la memoria caché datos que almacenan siempre o cuando los clientes utilizan el bloqueo pesimista.

Si lo datos se almacenan en la memoria caché constantemente y luego se invalidan en la memoria caché cercana del cliente, como resultado el fragmento primario debe detectar un índice de solicitudes get relativamente alto de los clientes. Asimismo, en modalidad de bloqueo pesimista, no existe memoria caché local, y por ello todas las solicitudes se envían al fragmento primario.

Si los datos son relativamente estáticos o si no se utiliza la modalidad pesimista, el envío de solicitudes de lectura a la réplica no tiene un gran impacto en el rendimiento. La frecuencia de las solicitudes get de los clientes con memoria caché que están llenas de datos no es alta.

Cuando un cliente se inicia, su memoria caché cercana está vacía. Las solicitudes de memoria caché para la memoria caché vacía se remiten al fragmento primario. La memoria caché del cliente obtendrá datos con el tiempo, lo que provocará que la carga de solicitudes baje. Si muchos clientes se inician simultáneamente, es posible que la carga sea significativa y la lectura de réplicas puede ser una opción de rendimiento apropiada.

Réplica del lado del cliente

Con eXtreme Scale, puede duplicar una correlación de servidor con uno o más clientes utilizando la réplica asíncrona. Un cliente puede solicitar una copia de sólo lectura local de una correlación en el servidor utilizando el método ClientReplicableMap.enableClientReplication.

void enableClientReplication(Mode mode, int[] partitions, ReplicationMapListener
listener) throws  ObjectGridException;

El primer parámetro es la modalidad de réplica. Esta modalidad puede ser una réplica continua o una réplica de instantánea. El segundo parámetro es una matriz de ID de particiones que representan las particiones desde las que duplicar los datos. Si el valor es nulo o una matriz vacía, los datos se duplican desde todas las particiones. El último parámetro es un escucha para recibir los sucesos de réplica de cliente. Para obtener detalles, consulte ClientReplicableMap y ReplicationMapListener en la documentación de la API.

Después de habilitar la réplica, el servidor empieza a duplicar la correlación con el cliente. Con el tiempo, el cliente sólo estará a unas pocas transacciones por detrás del servidor en cualquier momento dado.