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 una cuadrícula de datos porque la aplicación ya no está limitada por el tamaño del almacenamiento dinámico de una sola Máquina virtual Java (JVM) para mantener todas las entradas de una correlación. Las aplicaciones que desea cargar previamente con el método preloadMap de la interfaz Loader 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 como una aplicación puede identificar un subconjunto de datos que se debe cargar previamente 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.

Consulte Escribir un cargador con un controlador de precarga de réplica para obtener un ejemplo de cómo implementar un cargador para una cuadrícula de datos replicada.

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 un conjunto 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. La cuadrícula de datos 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 utilizar 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, cuando un fragmento primario está cargando la correlación, debe dejar algún estado en una correlación del MapSet que se está replicando para que la réplica determine qué estado debe devolver. Puede utilizar una correlación adicional llamada, por ejemplo, correlación RecoveryMap. Esta correlación RecoveryMap debe formar parte del mismo conjunto de correlaciones MapSet que se está precargando para garantizar que la correlación se replique 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 correlación RecoveryMap como parte de esa transacción. Los datos precargados y los datos de la correlación RecoveryMap se replican de forma atómica en las réplicas. Cuando la réplica se promociona a fragmento primario, puede comprobar la correlación RecoveryMap para ver qué ha pasado.

La correlación 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. La correlación RecoveryMap también puede mantener una entrada por correlación si cada correlación se precarga independientemente.

Manejo de la recuperación en modalidad de duplicación 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 invoca el plug-in para enviar, 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 transacción a la réplica y esperar al 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 fragmentoprimario debe pasar todos los cambios a través del cargador. La réplica no cambia ningún dato. 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 cuándo 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.