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:
/* Für diese Ressource verfügbare IP-Adressen abrufen */ if (scds_get_netaddr_list(scds_handle, &netaddr)) { scds_syslog(LOG_ERR, "Keine Netzwerkadressressource in Ressourcengruppe."); scds_close(&scds_handle); return (1); } /* Fehler zurückgeben, wenn keine Netzwerkressourcen vorhanden sind */ if (netaddr == NULL || netaddr->num_netaddrs == 0) { scds_syslog(LOG_ERR, "Keine Netzwerkadressressource in Ressourcengruppe."); 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 (;;) { /* * Für die Dauer von thorough_probe_interval zwischen den * einzelnen Testsignalen ruhen. */ (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++) { /* * Hostname und Port für Überwachung der * Fehlerfreiheit erfassen. */ hostname = netaddr->netaddrs[ip].hostname; port = netaddr->netaddrs[ip].port_proto.port; /* * HA-XFS unterstützt nur einen Port. Daher den Port-Wert * aus dem ersten Eintrag im Port-Array * abrufen. */ ht1 = gethrtime(); /* Testsignal-Startzeit festhalten */ scds_syslog(LOG_INFO, "Dienst auf Port: %d. testen", port); probe_result = svc_probe(scds_handle, hostname, port, timeout); /* * Testsignalhistorie des Dienstes aktualisieren, * bei Bedarf Aktionen ausführen. * Testsignal-Endzeit festhalten. */ ht2 = gethrtime(); /* In Millisekunden konvertieren */ dt = (ulong_t)((ht2 - ht1) / 1e6); /* * Fehlschlaghistorie berechnen und * bei Bedarf Aktionen ausführen */ (void) scds_fm_action(scds_handle, probe_result, (long)dt); } /* Jede Netzressource */ } /* Endlos weitertesten */
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 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; /* * Den Datendienst anhand einer Socketverbindung über den Port, */ * der in der port_list-Eigenschaft angeben ist, zum Host für den XFS-Datendienst * testen. Wenn der XFS-Dienst, der zum Abhören des angegebenen * Ports konfiguriert ist, auf die Verbindung antwortet, ist der Test erfolgreich * verlaufen. Andernfalls wird für den in der probe_timeout-Eigenschaft * festgesetzten Zeitraum gewartet, bevor geschlossen wird, dass der Test * fehlgeschlagen ist. */ /* * Den Zeitüberschreitungs-Prozentsatz aus SVC_CONNECT_TIMEOUT_PCT * für die Verbindung mit dem Port verwenden */ connect_timeout = (SVC_CONNECT_TIMEOUT_PCT * timeout)/100; t1 = (hrtime_t)(gethrtime()/1E9); /* * Das Testsignal stellt eine Verbindung mit den angegebenen Hostnamen und * Port her. Die Zeitdauer für die Verbindung beträgt 95% des probe_timeout- * Wertes. */ rc = scds_fm_tcp_connect(scds_handle, &sock, hostname, port, connect_timeout); if (rc) { scds_syslog(LOG_ERR, "Verbindung mit Port <%d> für Ressource <%s> konnte nicht hergestellt werden.", port, scds_get_resource_name(scds_handle)); /* Dies ist ein Totalfehlschlag */ return (SCDS_PROBE_COMPLETE_FAILURE); } t2 = (hrtime_t)(gethrtime()/1E9); /* * Tatsächliche Zeit für die Verbindungsherstellung berechnen. Der Wert sollte * kleiner oder gleich connect_timeout sein, der dem Verbindungsversuch * zugewiesenen Zeit. Wenn der Verbindungsversuch die gesamte zugewiesene * Zeit verbraucht, wird der restliche Wert aus probe_timeout, der an diese Funktion * übergeben wird, als Verbindungstrennungs-Zeitüberschreitung verwendet. * Andernfalls wird die restliche Zeit aus dem Verbindungsaufruf ebenfalls der * Verbindungstrennungs-Zeitüberschreitung hinzugerechnet. * */ time_used = (int)(t2 - t1); /* * Restliche Zeit (timeout - time_took_to_connect) für die * Verbindungstrennung verwenden */ time_remaining = timeout - (int)time_used; /* * Wenn die gesamte Zeit verbraucht wurde, einen kleinen festen * Zeitüberschreitungswert für einen weiteren Trennversuch verwenden. * So wird fd-Leak vermieden. */ if (time_remaining <= 0) { scds_syslog_debug(DBG_LEVEL_LOW, "svc_probe hat die gesamte Zeitüberschreitung von " "%d Sekunden während des Verbindungsvorgangs verbraucht und die" "Zeitüberschreitung um %d Sekunden überschritten. Trennversuch mit" " Zeitüberschreitung %d ", connect_timeout, abs(time_used), SVC_DISCONNECT_TIMEOUT_SECONDS); time_remaining = SVC_DISCONNECT_TIMEOUT_SECONDS; } /* * Bei Fehlschlag der Verbindungstrennung Teilfehlschlag zurückgeben. * Grund: Der Verbindungsaufruf ist erfolgreich, was bedeutet, dass die * Anwendung läuft. Ein Verbindungstrennungsfehlschlag kann durch * eine hängende Anwendung oder hohe Belastung verursacht werden. * In letzterem Fall die Anwendung nicht durch Rückgabe von Totalfehlschlag * als ausgefallen deklarieren. Stattdessen Teilfehlschlag deklarieren. * Wenn diese Situation anhält, schlägt der Verbindungstrennungsaufruf * erneut fehl, und die Anwendung wird neu gestartet. */ rc = scds_fm_tcp_disconnect(scds_handle, sock, time_remaining); if (rc != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Verbindung mit Port %d von Ressource %s konnte nicht getrennt werden.", port, scds_get_resource_name(scds_handle)); /* Dies ist ein Teilfehlschlag */ return (SCDS_PROBE_COMPLETE_FAILURE/2); } t2 = (hrtime_t)(gethrtime()/1E9); time_used = (int)(t2 - t1); time_remaining = timeout - time_used; /* * Wenn keine Zeit übrig ist, nicht den vollständigen Test * mit fsinfo ausführen. Stattdessen SCDS_PROBE_COMPLETE_FAILURE/2 * zurückgeben. So wird sichergestellt, dass der Server bei * Weiterbestehen dieser Zeitüberschreitung neu gestartet wird. */ if (time_remaining <= 0) { scds_syslog(LOG_ERR, "Testsignal-Zeitüberschreitung."); return (SCDS_PROBE_COMPLETE_FAILURE/2); } /* * Die Verbindung und Verbindungstrennung zum Port sind erfolgreich. * Den fsinfo-Befehl für einen vollständigen Gesundheits-Check * des Servers ausführen. * stdout umleiten. Andernfalls gelangt die Ausgabe von fsinfo * an die Konsole. */ (void) sprintf(testcmd, "/usr/openwin/bin/fsinfo -server %s:%d> /dev/null", hostname, port); scds_syslog_debug(DBG_LEVEL_HIGH, "Prüfung des Serverstatus mit %s.", testcmd); if (scds_timerun(scds_handle, testcmd, time_remaining, SIGKILL, &rc) != SCHA_ERR_NOERR || rc != 0) { scds_syslog(LOG_ERR, "Serverstatus konnte mit Befehl <%s> nicht geprüft werden", 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 der von scds_fm_action() verwalteten Fehlschlaghistorie ein Wert von 50 hinzugefügt. Der kumulative Fehlschlagwert beträgt nun 100, so dass scds_fm_action() den Datendienst neu startet.