RGM ruft die PROBE-Methode nicht direkt auf. Es wird vielmehr die Monitor_start -Methode aufgerufen, um den Monitor zu starten, nachdem eine Ressource auf einem Knoten gestartet wurde. Die xfnts_monitor_start-Methode startet den Fehler-Monitor unter PMF-Steuerung. Die xfnts_monitor_stop-Methode stoppt den Fehler-Monitor.
Der SUNW.xfnts-Fehler-Monitor führt folgende Aufgaben aus:
Er überwacht in regelmäßigen Abständen die Fehlerfreiheit des xfs-Serverdämons mithilfe eigens zur Prüfung von einfachen TCP-basierten Diensten wie xfs entworfener Dienstprogramme.
Er verfolgt Probleme der Anwendung innerhalb eines bestimmten Zeitfensters unter Verwendung der Eigenschaften Retry_count und Retry_interval und entscheidet, ob der Datendienst im Fall eines Totalfehlschlags der Anwendung neu gestartet oder ein Failover ausgeführt wird. Die Funktionen scds_fm_action() und scds_fm_sleep() unterstützen diesen Verfolgungs- und Entscheidungsmechanismus.
Er implementiert die Failover- bzw. Neustartentscheidung mithilfe von scds_fm_action().
Er aktualisiert den Ressourcenzustand und stellt ihn den Verwaltungstools und grafischen Benutzeroberflächen zur Verfügung.
Die xfonts_probe -Methode implementiert eine Schleife. Vor dem Implementieren der Schleife führt xfonts_probe folgende Aktionen aus:
Sie ruft die Netzwerkadressressourcen für die xfnts-Ressource folgendermaßen ab:
/* 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); }
Sie ruft scds_fm_sleep() auf und übergibt den Wert von Thorough_probe_interval als den Zeitüberschreitungswert. Das Testsignal ruht zwischen den einzelnen Testvorgängen für den Wert von Thorough_probe_interval.
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));
Die xfnts_probe-Methode implementiert die Schleife folgendermaßen:
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 */
Die svc_probe()-Funktion implementiert die Testsignallogik. Der Rückgabewert von svc_probe() wird an scds_fm_action() übergeben. Diese Funktion entscheidet, ob die Anwendung neu gestartet, ein Failover der Ressourcengruppe ausgeführt werden oder nichts geschehen soll.
Die svc_probe()-Funktion stellt eine einfache Socketverbindung mit dem angegebenen Port her, indem sie scds_fm_tcp_connect() aufruft. Wenn die Verbindung fehlschlägt, gibt svc_probe() den Wert 100 für Totalfehlschlag zurück. Wenn die Verbindung hergestellt werden kann, aber die Verbindungstrennung fehlschlägt, gibt svc_probe() den Wert 50 für Teilfehlschlag zurück. Wenn sowohl die Verbindung als auch die Verbindungstrennung erfolgreich verlaufen, gibt svc_probe() den Wert 0 für Erfolg zurück.
Der Code für svc_probe() sieht folgendermaßen aus:
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); }
Nach Beendigung gibt svc_probe() einen Wert für Erfolg (0), Teilfehlschlag (50), oder Totalfehlschlag (100) zurück. Die xfnts_probe-Methode übergibt diesen Wert an scds_fm_action().
Die xfnts_probe-Methode ruft scds_fm_action() auf, um die auszuführende Aktion festzulegen. Die Logik in scds_fm_action() sieht folgendermaßen aus:
Kumulative Fehlschlaghistorie innerhalb des Wertes der Retry_interval-Eigenschaft verwalten
Wenn der kumulative Fehlschlag 100 (Totalfehlschlag) erreicht, wird der Datendienst neu gestartet. Wenn Retry_interval überschritten ist, wird die Historie zurückgesetzt.
Wenn die Anzahl der Neustarts den in der Retry_count-Eigenschaft angegebenen Wert innerhalb der in Retry_interval angegebenen Zeit überschreitet, wird für den Datendienst ein Failover ausgeführt.
Angenommen, das Testsignal stellt eine Verbindung mit dem XFS-Server her, kann die Verbindung jedoch nicht trennen. Das bedeutet, dass der Server läuft, aber vielleicht hängt oder nur momentan überlastet ist. Bei Fehlschlag der Verbindungstrennung wird ein Teilfehlschlag (50) an scds_fm_action() gesendet. Dieser Wert liegt unter dem Schwellenwert für das Neustarten des Datendienstes. Der Wert wird jedoch in der Fehlerhistorie festgehalten.
Wenn während des nächsten Tests die Verbindungstrennung vom Server erneut fehlschlägt, wird ein Wert von 50 der von scds_fm_action() verwalteten Fehlschlaghistorie hinzugefügt. Der kumulative Fehlschlagwert beträgt nun 100, so dass scds_fm_action() den Datendienst neu startet.