Serwer Oracle w konfiguracji wielowątkowej

System Oracle jest najczęściej instalowany w konfiguracji z dedykowanymi procesami usługowymi (ang. dedicated server). Jednakże ta konfiguracja sprawdza się jedynie w przypadku sieci, gdzie z bazy danych korzysta jednocześnie niezbyt duża liczba użytkowników, jak również w sytuacjach, w których użytkownicy dość intensywnie wykorzystują zasoby serwera (na przykład uruchamiając zadania wsadowe). Zazwyczaj jednak użytkownicy nie obciążają równomiernie serwera przez cały czas trwania ich sesji (użytkownik który akurat pije kawę, bądź rozmawia przez telefon, na pewno nie korzysta z serwera w tym samym stopniu, co osoba wprowadzająca do bazy danych kolejną pozycję zamówienia). W przypadku konfiguracji z dedykowanymi procesami usługowymi, każdemu procesowi użytkownika (ang. user process) w momencie podłączania się do bazy danych przydzielany jest
"na stałe" jeden proces usługowy (ang. server process). Proces ten pełni niejako rolę interfejsu pomiędzy użytkownikiem (procesem użytkownika), a bazą
danych. To on decyduje o tym, gdzie należy skierować określone żądanie użytkownika oraz w jaki sposób ma ono zostać obsłużone. Dedykowany proces usługowy zwalniany jest dopiero w momencie rozłączania się użytkownika z bazą danych. Po co jednak rezerwować dla każdego użytkownika odrębny proces usługowy, skoro w określonym momencie tylko część osób aktywnie korzysta z bazy danych? W normalnych warunkach użytkownik od czasu do czasu pije kawę, je drugie śniadanie, czy po prostu rozmawia; w tych momentach dedykowany proces usługowy jest cały czas
"zajęty", niepotrzebnie wykorzystując zasoby serwera. Stąd właśnie wzięła się idea serwera w
konfiguracji wielowątkowej (ang. multithreded server – MTS), w której istnieje określona ilość procesów usługowych, przydzielanych dynamicznie jedynie tym użytkownikom, którzy kierują żądania do bazy danych.

Co więcej, przy takiej konfiguracji zmienia się sposób wykorzystania pamięci serwera. Zawsze gdy użytkownik łączy się z bazą danych, zostaje mu przydzielony odrębny obszar PGA (ang. process global area). W przypadku konfiguracji z dedykowanymi procesami usługowymi, część pamięci znajdująca się w obszarze PGA jest rezerwowana na tzw.
prywatny obszar poleceń SQL (ang. private SQL area), gdzie przechowywane są informacje dotyczące poleceń kierowanych przez użytkownika do bazy danych (na przykład wartości zmiennych). W przypadku dużej liczby użytkowników korzystających jednocześnie z bazy danych, rezerwowane dla nich obszary PGA mogą wydatnie zmniejszyć dostępne zasoby pamięci; może nawet dojść do sytuacji, w której użytkownik nie będzie mógł połączyć się z bazą danych z powodu braku wystarczającej ilości pamięci. Tu także z pomocą może przyjść serwer w konfiguracji wielowątkowej. W tej konfiguracji bowiem prywatny obszar poleceń przenoszony jest do SGA (ang. system global area), a w PGA pozostaje jedynie niewielki obszar pamięci przeznaczony na przestrzeń stosu, gdzie przechowywane są informacje charakterystyczne tylko i wyłącznie dla danej sesji użytkownika (takie jak zmienne, czy dane związane z działaniem konkretnej sesji). Prywatny obszar poleceń umieszczony w SGA nie potrzebuje tak dużo pamięci jak wówczas, gdy znajduje się on w PGA poszczególnych sesji; w tym pierwszym przypadku bowiem nie są powielane pewne dane wspólne dla różnych sesji (w końcu osoby korzystające z tej samej aplikacji zazwyczaj wykonują podobne, a nawet identyczne zadania).

Reasumując, korzystanie z serwera w konfiguracji wielowątkowej niesie ze sobą przynajmniej dwie zalety:


  1. Zmniejsza się ilość procesów
    usługowych w stosunku
    do wszystkich procesów
    użytkowników.
  2. Zmniejsza się ilość pamięci
    rezerwowanej w obszarze PGA
    dla poszczególnych
    sesji użytkowników.

Jak zatem uruchomić serwer w konfiguracji MTS i czy zawsze można tego dokonać?

Zasada jest taka: Jeśli serwer potrafi pracować w konfiguracji z dedykowanymi procesami usługowymi, to potrafi również pracować w konfiguracji wielowątkowej; cała tajemnica tkwi w dodaniu kilku parametrów do pliku init<SID>.ora. Zanim jednak te parametry zostaną przedstawione, postarajmy się dokładniej przyjrzeć zasadzie działania serwera MTS. Jest ona przedstawiona na poniższym rysunku:

Jak widać, pojawiły się tutaj dodatkowe procesy zwane procesami rozdzielającymi (ang. dispatcher processes); są one swego rodzaju pośrednikami pomiędzy procesami użytkownika a procesami usługowymi. Nowością jest również
kolejka żądań (ang. request queue) oraz kolejki odpowiedzi (ang.
response queues). W pierwszej z nich umieszczane są żądania kierowane przez procesy użytkownika do procesów usługowych, do drugich natomiast procesy usługowe wstawiają odpowiedzi przeznaczone dla konkretnych procesów użytkownika.

Serwer MTS działa w sposób opisany w poniższych podpunktach:


  1. Użytkownik zgłasza żądanie
    (np. wykonuje polecenie SQL)
  2. Żądanie to zostaje przejęte
    przez wolny proces rozdzielający
    i umieszczone we wspólnej dla
    wszystkich tych procesów kolejce
    żądań.
  3. Żądanie zostaje pobrane z kolejki
    żądań przez pierwszy wolny proces
    usługowy (żądania pobierane są
    według kolejności FIFO - pierwszy
    wchodzi, pierwszy wychodzi).
    Jeden proces usługowy może
    jednocześnie pobrać tylko jedno
    żądanie oczekujące w kolejce.
  4. Proces usługowy komunikując się
    z bazą danych, przystępuje
    do realizacji żądania.
  5. Proces usługowy umieszcza wyniki
    realizacji żądania w kolejce
    odpowiedzi należącej do procesu
    rozdzielającego, który "wystąpił
    z prośbą o realizację żądania".
    Każdy proces rozdzielający posiada
    w SGA swoją własną kolejkę
    odpowiedzi (w przeciwieństwie
    do kolejki żądań, która jest wspólna
    dla wszystkich tych procesów).
  6. Proces rozdzielający pobiera wynik
    wykonania żądania z kolejki
    odpowiedzi i przekazuje go
    do procesu użytkownika.

Różnicę pomiędzy tą konfiguracją, a konfiguracją z dedykowanymi procesami usługowymi widać już na pierwszy rzut oka. Procesy usługowe nie są tutaj
"marnotrawione" na obsługiwanie nie zawsze aktywnych sesji użytkownika, lecz przydzielane dynamicznie tylko i wyłącznie wówczas, gdy rzeczywiście zachodzi taka potrzeba. Koordynacją działań jakie zachodzą pomiędzy procesami użytkownika i współdzielonymi procesami usługowymi zajmują się procesy rozdzielające. Oczywiście ilość procesów usługowych jest tutaj dużo mniejsza niż w przypadku konfiguracji z procesami dedykowanymi. Również ilość procesów rozdzielających jest niewielka w stosunku do liczby procesów użytkownika. Jaka to ma być ilość, zależy od potrzeb konkretnej bazy danych i jest ustalane w trakcie strojenia tej bazy (będzie o tym mowa w dalszej części niniejszego tekstu).

Jak zostało to już wcześniej wspomniane, chcąc uruchomić serwer w konfiguracji wielowątkowej należy dodać kilka parametrów do pliku init<SID>.ora. Poza tym, warunkiem koniecznym wymaganym podczas łączenia się użytkownika z serwerem w tej konfiguracji, jest korzystanie z sieciowego procesu nasłuchującego (ang. listener). Warunek ten musi być spełniony nawet wówczas, gdy zarówno klient jak i serwer znajdują się na tej samej maszynie. Gdyby w przypadku pewnych użytkowników zasada ta nie została zrealizowana, system przydzieliłby im dedykowane procesy usługowe, przez co zalety serwera wielowątkowego nie mogłyby być w pełni wykorzystane.

Dlaczego proces nasłuchu jest tak istotny, nawet w konfiguracji w której zazwyczaj nie musi on być używany (gdy klient i serwer znajdują się na tym samym komputerze). Aby to zrozumieć należy prześledzić sekwencję zdarzeń, mających miejsce podczas łączenia się użytkownika z serwerem w konfiguracji wielowątkowej.

Najpierw uruchamiany jest proces nasłuchu, który
"oczekuje" na użytkownika pod adresem podanym w pliku konfiguracyjnym. Następnie zostaje uruchomiona instancja bazy danych, a tym samym swoją pracę rozpoczynają procesy rozdzielające, z których każdy otrzymuje określony adres. Po tej operacji następuje zarejestrowanie adresów wszystkich procesów rozdzielających (polegające na skojarzeniu adresów tych procesów z adresami pod którymi odbywa się nasłuch). Od tego momentu proces nasłuchu zaczyna kierować przychodzące żądania połączenia do wolnych procesów rozdzielających.

Pewne zaburzenia w tym schemacie mogą pojawić się wówczas, gdy instancja zostanie uruchomiona przed startem procesu nasłuchującego. Wówczas z pewnością wystąpi pewne opóźnienie w komunikacji procesu rozdzielającego i nasłuchującego, a tym samym opóźni się moment rejestracji procesu rozdzielającego. Jeśli w tym czasie przyjdzie od użytkownika żądanie o połączenie, wówczas może ono zostać odrzucone lub przyporządkowane do dedykowanego procesu usługowego. W kolejnych krokach proces nasłuchu sprawdza, czy żądanie użytkownika o przyłączenie do bazy danych może być zrealizowane. Jeśli tak nie jest, żądanie zostaje odrzucone i proces nasłuchu przechodzi w stan oczekiwania. W przeciwnym przypadku proces ten skierowuje żądanie użytkownika do wolnego procesu rozdzielającego. Po tej operacji klient rozwiązuje sesję z procesem nasłuchu, a za pośrednictwem procesu rozdzielającego ustanawia ją z procesem usługowym. Dodatkowo proces rozdzielający informuje proces nasłuchu o swojej zajętości, co pozwala temu ostatniemu kierować przychodzące żądania tylko do wolnych procesów rozdzielających.

Jak więc widać proces nasłuchu odgrywa tutaj olbrzymią rolę. Bez niego ustanowienie połączenia z serwerem w konfiguracji MTS byłoby po prostu niemożliwe. Wróćmy jednak do konfiguracji serwera wielowątkowego. Oto parametry które należy ustawić w pliku konfiguracyjnym init<SID>. ora:

MTS_LISTENER_ADDRESS

MTS_SERVICE

MTS_DISPATCHERS

MTS_MAX_DISPATCHERS

MTS_SERVERS

MTS_MAX_SERVERS

Należy również zmodyfikować wielkość współdzielonego obszaru pamięci, określoną przy pomocy parametru SHARED_POOL_SIZE, dodając doń tyle kilobajtów, ilu użytkowników będzie jednocześnie łączyło się z serwerem korzystając z konfiguracji MTS (ta dodatkowa pamięć jest konieczna do przechowania informacji dotyczącej połączenia pomiędzy procesami użytkownika, procesami rozdzielającymi i procesami usługowymi).

Poniżej zostaną scharakteryzowane poszczególne parametry konfiguracji MTS.

MTS_LISTENER_ADDRESS - Przy pomocy tego parametru należy podać konfigurację procesu nasłuchującego, tj. określić adres pod którym proces ten oczekuje na żądania użytkowników o przyłączenie się do bazy danych. Jeśli w systemie wykorzystywany jest więcej niż jeden protokół sieciowy, wówczas w pliku konfiguracyjnym init<SID>.ora może występować kilka parametrów MTS_LISTENER_ADDRESS (każdy dla innego protokołu). Nic tak nie rozjaśnia zagmatwanej teorii jak krótki przykład; oto on:

MTS_LISTENER_ADDRESS = "ADDRESS= (PROTOCOL=tcp) (PORT=1521) (HOST=Candy) "

MTS_LISTENER_ADDRESS = "ADDRESS= (PROTOCOL=decnet) (OBJECT=OUTA) (NODE=Candy) "

Oczywiście każdy z adresów które znajdą się w pliku init<SID>.ora musi posiadać swój odpowiednik w pliku konfiguracyjnym procesu nasłuchującego (listener.ora). Zresztą wystarczy przyjrzeć się strukturze pliku listener.ora, a analogia pomiędzy zapisami znajdującymi się tam w sekcji ADDRESS_LIST, a sposobem zapisu wartości parametru MTS_LISTENER_ADDRESS powinna zostać dostrzeżona bez większych kłopotów.

MTS_SERVICE - Wartością tego parametru powinien być alias bazy danych (określany czasem mianem 'nazwa usługi') podany w pliku
tnsnames.ora. Popatrzmy na poniższy przykład:

MTS_SERVICE = "multi"

przy czym odpowiedni łańcuch (tzw. connect string) w pliku tnsnames.ora mógłby wyglądać następująco:

multi =

        (DESCRIPTION =

         (ADDRESS = (PROTOCOL = TCP)(Host = Candy) (Port = 1521))

         (CONNECT_DATA = (SID = baza))

)

Zaleca się jednak, aby jako wartość tego parametru podawać SID bazy danych, bowiem wówczas użytkownik zostanie połączony z bazą nawet w przypadku, gdy z jakichś powodów proces rozdzielający nie będzie dostępny. Jeżeli wartość parametru MTS_SERVICE nie zostanie określona, system domyślnie przyporządkuje mu wartość parametru DB_NAME. Jeżeli zaś i ten drugi nie zostanie podany, Oracle zwróci błąd informujący o pominięciu wartości parametru MTS_SERVICE.

MTS_DISPATCHERS - Przy pomocy tego parametru należy określić początkową ilość procesów rozdzielających, to znaczy taką ilość, która zostanie utworzona w momencie uruchomienia instancji. Czy zatem ilość ta może zmieniać się podczas pracy instancji? Otóż tak; serwer bazy danych w zależności od potrzeb (tj. od ilości podłączonych użytkowników i stopnia wykorzystania zasobów) może dynamicznie tworzyć dodatkowe procesy rozdzielające, jak również likwidować je, gdy nie są już potrzebne. Ilość procesów rozdzielających należy określić dla każdego protokołu wykorzystywanego do łączenia się z bazą danych. To dlatego wartość parametru MTS_DISPATCHERS nie jest wbrew pozorom liczbą całkowitą, lecz łańcuchem znaków. Oczywistym jest również, że w pliku init<SID>.ora może wystąpić więcej niż jeden parametr MTS_DISPATCHERS, każdy dla innego protokołu. Oto przykład który wszystko wyjaśnia:

MTS_DISPATCHERS = " (PROTOCOL = tcp)
(DISPATCHERS = 5) "

MTS_DISPATCHERS = " (PROTOCOL = decnet) (DISPATCHERS = 3) "

Przy pomocy powyższych parametrów zostały zadeklarowane trzy procesy rozdzielające dla protokołu DECnet oraz pięć procesów rozdzielających dla protokołu TCP/IP.
To jeszcze nie wszystkie możliwości parametru MTS_DISPATCHERS. Przy jego pomocy można bowiem zadeklarować określoną liczbę procesów rozdzielających dla konkretnego adresu IP (na przykład w sytuacji, gdy w serwerze znajduje się kilka kart sieciowych, nierównomiernie obciążonych przez użytkowników):

MTS_DISPATCHERS = " (ADDRESS=
(PARTIAL=TRUE) (PROTOCOL=tcp)
(HOST=10.4.4.8)) (DISPATCHERS=2) "
MTS_DISPATCHERS = " (ADDRESS=
(PARTIAL=TRUE) (PROTOCOL=tcp)
(HOST=10.4.4.9)) (DISPATCHERS=4) "

Można także deklarować procesy rozdzielające dla konkretnych portów na których serwer nasłuchuje żądań od użytkowników:

MTS_DISPATCHERS = " (ADDRESS=
(PARTIAL=TRUE) (PROTOCOL=tcp)
(HOST=10.4.4.9) (PORT=1521))
(DISPATCHERS=2) "
MTS_DISPATCHERS = " (ADDRESS=
(PARTIAL=TRUE) (PROTOCOL=tcp)
(HOST=10.4.4.9) (PORT=1522))
(DISPATCHERS=3) "

Jak widać na powyższych przykładach, 'grupowanie' procesów rozdzielających możliwe jest dzięki nadaniu klauzuli PARTIAL wartości TRUE.

Jak zostało to wspomniane wcześniej, serwer - w zależności od obciążenia
- dynamicznie zwiększa lub zmniejsza ilość procesów rozdzielających. Tego typu zmiany mogą być również wykonywane
"ręcznie" przez administratora lub użytkownika posiadającego uprawnienie ALTER SYSTEM. Chcąc zmienić ilość procesów rozdzielających bez konieczności zatrzymywania instancji i modyfikowania pliku konfiguracyjnego, należy wydać polecenie ALTER SYSTEM:

ALTER SYSTEM SET MTS_DISPATCHERS
= ' (PROTOCOL=tcp) (DISPATCHERS=6) ';

Obowiązuje tu jednak pewna zasada: można zmieniać ilość procesów rozdzielających jedynie dla tych protokołów, dla których takie procesy zostały zdefiniowane (to znaczy dla tych, które znalazły się w jednej z wartości
parametru MTS_DISPATCHERS w pliku
init<SID>. ora). Chcąc przydzielić jakąś ilość procesów do protokołu nie spełniającego tej zasady, należy zmienić plik init<SID>.ora i ponownie uruchomić instancję.

Zmniejszenie ilości procesów rozdzielających nie spowoduje automatycznej ich likwidacji, lecz jedynie poinformuje system, że powinien on stopniowo kończyć działanie procesów pozostających zbyt długo w stanie bezczynności, zbliżając ich ilość do tej, jaka została określona w poleceniu ALTER SYSTEM.

MTS_MAX_DISPATCHERS - Wartość tego parametru przedstawia maksymalną ilość procesów rozdzielających jaka może istnieć w systemie (dla wszystkich protokołów łącznie). Jak wspomniano parę akapitów wcześniej, system dynamicznie dobiera liczbę procesów rozdzielających; jednakże liczba ta nigdy nie przekroczy wartości określonej parametrem MTS_MAX_DISPATCHERS.
Wartość tego parametru zależna jest od widzimisię administratora bazy danych, jednak należy uważać, aby liczba wszystkich procesów istniejących w systemie nie przekroczyła wartości dla tego systemu dopuszczalnej. Wartością domyślną tego parametru jest 5.

MTS_SERVERS - Przy pomocy tego parametru należy określić początkową ilość procesów usługowych. Zasady dotyczące zarządzania przez system procesami usługowymi są podobne do tych, które obowiązują dla procesów rozdzielających. Ich ilość jest dynamicznie zwiększana bądź zmniejszana, w zależności od bieżących potrzeb systemu. Procesy które zbyt długo pozostają w stanie bezczynności są automatycznie usuwane, jednak ich ilość nigdy nie spadnie poniżej tej, określonej przy pomocy parametru MTS_SERVERS. Nie należy zatem przesadzać ze zbyt dużą wartością tego parametru, gdyż takie działanie może doprowadzić do spadku wydajności systemu. Podobnie jak miało to miejsce w przypadku procesów rozdzielających, administrator (bądź użytkownik posiadający uprawnienie ALTER SYSTEM) może 'ręcznie' zmieniać ilość procesów usługowych, bez konieczności restartowania instancji i zmian pliku konfiguracyjnego. W tym celu wystarczy wydać na przykład następujące polecenie ALTER SYSTEM:

ALTER SYSTEM SET MTS_SERVERS = 4

Logicznie rzecz biorąc, minimalną wartością parametru MTS_SERVERS jest liczba 1. Mimo to można ustawić ów parametr na wartość 0, to jednak spowoduje, że Oracle zacznie zakańczać nieaktywne procesy usługowe, nie uruchamiając jednocześnie nowych procesów; gdy liczba istniejących w systemie procesów usługowych spadnie do zera, możliwość korzystania z konfiguracji serwera wielowątkowego zostanie tymczasowo wyłączona.

MTS_MAX_SERVERS - Przy pomocy tego parametru należy określić maksymalną
ilość procesów usługowych, jaka może jednocześnie istnieć w systemie. Choć Oracle dynamicznie uruchamia w miarę potrzeb nowe procesy usługowe, to ich liczba nigdy nie przekroczy tej, określonej parametrem MTS_MAX_SERVERS. Jak widać istnieje tu ścisła analogia do procesów rozdzielających i ograniczającego ich ilość parametru MTS_MAX_DISPATCHERS.
Wartością domyślną parametru MTS_MAX_SERVERS jest 20.

Wartość poszczególnych parametrów serwera w konfiguracji wielowątkowej dobierana jest raczej eksperymentalnie i w ścisły sposób zależy od obciążenia systemu (zarówno od ilości użytkowników łączących się z bazą danych, jak i od stopnia złożoności wykonywanych przez nich zadań). Mimo to istnieją pewne reguły, które pomagają administratorowi określać przybliżoną ilość procesów.
Chcąc poprawnie dobrać początkową ilość procesów rozdzielających (parametr MTS_DISPATCHERS), należy określić średnią liczbę równoczesnych sesji i podzielić tę wartość przez ilość połączeń jaka ma przypaść na pojedynczy proces rozdzielający (oczywiście należy tu uwzględnić sesje korzystające z tego protokołu, dla którego wyliczana jest ilość procesów rozdzielających). Co do maksymalnej liczby procesów rozdzielających (parametr MTS_MAX_DISPATCHERS) to będzie ona wynikiem dzielenia maksymalnej liczby jednoczesnych połączeń przez ilość połączeń przypadającą na pojedynczy proces.
Podobnie wygląda operacja ustalania początkowej i maksymalnej ilości procesów usługowych. Tutaj również należy kierować się wyczuciem, biorąc pod uwagę średnie i maksymalne obciążenie oraz ilość użytkowników bazy danych. Ustalając wartość parametru MTS_MAX_SERVERS należy mieć na uwadze pewne negatywne zjawisko jakie może wystąpić przy zbyt małej wartości tego parametru. Otóż w takiej sytuacji mogą pojawić się tzw. 'sztuczne zakleszczenia' (ang. artificial deadlock). Cóż to takiego? Najlepiej wyjaśnić to na przykładzie: wyobraźmy sobie sytuację, w której parametr MTS_MAX_SERVERS ustawiony jest na wartość 5. Użytkownik połączony z bazą danych zakłada na pewną tabelę blokadę w trybie wyłączności (ang. exclusive lock) (wydając na przykład polecenie LOCK TABLE). W tym celu użytkownik ów korzysta ze współdzielonego procesu usługowego, który jest zwalniany natychmiast po wykonaniu swojego zadania. Po tej operacji inni użytkownicy (załóżmy że jest ich pięciu) próbują uzyskać dostęp do zablokowanej tabeli. Każdy z procesów użytkownika wykorzystuje w tym celu jeden proces usługowy. Użytkownik, który założył blokadę, próbuje zwolnić zablokowane zasoby, jednak nie może tego zrobić, gdyż nie ma już ani jednego wolnego procesu usługowego, który mógłby obsłużyć jego żądanie. W normalnej sytuacji system powinien dynamicznie utworzyć dodatkowy proces, jednak jak wiadomo, ilość wszystkich procesów usługowych nie może przekroczyć wartości określonej parametrem
MTS_MAX_SERVERS. To prowadzi do zakleszczenia, które może "rozwiązać" jedynie administrator, odłączając użytkownika od bazy danych (wówczas proces usługowy zwolniony przez tego użytkownika posłuży do zdjęcia
"problematycznej" blokady).

Jak więc widać, dobór parametrów serwera w konfiguracji wielowątkowej zależy raczej od doświadczenia i 'nosa' administratora, niż od czysto matematycznych wyliczeń (podobnie jest zresztą w przypadku większości parametrów serwera Oracle). Tak czy inaczej po pewnym czasie pracy instancji można zbadać, czy wartości tych parametrów zostały dobrane prawidłowo i wprowadzić ewentualne korekty. W tym celu należy przeanalizować sposób wykorzystania kolejki żądań oraz kolejek komunikatów.

Na początek zajmiemy się oceną
i redukcją rywalizacji o procesy rozdzielające. Zbyt mała ilość tych procesów może prowadzić do wzrostu ich współczynnika zajętości oraz do zwiększenia czasu oczekiwania wyników realizacji zadań w kolejce odpowiedzi, co w efekcie odbije się na dłuższym oczekiwaniu użytkownika na odpowiedź. Aktywność procesów rozdzielających można oceniać na podstawie danych zgromadzonych w dynamicznej tabeli systemowej V$DISPATCHER (jest ona dostępna dla użytkownika SYS oraz dla użytkowników z uprawnieniem systemowym SELECT ANY TABLE). Spośród kolumn tej tabeli szczególną uwagę należy zwrócić na dwie następujące:

IDLE - umieszczany jest tu czas bezczynności określonego procesu rozdzielającego.

BUSY - tu znajduje się czas zajętości danego procesu rozdzielającego.

Wartości w kolumnach IDLE oraz BUSY zapisane są w setnych częściach sekundy.

Po dłuższym czasie pracy instancji, a właściwie aplikacji z której korzystają użytkownicy, można wyznaczyć
całkowity współczynnik zajętości dla wszystkich procesów rozdzielających, współpracujących z określonym protokołem sieciowym. Można w tym celu posłużyć się poniższym zapytaniem:

SELECT network "Protokół",

    SUM (busy) / (SUM (busy) +SUM (idle)) " Całkowity wsp. zajętości "

    FROM v$dispatcher

    GROUP BY network;

gdzie network, to pole zawierające nazwę wykorzystywanego protokołu.

Wynik powyższego zapytania mógłby być na przykład taki:

Protokół Całkowity wsp. zajętości
------------ -------------------------------------
tcp .032111042
decnet .005023104

Analizując powyższe rezultaty, można wysnuć następujące wnioski: Całkowity współczynnik zajętości, tj. procent czasu jaki procesy rozdzielające były zajęte, wynosi dla protokołu DECnet 0,5%, natomiast dla protokołu TCP/IP nieco ponad 3%. Otrzymane wyniki należy rozpatrywać, biorąc pod uwagę efektywny czas pracy użytkowników (zazwyczaj w nocy baza danych nie jest obciążona tak samo jak w dzień). Jeśli przy tym założeniu całkowity współczynnik zajętości dla jakiegoś protokołu przekroczy 50%, to jest to niechybny znak, iż należy zwiększyć ilość procesów rozdzielających.

Pomocna w dobieraniu wartości
parametrów MTS_DISPATCHERS i MTS_MAX_DISPATCHERS może okazać się również analiza dynamicznej tabeli systemowej V$QUEUE (jest ona dostępna dla użytkownika SYS oraz dla użytkowników z uprawnieniem systemowym SELECT ANY TABLE). Zawiera ona bowiem statystyki, odzwierciedlające sposób pracy kolejek odpowiedzi. Jak wiadomo, w kolejkach tych procesy usługowe umieszczają wyniki realizacji zadań, które następnie trafiają do odpowiednich procesów rozdzielających (każdy z takich procesów na swoją własną kolejkę odpowiedzi). Szczególnie ważne są dane gromadzone w dwóch poniższych kolumnach tej tabeli:

WAIT znajduje się tu całkowity czas oczekiwania wszystkich odpowiedzi/żądań, które kiedykolwiek (od momentu uruchomienia instancji) znalazły
się w kolejce.

TOTALQ - tu umieszczana jest całkowita liczba odpowiedzi/żądań, które były umieszczane w kolejce od czasu uruchomienia instancji.

Wartości w kolumnach WAIT oraz TOTALQ zapisane są w setnych częściach sekundy. To, czy wartości znajdujące się w kolumnach WAIT i TOTALQ dotyczą żądań czy też odpowiedzi, zależy od wartości jaka znajduje się w kolumnie TYPE tej tabeli, przy pomocy której określany jest typ kolejki (kolejka żądań bądź kolejka odpowiedzi).

Do monitorowania pracy kolejek odpowiedzi może posłużyć poniższe zapytanie, które pozwala na określenie średniego czasu oczekiwania przez odpowiedź:

SELECT network 'Protokół',

    DECODE (SUM (totalq), 0, 'Brak odpowiedzi',

    SUM (wait) /SUM (totalq) || ' setnych sekundy')

     'Śr. czas oczek. przez odp. '

    FROM v$queue q, v$dispatcher d

    WHERE q. type = 'DISPATCHER'

    AND q. paddr = d. paddr

    GROUP BY network;

gdzie network, to pole zawierające nazwę wykorzystywanego protokołu,

type, to typ "kolejki ('COMMON ' kolejka żądań, 'DISPATCHER' kolejka
odpowiedzi),

paddr, to adres procesu rozdzielającego będącego właścicielem kolejki.

W wyniku realizacji tego zapytania otrzymany zostanie średni czas, jaki wszystkie odpowiedzi oczekiwały w kolejkach, na przesłanie ich do właściwych procesów rozdzielających (a tym samym do procesów użytkownika). Przykładowy wynik tego zapytania mógłby wyglądać na przykład tak:



Protokół Średni czas oczek. przez odp
------------ -------------------------------------
tcp .2647148 setnych sekundy
decnet brak odpowiedzi

Z powyższych wyników można wyciągnąć wniosek, że dla protokołu TCP/IP odpowiedzi oczekiwały w kolejce średnio przez 0,26 sekundy, natomiast dla protokołu DECnet nie było w kolejce żadnych odpowiedzi.

Jeśli czas oczekiwania w przypadku określonego protokołu ustawicznie wzrasta podczas pracy aplikacji, wówczas należy rozważyć decyzję o zwiększeniu ilości procesów rozdzielających.

Po określeniu prawidłowej liczby procesów rozdzielających, można przystąpić do redukowania
rywalizacji o procesy usługowe. Do tego celu również posłuży dynamiczna tabela systemowa
V$QUEUE oraz dane zgromadzone w jej kolumnach WAIT i TOTALQ. Jednak tym razem warunek WHERE dotyczył będzie wartości 'COMMON' w kolumnie TYPE, która to wartość odpowiada kolejce żądań (jak wiadomo, ta kolejka obsługiwana jest przez procesy usługowe). Oto zapytanie pozwalające określić
średni czas oczekiwania przez żądania:

SELECT DECODE (totalq, 0, 'Brak odpowiedzi',

wait/totalq || ' setnych sekundy')

'Śr. czas oczek. przez żądania'

FROM v$queue

WHERE type = 'COMMON';

(Należy zauważyć, że nie występuje tutaj charakterystyczna dla poprzedniego zapytania funkcja SUM. Otóż dzieje się tak dlatego, że istnieje tylko jedna kolejka żądań, w przeciwieństwie do wielu kolejek odpowiedzi).

Zapytanie to zwróci średni czas jaki żądania musiały spędzić w kolejce, w oczekiwaniu na pobranie ich i realizację przez jeden z procesów usługowych. Przykładowy rezultat powyższego zapytania mógłby wyglądać następująco:

Średni czas oczek. przez żądanie
-------------------------------------------
.087176 setnych sekundy

Można stąd wysnuć wniosek, że każde z żądań oczekiwało w kolejce na obsłużenie średnio przez 0,08 setnych sekundy.

Jeśli liczba procesów usługowych tworzonych dynamicznie przez serwer osiągnęła wartość graniczną określoną parametrem MTS_MAX_SERVERS, a średni czas oczekiwania żądań w kolejce rośnie, należy niezwłocznie zwiększyć wartość parametru MTS_MAX_SERVERS. Skąd wiadomo jaka ilość procesów usługowych pracuje aktualnie w systemie? Otóż wystarczy zadać następujące zapytanie do dynamicznej tabeli systemowej V$SHARED_SERVER:

SELECT COUNT (*) "Procesów usługowych"

FROM v$shared_server

WHERE status! = 'QUIT';

gdzie status, to stan procesu usługowego. Wartość 'QUIT' oznacza proces zakończony.

Mimo tych wszystkich zalet konfiguracji serwera wielowątkowego, istnieją sytuacje w których nie powinno się, a wręcz nie można z niej korzystać. Do tego typu wyjątków należy uruchamianie i wyłączanie instancji oraz wykonywanie odtwarzania bazy danych. W przypadku połączenia administratora ze współdzielonym procesem usługowym, system nie pozwoli mu zamknąć instancji, zgłaszając błąd. Nie powinno się również używać konfiguracji MTS w przypadku zamiaru wykonywania zadań wsadowych (zadania takie mocno obciążają system, zatem powinny one mieć swoje własne dedykowane procesy usługowe, co pozwoli na szybszą ich realizację). Korzystanie z serwera w konfiguracji MTS nie uniemożliwia łączenia się z dedykowanym procesem usługowym. Oracle jest tutaj bardzo elastyczny, pozwala bowiem różnym użytkownikom korzystać jednocześnie z obu konfiguracji. Chcąc połączyć się z bazą danych
w konfiguracji z dedykowanym procesem usługowym, należy dodać do pliku tnsnames.ora (do odpowiedniego connect string) następującą klauzulę: SRVR=DEDICATED. Po takiej operacji zapis w tym pliku może wyglądać na przykład następująco:

multi =

    (DESCRIPTION =

     (ADDRESS = (PROTOCOL = TCP) (Host = Candy) (Port = 1521))

      (CONNECT_DATA = (SID = baza)

      SRVR = DEDICATED))
)

To tyle na temat systemu Oracle w konfiguracji serwera wielowątkowego. Każdy DBA powinien sam rozważyć czy warto stosować tę konfigurację w obsługiwanym przezeń systemie. Jednak biorąc pod uwagę niewątpliwe zalety, łatwość konfigurowania i strojenia oraz elastyczność jaką zapewnia to rozwiązanie, staje się ono naprawdę warte uwagi.

Piotr Listosz