Sun Cluster: Guía del desarrollador de los servicios de datos del sistema operativo Solaris

Supervisor de fallos SUNW.xfnts

RGM no invoca directamente el método PROBE, sino que invoca el método Monitor_start para iniciar el supervisor después de que se inicie un recurso en un 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:

Bucle principal de xfonts_probe

El método xfonts_probe implementa un bucle. Antes de hacerlo, xfonts_probe ejecuta estas acciones:

El método xfnts_probe implementa el bucle como sigue:


for (ip = 0; ip < netaddr->num_netaddrs; ip++) {
         /*
          * Tomar el nombre de sistema y puerto en el que se va a
          * supervisar el estado.
          */
         hostname = netaddr->netaddrs[ip].hostname;
         port = netaddr->netaddrs[ip].port_proto.port;
         /*
          * HA-XFS admite un solo puerto y obtiene el
          * valor del puerto de la primera
          * entrada de la matriz de puertos.
          */
         ht1 = gethrtime(); /* Bloquear el tiempo de inicio del análisis */
         scds_syslog(LOG_INFO, "Analizar el servicio en el puerto: %d.", port);

         probe_result =
         svc_probe(scds_handle, hostname, port, timeout);

         /*
          * Actualizar historial de análisis de servicio,
          * tomar medidas si fuera necesario.
          * Bloquear el tiempo de finalización del análisis.
          */
         ht2 = gethrtime();

         /* Convertir a milisegundos */
         dt = (ulong_t)((ht2 - ht1) / 1e6);

         /*
          * Calcular el historial de fallos y tomar
          * medidas si corresponde
          */
         (void) scds_fm_action(scds_handle,
             probe_result, (long)dt);
      }   /* Cada recurso de red */
   }    /* Seguir analizando indefinidamente */

La función svc_probe() implementa la lógica del análisis. El valor de retorno de svc_probe() se pasa a scds_fm_action(), que determina si debe reiniciar la aplicación, realizar una recuperación de fallos del grupo de recursos o si no debe hacer nada.

Función svc_probe()

La función svc_probe() establece una conexión de zócalo simple al puerto especificado, mediante una llamada a scds_fm_tcp_connect(). Si falla la conexión, svc_probe() retorna un valor de 100 que indica que el fallo es total. Si la conexión es satisfactoria, pero falla la desconexión, svc_probe() devuelve un valor de 50, lo que indica un fallo parcial. Si la conexión y la desconexión son satisfactorias, svc_probe() devuelve un valor de 0, que indica que la operación ha sido satisfactoria.

El código de svc_probe() es el siguiente.


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;


   /*
    * analizar el servicio de datos mediante una conexión de zócalo al
    * puerto especificado en la propiedad port_list property del sistema
    * que sirve al servicio de datos de XFS. Si el servicio XFS que se ha
    * configurado para recibir en el puerto especificado responde a la
    * conexión, el análisis es satisfactorio. En caso contrario, esperar
    * durante un tiempo definido en la propiedad probe_timeout antes de
    * determinar que el análisis ha fallado.
    */

   /*
    * Utilizar el porcentaje SVC_CONNECT_TIMEOUT_PCT de tiempo de
    * espera para conectarse al puerto
    */
   connect_timeout = (SVC_CONNECT_TIMEOUT_PCT * timeout)/100;
   t1 = (hrtime_t)(gethrtime()/1E9);

   /*
    * el análisis realiza una conexión al nombre de sistema y puerto
    * especificados. La conexión tiene un 95% del valor real de probe_timeout.
    */
   rc = scds_fm_tcp_connect(scds_handle, &sock, hostname, port,
       connect_timeout);
   if (rc) {
      scds_syslog(LOG_ERR,
          "No se ha podido conectar con el puerto <%d> "
          "del recurso <%s>.",
          port, scds_get_resource_name(scds_handle));
      /* es un fallo total */
      return (SCDS_PROBE_COMPLETE_FAILURE);
   }

   t2 = (hrtime_t)(gethrtime()/1E9);

   /*
    * Calcular el tiempo real que tardó en conectarse. Debe ser
    * menor o igual que connect_timeout, el tiempo asignado
    * para la conexión. Si la conexión utiliza todo el tiempo que se
    * le asigna, el valor restante de probe_timeout que se pasa a
    * esta función se utilizará como tiempo de desconexión. En
    * caso contrario, el tiempo restante de la llamada de conexión
    * se agregará también al tiempo de espera de desconexión.
    *
    */

   time_used = (int)(t2 - t1);

   /*
    * Usar el tiempo restante (timeout - time_took_to_connect)
    * para la desconexión
    */

   time_remaining = timeout - (int)time_used;

   /*
    * Si se ha usado todo el tiempo, utilice un tiempo de espera
    * reducido y no modificable para seguir intentando la desconexión.
    * Así se evitará la fuga de fd.
    */
   if (time_remaining <= 0) {
      scds_syslog_debug(DBG_LEVEL_LOW,
          "svc_probe ha usado el tiempo total de espera de "
          "%d segundos durante la operación de conexión y ha"
          "sobrepasado el tiempo de espera en %d segundos."
          "Intentado desconectar con el tiempo de espera"
          " %d ",
          connect_timeout,
          abs(time_used),
          SVC_DISCONNECT_TIMEOUT_SECONDS);

      time_remaining = SVC_DISCONNECT_TIMEOUT_SECONDS;
   }

   /*
    * Devolver fallo parcial en caso de fallo de desconexión.
    * Motivo: la llamada de conexión es satisfactoria, lo que
    * significa que la aplicación está activa. Un fallo de
    * desconexión se puede producir debido a una aplicación
    * bloqueada o a una carga excesiva.
    * Si fuera este último caso, no declarar la aplicación
    * terminada devolviendo un fallo completo. En su lugar,
    * declararlo fallo parcial. Si la situación persiste, la llamada
    * de desconexión volverá a fallar y se reiniciará la aplicación.
    */
   rc = scds_fm_tcp_disconnect(scds_handle, sock, time_remaining);
   if (rc != SCHA_ERR_NOERR) {
      scds_syslog(LOG_ERR,
          "No se ha podido desconectar el puerto %d del recurso %s.",
          port, scds_get_resource_name(scds_handle));
      /* es un fallo parcial */
      return (SCDS_PROBE_COMPLETE_FAILURE/2);
   }

   t2 = (hrtime_t)(gethrtime()/1E9);
   time_used = (int)(t2 - t1);
   time_remaining = timeout - time_used;

   /*
    * Si no queda tiempo, no realizar la prueba completa con
    * fsinfo. Devolver SCDS_PROBE_COMPLETE_FAILURE/2
    * en su lugar. Así se asegurará que si el tiempo de espera
    * agotado persiste, se reiniciará el servidor.
    */
   if (time_remaining <= 0) {
      scds_syslog(LOG_ERR, "Tiempo de espera de análisis agotado.");
      return (SCDS_PROBE_COMPLETE_FAILURE/2);
   }

   /*
    * La conexión y desconexión del puerto han sido satisfactorias.
    * Ejecutar la orden fsinfo para realizar una comprobación
    * completa del estado del servidor.
    * Redirigir stdout o la salida de fsinfo terminará en la consola.
    */
   (void) sprintf(testcmd,
       "/usr/openwin/bin/fsinfo -server %s:%d > /dev/null",
       hostname, port);
   scds_syslog_debug(DBG_LEVEL_HIGH,
       "Comprobar el estado del servidor con %s.", testcmd);
   if (scds_timerun(scds_handle, testcmd, time_remaining,
      SIGKILL, &rc) != SCHA_ERR_NOERR || rc != 0) {

      scds_syslog(LOG_ERR,
         "No se ha podido comprobar el estado del servidor "
         "con la orden <%s>",
         testcmd);
      return (SCDS_PROBE_COMPLETE_FAILURE/2);
   }
   return (0);
}

Al terminar, svc_probe() devuelve un valor de éxito (0), fallo parcial (50) o fallo total (100). El método xfnts_probe pasa este valor a scds_fm_action().

Selección de la acción del supervisor de fallos

El método xfnts_probe invoca scds_fm_action() para determinar qué acción debe tomar. La lógica de scds_fm_action() es la siguiente:

Por ejemplo, supongamos que el análisis establece una conexión con el servidor xfs, 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. El fallo de desconexión 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 análisis siguiente, el servidor vuelve a fallar en la desconexión, se añadirá un valor de 50 al historial de fallos que mantiene scds_fm_action(). El valor acumulado de fallos es de 100, por lo que scds_fm_action() reiniciará el servicio de datos.