Guide du développeur de services de données Sun Cluster pour SE Solaris

Détecteur de pannes SUNW.xfnts

Le RGM n'appelle pas directement la méthode PROBE : il appelle d'abord la méthode Monitor_start pour démarrer le détecteur après le démarrage d'une ressource sur un noeud. La méthode xfnts_monitor_start démarre le détecteur de pannes sous le contrôle du gestionnaire de processus. La méthode xfnts_monitor_stop arrête le détecteur de pannes.

Le détecteur de pannes SUNW.xfnts effectue les opérations suivantes :

Boucle principale xfonts_probe

La méthode xfonts_probe met en oeuvre une boucle. Mais avant cela, xfonts_probe effectue les opérations suivantes :

La méthode xfnts_probe met en oeuvre la boucle suivante :

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 fonction svc_probe() met la logique de sondage en oeuvre. La valeur de retour de svc_probe() est transmise à scds_fm_action (), qui détermine s'il faut redémarrer l'application, basculer le groupe de ressources, ou ne rien faire du tout.

Fonction svc_probe()

La fonction svc_probe () établit une connexion de prise simple au port spécifié en appelant scds_fm_tcp_connect(). Si la connexion échoue, svc_probe() renvoie une valeur de 100, ce qui indique un échec total. Si la connexion est établie mais que la déconnexion échoue, svc_probe() renvoie une valeur de 50, ce qui indique un échec partiel. Si la connexion et la déconnexion fonctionnent, svc_probe() renvoie une valeur de 0, ce qui indique une réussite.

Le code de svc_probe() est le suivant :

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);
}

Ensuite, svc_probe() renvoie une valeur indiquant une réussite (0), un échec partiel (50) ou un échec total (100). La méthode xfnts_probe transmet cette valeur à scds_fm_action().

Détermination de l'action du détecteur de pannes

La méthode xfnts_probe appelle scds_fm_action() pour décider de la mesure à prendre. La logique de scds_fm_action() est la suivante :

Par exemple, supposons que la sonde établisse une connexion au serveur xfs, mais qu'elle ne puisse pas se déconnecter. Ceci indique que le serveur tourne mais qu'il peut être bloqué ou être provisoirement soumis à une forte charge. L'échec de la déconnexion entraîne l'envoi d'un échec partiel ( 50) à scds_fm_action(). Cette valeur se situe sous le seuil de redémarrage du service de données, mais la valeur est gérée dans l'historique des pannes.

Si, au cours de la détection suivante, le serveur n'arrive toujours pas à se déconnecter, une valeur de 50 est ajoutée à l'historique des pannes géré par scds_fm_action (). La valeur des pannes cumulées est à présent de 100. Par conséquent, scds_fm_action() redémarre le service de données.