RGM no llama directamente al método PROBE, sino que llama a Monitor_start para iniciar el supervisor una vez iniciado un recurso en el nodo. El método xfnts_monitor_start inicia el supervisor de fallos bajo el control de PMF. El método xfnts_monitor_stop detiene el supervisor de fallos.
El supervisor de fallos SUNW.xfnts realiza las operaciones siguientes:
Supervisa periódicamente el estado del daemon del servidor xfs mediante las utilidades diseñadas específicamente para comprobar servicios simples basados en TCP, como xfs.
Realiza un seguimiento de los problemas que encuentra la aplicación en un intervalo de tiempo (mediante las propiedades Retry_count y Retry_interval) y decide si se debe reiniciar el servicio de datos o realizar una recuperación ante fallos en caso de que falle por completo la aplicación. Las funciones scds_fm_action() y scds_fm_sleep() proporcionan soporte integrado para este mecanismo de rastreo y toma de decisiones.
Implementa el reinicio o la recuperación ante fallos utilizando scds_fm_action ().
Actualiza el estado del recurso y lo facilita a las herramientas administrativas e interfaces gráficas de usuario.
El método xfonts_probe implementa un bucle. Antes de implementar el bucle, xfonts_probe realiza las siguientes operaciones:
Recupera los recursos de dirección de red para el recurso xfnts de la siguiente forma:
/* Get the ip addresses available for this resource */ if (scds_get_netaddr_list(scds_handle, &netaddr)) { scds_syslog(LOG_ERR, "No network address resource in resource group."); scds_close(&scds_handle); return (1); } /* Return an error if there are no network resources */ if (netaddr == NULL || netaddr->num_netaddrs == 0) { scds_syslog(LOG_ERR, "No network address resource in resource group."); return (1); }
Llama a scds_fm_sleep() y pasa el valor de Thorough_probe_interval como valor de tiempo de espera. El análisis permanece inactivo durante el tiempo indicado en Thorough_probe_interval, como se indica a continuación:
timeout = scds_get_ext_probe_timeout(scds_handle); for (;;) { /* * sleep for a duration of thorough_probe_interval between * successive probes. */ (void) scds_fm_sleep(scds_handle, scds_get_rs_thorough_probe_interval(scds_handle));
El método xfnts_probe implementa el siguiente bucle:
for (ip = 0; ip < netaddr->num_netaddrs; ip++) { /* * Grab the hostname and port on which the * health has to be monitored. */ hostname = netaddr->netaddrs[ip].hostname; port = netaddr->netaddrs[ip].port_proto.port; /* * HA-XFS supports only one port and * hence obtain the port value from the * first entry in the array of ports. */ ht1 = gethrtime(); /* Latch probe start time */ scds_syslog(LOG_INFO, "Probing the service on port: %d.", port); probe_result = svc_probe(scds_handle, hostname, port, timeout); /* * Update service probe history, * take action if necessary. * Latch probe end time. */ ht2 = gethrtime(); /* Convert to milliseconds */ dt = (ulong_t)((ht2 - ht1) / 1e6); /* * Compute failure history and take * action if needed */ (void) scds_fm_action(scds_handle, probe_result, (long)dt); } /* Each net resource */ } /* Keep probing forever */
La función svc_probe() implementa la lógica del análisis. El valor de devolución de svc_probe() se pasa a scds_fm_action (), que determina si se debe reiniciar la aplicación, realizar una recuperación ante fallos del grupo de recurso o no realizar ninguna acción.
La función svc_probe () establece una conexión de socket simple al puerto especificado mediante una llamada a scds_fm_tcp_connect(). Si falla la conexión, svc_probe() devuelve el valor 100, que indica la existencia de un fallo completo. Si la conexión se establece con éxito, pero falla la desconexión, svc_probe() devuelve el valor 50, que indica la existencia de un fallo parcial. Si la conexión y desconexión se realizan satisfactoriamente, svc_probe() devuelve el valor 0, que indica que no hay fallos.
A continuación se muestra el código de svc_probe():
int svc_probe(scds_handle_t scds_handle, char *hostname, int port, int timeout) { int rc; hrtime_t t1, t2; int sock; char testcmd[2048]; int time_used, time_remaining; time_t connect_timeout; /* * probe the data service by doing a socket connection to the port * specified in the port_list property to the host that is * serving the XFS data service. If the XFS service which is configured * to listen on the specified port, replies to the connection, then * the probe is successful. Else we will wait for a time period set * in probe_timeout property before concluding that the probe failed. */ /* * Use the SVC_CONNECT_TIMEOUT_PCT percentage of timeout * to connect to the port */ connect_timeout = (SVC_CONNECT_TIMEOUT_PCT * timeout)/100; t1 = (hrtime_t)(gethrtime()/1E9); /* * the probe makes a connection to the specified hostname and port. * The connection is timed for 95% of the actual probe_timeout. */ rc = scds_fm_tcp_connect(scds_handle, &sock, hostname, port, connect_timeout); if (rc) { scds_syslog(LOG_ERR, "Failed to connect to port <%d> of resource <%s>.", port, scds_get_resource_name(scds_handle)); /* this is a complete failure */ return (SCDS_PROBE_COMPLETE_FAILURE); } t2 = (hrtime_t)(gethrtime()/1E9); /* * Compute the actual time it took to connect. This should be less than * or equal to connect_timeout, the time allocated to connect. * If the connect uses all the time that is allocated for it, * then the remaining value from the probe_timeout that is passed to * this function will be used as disconnect timeout. Otherwise, the * the remaining time from the connect call will also be added to * the disconnect timeout. * */ time_used = (int)(t2 - t1); /* * Use the remaining time(timeout - time_took_to_connect) to disconnect */ time_remaining = timeout - (int)time_used; /* * If all the time is used up, use a small hardcoded timeout * to still try to disconnect. This will avoid the fd leak. */ if (time_remaining <= 0) { scds_syslog_debug(DBG_LEVEL_LOW, "svc_probe used entire timeout of " "%d seconds during connect operation and exceeded the " "timeout by %d seconds. Attempting disconnect with timeout" " %d ", connect_timeout, abs(time_used), SVC_DISCONNECT_TIMEOUT_SECONDS); time_remaining = SVC_DISCONNECT_TIMEOUT_SECONDS; } /* * Return partial failure in case of disconnection failure. * Reason: The connect call is successful, which means * the application is alive. A disconnection failure * could happen due to a hung application or heavy load. * If it is the later case, don't declare the application * as dead by returning complete failure. Instead, declare * it as partial failure. If this situation persists, the * disconnect call will fail again and the application will be * restarted. */ rc = scds_fm_tcp_disconnect(scds_handle, sock, time_remaining); if (rc != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Failed to disconnect to port %d of resource %s.", port, scds_get_resource_name(scds_handle)); /* this is a partial failure */ return (SCDS_PROBE_COMPLETE_FAILURE/2); } t2 = (hrtime_t)(gethrtime()/1E9); time_used = (int)(t2 - t1); time_remaining = timeout - time_used; /* * If there is no time left, don't do the full test with * fsinfo. Return SCDS_PROBE_COMPLETE_FAILURE/2 * instead. This will make sure that if this timeout * persists, server will be restarted. */ if (time_remaining <= 0) { scds_syslog(LOG_ERR, "Probe timed out."); return (SCDS_PROBE_COMPLETE_FAILURE/2); } /* * The connection and disconnection to port is successful, * Run the fsinfo command to perform a full check of * server health. * Redirect stdout, otherwise the output from fsinfo * ends up on the console. */ (void) sprintf(testcmd, "/usr/openwin/bin/fsinfo -server %s:%d > /dev/null", hostname, port); scds_syslog_debug(DBG_LEVEL_HIGH, "Checking the server status with %s.", testcmd); if (scds_timerun(scds_handle, testcmd, time_remaining, SIGKILL, &rc) != SCHA_ERR_NOERR || rc != 0) { scds_syslog(LOG_ERR, "Failed to check server status with command <%s>", testcmd); return (SCDS_PROBE_COMPLETE_FAILURE/2); } return (0); }
Una vez finalizado, svc_probe() devuelve un valor que indica que el proceso se ha realizado con éxito (0), o que se ha producido un fallo parcial (50) o uno completo (100). El método xfnts_probe pasa este valor a scds_fm_action().
El método xfnts_probe llama a scds_fm_action() para determinar la acción que debe realizarse. La lógica de scds_fm_action() es la siguiente:
Mantiene un historial de fallos acumulativos en el intervalo especificado en la propiedad Retry_interval.
Si el fallo acumulativo alcanza el valor (fallo completo), debe reiniciarse el servicio de datos. Si se supera Retry_interval, hay que poner a cero el historial.
Si el número de reinicios supera el valor de la propiedad Retry_count durante el tiempo especificado por Retry_interval, debe realizarse una recuperación ante fallos del servicio de datos.
Por ejemplo, supongamos que el análisis establece una conexión con el servidorxfs, pero no logra desconectarse satisfactoriamente. Esto indica que el servidor está en ejecución, pero que es posible que esté bloqueado o bajo una carga temporal. Al fallar la desconexión, se envía un fallo parcial ( 50) a scds_fm_action(). Este valor está por debajo del umbral para reiniciar el servicio de datos, pero se mantiene el valor en el historial de fallos.
Si, durante el siguiente análisis, el servidor no puede desconectarse otra vez, el valor 50 se agrega al historial de fallos que mantiene scds_fm_action (). El valor de fallo acumulativo es ahora de 100, por lo que scds_fm_action() reinicia el servicio de datos.