Servicenamen und Data Guard

Werbung
Servicenamen und Data Guard
Dr. Martin Wunderli
Trivadis
Zürich-Glattbrugg
Problemstellung
Die Netzwerkkonfiguration im Data Guard Umfeld enthält eine entscheidende
Herausforderung: Den Client dazu zu bringen, beim Verbindungsversuch auf die
Standby Site dies zu erkennen und auf die Primary Site zu wechseln.
Ein Knackpunkt dabei ist der Listener auf der Standby Site. Einerseits braucht man ihn,
damit die archivierten Redo Log Dateien auf die Standby Site übertragen werden
können. Auf der anderen Seite muss ein Client mit TAF-Netzwerkkonfiguration einen
Netzwerk-Fehler beim Connect auf einen Standby Host/Listener bekommen, damit er
einen Failover auf die (richtige) Primary Site durchführt. Eine Möglichkeit hierzu ist ein
fehlender Listener. Ein Widerspruch?
Eine schnelle Lösung wäre die mit 2 Listenern auf unterschiedlichen Ports, einen für die
Redo Übertragung, der immer gestartet sein darf, und einen für die Client Connects, der
nur auf der Primary Site gestartet sein darf. Leider erfordert diese Lösung manuelle
Eingriffe bei Switchover, Failover etc (der Client Listener muss jeweils korrekt – auf der
Primary – gestartet werden).
Eine andere Lösung wäre, einen zusätzlichen Servicenamen (Datenbankparameter
service_names) für die Datenbank zu definieren, falls sie für Client Connects bereit ist.
Dieser Servicename wird dann in den TNSNAMES Einträgen auf den Clients benutzt.
Ein Client Connect auf einen Listener ergibt einen Netzwerkfehler, falls der Listener
diesen Servicenamen nicht kennt und er kennt ihn nur, wenn der PMON der
Datenbank ihn aufgrund des Parameters service_names beim Listener registriert hat.
Doch auch diese Lösung erfordert eine manuelle Interaktion (Modifikation von
service_names) bei Rollenwechseln, oder nicht?
Die Lösung
Die Lösung heisst Database Trigger, genauer: Startup Trigger. Er feuert, nachdem die
Datenbank geöffnet wurde und kann als SYS erzeugt werden.
Der nachfolgend abgebildete Trigger Code prüft, ob die Datenbank den korrekten
open_mode (Read-Write) hat und hängt im Erfolgsfall einen zusätzlichen Servicenamen
an den bestehenden Datenbankparameter service_names an. Wir wählen hier
db_name_RW.trivadistraining.com (könnte man noch generischer durch Auslesen von
db_domain aus v$parameter machen...). Damit wir bei Shutdown etc. diesen
zusätzlichen Servicenamen nicht löschen müssen, erfolgt die Modifikation nur im
Memory.
create or replace trigger service_trigger after startup on database
declare
name varchar(9); open_mode varchar(10);
service_names varchar(4000);
begin
select name,open_mode into name,open_mode from v$database;
select value into service_names from v$parameter
where name = 'service_names';
if open_mode = 'READ WRITE' then
service_names := service_names || ', ' || name ||
'_RW.trivadistraining.com';
end if;
execute immediate 'alter system set service_names = '''
|| service_names || ''' scope=memory';
end;
Der passende TNSNAMES Eintrag für Clients sieht dann wie folgt aus:
MIS.TRIVADISTRAINING.COM =
(DESCRIPTION =
(FAILOVER=ON)
(LOAD_BALANCE=OFF)
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = bagheera)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = hathi)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = MIS_RW.TRIVADISTRAINING.COM)
)
)
Die Triggererweiterung
Die vorgestellte Lösung ist schon ganz nett. Was aber, wenn eine physiche Standby
Datenbank Read-Only geöffnet wird? Und was ist mit einer logischen Standby
Datenbank? Diese ist Read-Write geöffnet, auf sie darf aber nur lesend zugegriffen
werden!
Durch einen weiteren Servicename mit der Endung _RO, auf den ein zusätzlicher
TNSNAMES Eintrag zugreifen kann, erfüllt der Trigger auch diese Anforderung.
create or replace trigger service_trigger after startup on database
declare
name varchar(4000);
open_mode varchar(10);
database_role varchar(16);
service_names varchar(4000);
begin
select name,open_mode,database_role into
name,open_mode,database_role from v$database;
select value into service_names from v$parameter
where name = 'service_names';
if open_mode = 'READ WRITE' and database_role = 'PRIMARY' then
service_names := service_names || ', ' || name ||
'_RW.trivadistraining.com';
else
service_names := service_names || ', ' || name ||
'_RO.trivadistraining.com';
end if;
execute immediate 'alter system set service_names = ''' ||
service_names || ''' scope= memory';
end;
/
In diesem Fall sieht der passende TNSNAMES Eintrag für Clients dann wie folgt aus:
MIS_RO.TRIVADISTRAINING.COM =
(DESCRIPTION =
(FAILOVER=ON)
(LOAD_BALANCE=OFF)
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = bagheera)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = hathi)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = MIS_RO.TRIVADISTRAINING.COM)
)
)
Bei Switchover Operationen meldet sich die Primary sauber beim Listener ab, der
Servicename verschwindet. Bei Failover Operationen muss man einen eventuell noch
laufenden Listener restarten oder reloaden, damit er den Servicenamen verliert.
Wechselt eine physische Standby Datenbank von Read-Only zurück in den Log-Apply
Modus, ist es am einfachsten, diese zu restarten. Damit ist der _RO Servicename weg
und der Bounce stört ja nicht besonders.
Kritische Würdigung
Der abgebildete Datenbank Trigger ist sehr einfach gehalten und nutzt die
Möglichkeiten von Oracle 10g nicht (Oracle Notification Service, das Package
dbms_services etc. Vgl. [1]). Er hilft daher nicht, ein immer noch verbleibendes Problem
des Failovers im DataGuard Umfeld zu lösen: Das der TCP Timeouts im Falle eines
totalen Serverausfalls (IP des Servers nicht mehr erreichbar): Denn ein TAF-enableter
TNSNAMES Eintrag, der den abgeschalteten Server als ersten in der Adressliste enthält,
wird längere Zeit (abhängig vom Betriebssystem) warten, bis er eine Connection zu dem
nächsten Server in der ADDRESS_LIST versucht. Hier kann nur eine Benachrichtigung
durch die neue Primary Datenbank an (registrierte) Clients oder ein Konzept mit
virtuellen IPs (welche failovern) Abilfe schaffen.
Fazit
Die beschriebene Lösung aktiviert zuverlässig Services auf Primary Datenbanken, auf
physichen Standby Datenbanken, die Read-Only geöffnet sind, und auf logischen
Standby Datenbanken. Zudem ist sie lauffähig mit den Oracle Releases 9.x und 10.x
(eigentlich auch 8.1.x ☺), einem standardisierten Einsatz auch in gemischten Umfeldern
steht also nichts im Wege. Bleibt eigentlich nur die Frage, warum Oracle nicht selbst
auf diese Lösung gekommen ist...
Sie sehen also, dass die Herausforderungen für eine optimale Infrastruktur oftmals im
Detail liegen. Trivadis achtet auf diese Details, wovon sie zum Beispiel in unseren
Oracle High Availability Kursen O-RAC (Real Application Clusters) und O-DG (Data
Guard) profitieren können.
Kontaktadresse:
Trivadis AG
Dr. Martin Wunderli
Europastrasse 5
CH-8152 Glattbrugg
[email protected]
http://www.trivadis.com
Literatur
[1] Fast-Start Failover – Oracle Data Guard 10g Release 2.
Oracle White Paper September 2005
Herunterladen