Tomcat

From Training Material
Jump to navigation Jump to search

Template:Tomcat Links Nobleprog.svg

Apache Tomcat and Java EE Administration

title
Apache Tomcat and Java EE Administration
author
Stefan Mucha

JVM

JVM, JRE, JDK - co to? czym to się je? ⌘

JVM to akronim dla Java Virtual Machine, tj. Wirtualna Maszyna Javy. Aby aplikacja napisana w języku Java mogła być uruchomiona, pliki zawierające kod źródłowy muszą być skompilowane. Kompilacja polega na przetłumaczeniu programu napisanego w Javie na kod wykonywalny, tzw. Bytecode. Kompilację wykonujemy przy użyciu specjalnego narzędzia, tzw. kompilatora.

Jednak Bytecode to nie jest ciąg instrukcji procesora (jednostki centralnej komputera), tylko ciąg instrukcji specjalnego języka. Języka którego instrukcje wykonywane są właśnie przez Wirtualną Maszynę Javy (JVM). JVM jest więc w pewnym sensie procesorem wykonującym skompilowany kod języka Java.

JRE to akronim dla Java Runtime Environment, tj. Środowisko Uruchomieniowe Javy. JRE składa się z Wirtualnej Maszyny Javy (tzn. zawiera JVM) oraz zestawu klas i narzędzi niezbędnych dla uruchamiania programów napisanych w Javie.

JDK to akronim dla Java Development Kit, tj. Pakiet Programisty Javy. JDK zawiera Środowisko Uruchomieniowe Javy (tzn. JRE) oraz narzędzia niezbędne do implementacji i kompilacji aplikacji napisanych w języku Java.

Podsumowując - jeśli chcemy implementować, lub chodziażby kompilować, programy napisane w Javie to musimy zainstalować JDK. Jeśli nie jesteśmy programistami i chcemy jedynie uruchamiać skompilowane już aplikacje to wystarczy nam JRE. JVM nie występuje w formie samodzielnej a jedynie jako część większej całości - JRE albo JDK.

Wstęp do programowania JAVA⌘

Klasa⌘

Klasa jest podstawowym elementem składowym każdej aplikacji zaimplementowanej w języku Java. W niewielkim uproszczeniu, program w Javie to właśnie pewien zbiór klas. Definicję każdej z klas umieszczamy w osobnym pliku, który to plik musi nazywać się tak samo jak klasa i mieć rozszerzenie java. Patrząc od drugiej strony, program napisany w Javie jest więc kolekcją plików z rozszerzeniem java, przy czym każdy z tych plików zawiera definicję klasy.

Powyższe wyjaśnienie jest pewnym uproszczeniem rzeczywistości, ale jest wystarczająco bliskie prawdzie, by póki co przyjąć że tak właśnie jest.

Klasa jest to definicja pewnego rodzaju bytów. Bytów które posiadają określone cechy, zachowanie i umiejętności. Pragmatycznie rzecz ujmując klasa to pewien nazwany zbiór metod i zmiennych.

Klasa jest definicją bytu, albo mówiąc inaczej typem bytu, ale dopiero instancja klasy, tj. obiekt, odzwierciedla konkretny byt.

Przykład użycia klasy ⌘

Implementując aplikację w języku Java definiujemy nowe klasy, ale także – a może przede wszystkim – używamy klas bibliotecznych, tj. zaimplementowanych przez kogoś innego. Szczególną biblioteką, tj. zbiorem klas jest tzw. biblioteka standardowa. Biblioteka standardowa zawiera klasy implementujące podstawowe funkcjonalności, np. klasy umożliwiające manipulowanie plikami dyskowymi. Klasy biblioteki standardowej opisane są w ramach specyfikacji Java SE.

Poniższy fragment kodu demonstruje użycie klasy File pochodzącej z biblioteki standardowej (tj. z biblioteki Java SE). Klasa File reprezentuje dowolny zbiór dyskowy, tj. plik lub katalog. Aby sprawdzić czy zbiór dyskowy określony przez pewną ścieżkę dostępu – w naszym przypadku C:/mydir/file.txt – istnieje i czy jest to plik wystarczy utworzyć obiekt klasy File, a następnie wywołać na tym obiekcie metodę isFile(). Rezultat wywołania metody isFile() wykorzystujemy aby wyświetlić stosowny komunikat.

File file = new File("C:/mydir/file.txt");
if (file.isFile())
System.out.println("Plik znaleziono!");
else
System.out.println("Wskazany plik nie istnieje!");

Pliki JAR ⌘

Ogólnie mówiąc pliki JAR są archiwami (podobnymi do plików zip, rar itd) zawierającymi programy Javy. Charakterystyczne jest to, że oprócz spakowanych plików (źrodłowych, skompilowanych klas,..) zawierają one inforacje o sposobie uruchomienia programu. Informacje te zawarte są w tzw. manifeście - pliku manifest.mf umieszczonym w katalogu META archiwum.

Tworzenie plików JAR⌘

Tworzenie plików JAR z poziomu Eclipse


Aby utworzyć plik JAR z poziomu Eclipse należy:

  1. Wybrać odpowiedni projekt, kliknąć na nim prawym klawiszem myszy i wybrać opcję Export...
  2. Wybrać opcję Java-> JAR File i kliknąć Next
  3. Wybrać zasoby, które mają być umieszczone w pliku JAR; następnie wybrać lokalizację i nazwę dla tworzonego pliku JAR, (Next)
  4. W widoku JAR Packaging Options można zaakceptować domyślne ustawienia klikając Next
  5. Zaznaczyć pole "Generate the manifest file", a następnie kliknąć Browse (obok pola MainClass ) i wybrać klasę, od której ma być zaczynane uruchamianie programu - klasa musi posiadać metodę main()!!!
  6. Po kliknięciu Finish w wybranej lokalizacji powinien pojawić się nowy plik JAR.

Uruchamianie plików JAR⌘

Plik JAR można uruchomić na kilka sposobów (działanie zależne ustatwień od systemu operacyjnego):

  • dwukrotnie klikając na jego ikonie
  • klikając prawym klawiszem i wybierając odpowiednią opcję z menu kontekstowego
  • z linii poleceń poprzez wpisanie: java -jar NazwaArchiwum.jar

Java SE, JAVA EE⌘

Java SE, J2SE to skrót dla Java Standard Edition (oficjalnie Java Platform™, Standard Edition), czyli zestaw specyfikacji technologii podstawowych, wchodzących w skład platformy Java.
Do wersji 1.5 platformy używano dla tego samego bytu nazwy Java 2 Standard Edition (J2SE). J2SE jest więc nazwą starszych wersji specyfikacji Java SE.

Architektura Java EE

Warstwy ⌘

Na rysunku 1 przedstawiono dwie wielowarstwowe aplikacje Java EE podzielone na warstwy opisane w poniższej liście:

  • Warstwa klienta (ang. client tier) pracująca na maszynie klienta.
  • Warstwa sieci (ang. web tier) pracująca na serwerze Java EE.
  • Warstwa logiki biznesowej (ang. business tier) pracująca na serwerze Java EE.
  • Warstwa danych (ang. enterprise information system ? EIS tier) pracująca na serwerze bazy danych

Administracja serwerem Glassfish rys.1

Architektura wielowarstwowa ⌘

  • Warstwa klienta może się składać z jednego, bądź też kilku z podanych rozwiązań:
  • Klient webowy. Składa się z dynamicznej strony Web zbudowanej przy użyciu języków znaczników, takich jak HTML, czy XML oraz przeglądarki internetowej, która prezentuje dane otrzymane z serwera. Klienci tacy często nazywani są cienkimi klientami (ang. thin client) z uwagi na fakt, że nie wykonują oni z reguły złożonych zadań biznesowych, czy zapytań do baz danych. Operacje takie delegowane są przez nich do komponentów pracujących na serwerach Java EE
  • Applet. Jest to mała aplikacja napisana w języku Java, która wykonywana jest na zainstalowanej w przeglądarce internetowej wirtualnej maszynie Java.
  • Aplikacja kliencka. Uruchamiana jest ona na maszynie klienta i jak to widać na rysunku 2-2 komunikuje się bezpośrednio z komponentami logiki biznesowej z pominięciem warstwy sieci. Z reguły posiada graficzny interfejs użytkownika (ang. grafical user interface, GUI), co umożliwia wykonywanie zadań wymagających wykorzystania możliwości nie oferowanych przez przeglądarki internetowe. Aplikacje klienckie napisane w językach innych niż Java również mogą komunikować się z serwerami Java EE.
  • JavaBeans. JavaBeans są to klasy posiadające pewne właściwości oraz metody get i set, które pozwalają te właściwości pobierać i ustawiać. Mogą one istnieć zarówno na poziomie klienta, jak i serwera. Wspomagają przepływ informacji pomiędzy aplikacja kliencką, serwerem oraz bazą danych.
  • Warstwa sieci składa się z serwletów (ang. servlet) lub stron tworzonych za pomocą technologii JSP i/lub JSF. Serwlety są to klasy, które dynamicznie przetwarzają żądania (ang. requests) wysyłane przez przeglądarkę internetową do serwera i konstrują odpowiedzi (ang. responses). Strony JSP to dokumenty tekstowe, które w kodzie HTML umożliwiają wstawienie fragmentów języka JAVA. Kod taki przed wysłaniem do użytkownika jest przetwarzany przez serwer do postaci kodu HTML. Umożliwia to bardziej naturalne podejście do tworzenia statycznej treści niż w przypadku serwletów. JSF jest zbudowana na bazie serwletów i stron JSP, w pewnym sensie je łączy udostępniając interfejs użytkownika.
  • Warstwa logiki biznesowej jest to miejsce, w którym tak na prawdę odbywa się przetwarzanie danych i rozwiązywanie problemów stawianych przed aplikacją, takich jak np. obliczenie ile klient danego banku ma jeszcze kredytu do spłaty. Rysunek 2-2 przedstawia jak warstwa logiki biznesowej odbiera informacje, jeżeli potrzeba przetwarza je i przekazuje do warstwy danych w celu ich zapisania. Warstwa ta pobiera też dane z warstwy danych i przekazuje je dalej w celu prezentacji klientowi.
  • Warstwa danych - jej zadaniem jest odpowiednie utrwalenie przekazanych jej danych, oraz ich odczytanie i zwrócenie, gdy zostanie do niej wysłane odpowiednie żądanie.

Glassfish Administracja rysunek 2

Pomimo faktu, że aplikacje Java EE mogą zawierać trzy, lub cztery warstwy, tak jak to widać na rysunku 2-2 przyjęło się, że aplikacje Java EE są trzywarstwowe, z uwagi na fakt, że pracują one w trzech lokacjach: maszynie klienta, serwerze Java EE oraz serwerze bazy danych. Aplikacje trzywarstwowe pracujące w ten sposób rozwijają standardową architekturę dwuwarstwową poprzez dodanie wielowątkowego serwera aplikacji pomiędzy klientem a serwerem baz danych.

Komponenty ⌘

Aplikacje Java EE tworzone są z komponentów. Komponenty są to samowystarczalne jednostki oprogramowania dostarczające pewne funkcje i mające możliwość komunikowania się z innymi komponentami. Zawierają one w sobie odpowiednie klasy oraz wszelkie inne niezbędne pliki. Tworzą one pewnego rodzaju cegiełki, z których składa się aplikacje. Specyfikacja Java EE definiuje następujące komponenty:

  • Aplikacje klienckie i aplety pracujące w warstwie prezentacji.
  • Serwlety, JavaServer Faces (JSF) oraz JavaServer Pages (JSP) będące komponentami webowymi i pracujące na serwerze.
  • Komponenty Enterprise JavaBeans (EJB), zwane też enterprise beans, będące komponentami biznesowymi pracującymi na serwerze.

Komponenty Java EE pisane są w języku JAVA i kompilowane są tak samo, jak wszystkie inne programy napisane w tym języku. Różnica pomiędzy komponentami Java EE, a standardowymi klasami Java polega na tym, że działają one i są zarządzane przez kontenery Java EE.



JMS (Java Messaging Service)⌘

Klienci (fragmenty systemu, aplikacje itp.) w środowisku rozproszonym mogą współdziałać poprzez wymianę komunikatów, przy czym:

  • klient-producent wysyła komunikat
  • klient-konsument odczytuje komunikat
  • obaj klienci nie muszą działać równocześnie
  • żaden z nich nie musi nic "wiedzieć" o budowie, kodzie itp. drugiego

Współdziałanie aplikacji poprzez wymianę komunikatów ma tę zaletę, że uniezależnia kody programów od siebie ("loose coupling") Ten sposób programowania realizowany jest na różnych platformach poprzez różne technologie - np. IBM MQseries.
W środowisku Javy mamy do dyspozycji JMS (Java Messaging Service).
Java Messaging Service to API (zestaw interfejsów), które zapewnia m.in.:

  • synchroniczną wymianę komunikatów (klient czeka na komunikat, spodziewa się go),
  • asynchroniczną wymianę komunikatów (JMS wysyła komunikat do klienta, gdy tylko komunikat się pojawi, a klient nie musi sprawdzać czy komunikat jest, obsługuje go na zasadzie "callback"),
  • niezawodność - gwarancję, że komunikat zostanie "dostarczony" raz i tylko raz.

Architektura JMS ⌘

Składowe aplikacji JMS

  • serwis (JMS provider) implementuje interfejsy i dostarcza narzędzi administrowania
  • klienci - tworzą, wysyłają i odbierają komunikaty
  • obiekty administrowane - destynacje oraz fabryki połączeń (są zwykle tworzone i konfigurowane przez narzędzia administracyjne, ale również istnieje programistyczne API do tych celów)

JMS 1.gif
Destynacje i domeny

Destynacja JMS jest miejscem w którym nadawca umieszcza wiadomości i z którego odbiorca odczytuje wiadomości.

Dwie możliwe domeny (rodzaje destynacji):

kolejka (Queue) - Point-to-Point za pośrednictwem kolejki komunikatów, nadawca wysyła do określonej nazwanej kolejki (destynacji), odbiorca - odbiera komunikat z tej kolejki.
JMS 2.gif

  • każdy komunikat może być odebrany tylko przez jednego odbiorcę;
  • odbiorca może odebrać wiadomość niezależnie od tego czy nadawca działa czy też juz zakończył działanie;
  • zasadą jest, że odbiorca potwierdza odebranie wiadomości, co zapewnia, że nie będzie mu ona przysłana po raz kolejny.

Temat (Topic) - zasada publikacji i subskrypcji.
JMS 4.gif

  • każda wiadomość może mieć wielu odbiorców (subskrybentów tematu),
  • w danym temacie może publikował wielu nadawców,
  • odbiorca może odbieracz tylko te wiadomości z danego tematu, które zostały opublikowane po zapisaniu się przez niego do subskrypcji

Uwaga: wersja 1.1 JMS pozwala na oprogramowanie obu typów komunikacji za pomocą tych samych interfejsów.

Architektura aplikacji JMS
JMS 3.gif
ConnectionFactory - tworzy połączenie do dostawcy serwisu JMS. Destination - określa destynację nadawanych i odbieranych wiadomości.

Instalacja Serwera⌘

  • Pobieramy plik apache-tomcat-5.5.33.exe ze strony http://tomcat.apache.org
  • Uruchamiamy plik apache-tomcat-5.5.33.exe w celu rozpoczęcia instalacji

serwera aplikacji. Klikamy przycisk Next >.

Tomcat1.png

Zapoznajemy się z licencją Apache Licence na której rozpowszechniane jest oprogramowanie Apache Tomcat. Klikamy przycisk I Agree.

Tomcat2.png

Wybieramy rodzaj instalacji Normal. Rozwijamy gałąź Tomcat. Mamy możliwość zainstalowania opcji Service która powoduje automatyczne uruchamianie serwera aplikacji w momencie uruchomienia systemu operacyjnego oraz opcję Native służącą do poprawy wydajności działania serwera aplikacji w środowisku produkcyjnym. Zaznaczamy chęć doinstalowania przykładów aplikacji internetowych. Klikamy przycisk Next >.

Tomcat3.png

Wskazujemy katalog instalacyjny dla serwera aplikacji (można pozostawić domyślną lokalizację). Klikamy przycisk Next >.

Tomcat4.png

Wskazujemy port TCP/IP na którym ma być uruchomiony (nasłuchiwać) serwer aplikacji oraz nazwę i hasło użytkownika, który będzie miał prawo administrowania serwerem aplikacji. Klikamy przycisk Next >.

Tomcat5.png

Wskazujemy lokalizację środowiska Java Runtime Environment (koniecznie w wersji 5.0). Klikamy przycisk Install.

Tomcat6.png

Upewniamy się, że opcja Run Apache Tomcat jest zaznaczona. Klikamy przycisk Finish

Tomcat8.png

Czekamy na uruchomienie usługi. Upewniamy się, że w pasku systemowym jest obecna ikona Apache Tomcat.

Tomcat9.png

Zarządzanie serwerem⌘

Katalogi serwera i ich znaczenie⌘

  • bin - aplikacje startujące serwer, najważniesze binaria.
  • conf - pliki (głównie xml) zawierające dyrektywy konfiguracji serwera
  • common - (wersja Tomcat 5.5 lub wcześniejsze) biblioteki serwera - *.jar oraz wersje językowe serwera
  • lib - (wersja Tomcat 6 i późniejsze) biblioteki serwera - *.jar
  • logs - logi serwera (administracja, obsługa)
  • server - (wersja Tomcat 5.5 lub wcześniejsze) moduł administracyjny, niedostępny w podstawowej konfiguracji (instalujemy go pobierając rozszerzenie: apache-tomcat-5.5.xx-admin.zip, które rozpakowujemy w katalogu $CATALINA_HOME)
  • temp - pliki tymczasowe serwera
  • webapps - katalog z którego w domyślnej konfiguracji uruchamiane są aplikacje.
  • work - skompilowane źródła naszych aplikacji.

Konfiguracja serwera⌘

Pliki konfiguracyjne XML Dwa najważniejsze pliki konfiguracyjne, które są wymagane aby Tomcat mógł być uruchomiony nazywają server.xml i web.xml. Domyślnie pliki te znajdują się w $CATALINA_HOME/conf/server.xml i $CATALINA_HOME/conf/web.xml.

Server.xml⌘

Server.xml jest to główny plik konfiguracji serwera Tomcat i jest odpowiedzialny za określenie początkowej konfiguracji serwera na starcie, a także określenie sposobu i kolejności, w której Tomcat i buduje kontener dla uruchamiania aplikacji. Elementy pliku server.xml znajdują się w pięciu podstawowych kategoriach - Top Level Elements, Connectors, Containers, Nested Components, and Global Settings. Wszystkie elementy w obrębie tych kategorii ma wiele cech, które mogą być stosowane do dokładnej regulacji ich zadań. Najczęściej, gdy trzeba dokonać większych zmian w instalacji Tomcata, takich jak np: liczby określające porty aplikacji, server.xml trzeba edytować server.xml.

Można znaleźć obszerną dokumentację dla tych opcji na stronach dokumentacji Apache Tomcat, ale podam kilka najważniejszych informacji.

Top Level Elements⌘
Server⌘

Ten element definiuje pojedynczy serwer Tomcat i zawiera Logger i elementy konfiguracyjne ContextManager. Dodatkowo elementem Server wspiera atrybuty "port", "shutdown", oraz "className".

Atrybut port jest używany do określenia, który portu, na którym Tomcat powinien słuchać poleceń zamykania systemu. Atrybut shutdown definiuje ciąg poleceń do nasłuchiwania na określonym porcie, który wywołuje zamknięcie. Atrybut className określa, które wywolanie klasy Java ma być stosowane.

Service⌘

Ten element, który może być zagnieżdżony w elemencie serwera, jest używany do umieszczenia jednej lub wielu dyrektyw Connector, które dzielą ze sobą ten sam element silnika. Głównym zadaniem tego składnika jest określenie składników jako pojedyncze usługi. Nazwa usługi, która pojawi się w logach jest określona za pomocą elementu service "name" atrybutu.

Connectors⌘

W celu zagnieżdżenia kilku wywołań connectora (różne porty), dla tagu services, pozwalamy Catalina do przekazania żądania z tych portów do jednego modułu - wątku silnika w celu przetworzenia. Tomcat pozwala zdefiniować zarówno HTTP i złącza AJP.

HTTP Connector⌘

Element ten stanowi łącznik HTTP 1.1 i zapewnia działanie Serwera Tomcat z autonomiczną funkcjonalnością serwera WWW. Oznacza to, że oprócz wykonywania serwletów i JSP, Catalina jest w stanie nasłuchiwań na określonych portach TCP. Każdy zdefiniowany Connector definiuje pojedynczy port TCP Catalina i powinien słuchać żądań HTTP. Podczas konfigurowania Connectorów HTTP, należy zwracać szczególną uwagę na atrybuty "minSpareThreads", "maxThreads", i "acceptCount". Atrybut "MaxThreads" ma szczególne znaczenie, bo kontroluje maksymalną liczbę wątków, które mogą być tworzone do obsługi żądań. Ustawienie tej wartości na zbyt niską wartość powoduje zbyt szybkie odrzucanie przychodzących połączeń.

AJP Connector⌘

Element ten stanowi Connector, który jest w stanie komunikować się protokołem AJP. Głównym zadaniem tego elementu jest pomoc Tomcatowi w zintegrowaniu z instalacją Apache. Nie używamy tej funkcjonalności, jeśli planujesz używać Apache jako statyczny serwer przed Tomcatem. Technika ta ma na celu uwolnić więcej zasobów do dynamicznego generowania stron i równoważenia obciążenia, więc jeśli szybko chcesz poprawić wydajność aplikacji, to AJP jest dobrym pomysłem. Złącza AJP mogą być również wykorzystywane do optymalizacji żądań po SSL.

Containers⌘

Elementy te są wykorzystywane przez Catalina do kierowania żądań do odpowiednich aplikacji.

Context⌘

Element ten reprezentuje pojedynczą aplikację internetową, i zawiera informacje o ścieżce do kierowania żądań,do odpowiednich zasobów aplikacji. Kiedy Catalina otrzymuje żądanie, próbuje dopasować najdłuższy URI do ścieżki danym kontekście, aż znajdzie odpowiedni element, aby obsłużyć żądanie. Element Kontekst może mieć maksymalnie jeden zagnieżdżony element: na przykład przykład element Loader , manager, Realm, resources i WatchedResource. Chociaż Tomcat pozwala na zdefiniowanie kontekstu w "TOMCAT-HOME/conf/server.xml", to powinno się tego generalnie unikać, ponieważ te globalne ustawienia konfiguracyjne nie mogą być ładowane bez restartu Tomcata, co sprawia, że ​​edytowanie atrybutów kontekstu bardziej inwazyjne niż to konieczne.

Engine⌘

Element ten jest stosowany w połączeniu z jednym lub więcej Connectorem, i jest odpowiedzialny za przetwarzanie wszystkich żądań związane z obsługą macierzystego Elementu. Element silnika może być używany tylko, jeśli jest zagnieżdżony w elemencie Services. Należy zadbać by został zdefiniowany atrybut "defaulthost" który definiuje Hosta odpowiedzialnego za kierowanie żądań na serwerze - nie jest skonfigurowany w server.xml. Atrybut ten musi się zgadzać z nazwą jednego z elementów Hosta zagnieżdżonych wewnątrz elementu silnika. Ponadto, ważne jest, aby przypisać unikalną, logiczną nazwę do każdego z elementów silnika, przy użyciu atrybutu "Name", wtedy gdy element Server w pliku server.xml zawiera wiele elementów Services.

Host⌘

Element ten, jest zagnieżdżony wewnątrz elementu silnika, służy do kojarzenia nazw sieciowych serwerów z serwerami Catalina. Ten element będzie działać poprawnie, jeśli wirtualny host jest zarejestrowany w usłudze DNS zarządzających danej domeny.

Jedną z najbardziej przydatnych funkcji elementu hosta jest jego zdolność do zawierania zagnieżdżonych elementów "Alias", które są wykorzystywane do określenia nazw sieci, które należy rozwiązać.

Cluster⌘

Element Cluster jest używany przez Tomcat, aby zapewnić replikację atrybutów kontekstu, replikację sesji. Może być zagnieżdżony w każdym silniku lub elemencie nadrzędnym. Elementy Manager, Channel, Valve, Deployer i elementy ClusterListener są zagnieżdżone wewnątrz niego. Więcej informacji na temat tych elementów, i jak są one używane można znaleźć na stronie konfiguracji Apache Tomcat. Mimo, że ten element jest wysoce konfigurowalny, domyślna konfiguracja jest zazwyczaj wystarczy do zaspokojenia potrzeb większości użytkowników.

Nested Components (Elementy zagnieżdżone)⌘

Te elementy są zagnieżdżone wewnątrz elementów kontenerowych zdefiniować dodatkowe funkcjonalności.

Listeners⌘

To dyrektywy, które mogą być zagnieżdżone wewnątrz serwera, silnika, hosta, który wykona akcję, gdy wystąpi określone zdarzenie. Podczas gdy większość składników posiadają atrybut className, aby wybrać różne implementacje tego elementu, element detektora jest wyjątkowy, istnieje wiele unikalnych implementacji innych niż domyślny. Wszystkie te implementacje, które wymagają elementów listener mogą być zagnieżdżone w elemencie Server. Tak więc prawidłowe ustawienie tego atrybutu jest ważne. Obecnie dostępne są APR Listener Lifecycle, Listener Jasper, Listener Lifecyle Server, JMX Remote Listener Lifecycle i Memory JRE Leak Prevention Listener.

Global Naming Resources⌘

Element ten jest używany do określenia globalnego nazewnictwo Java i interfejsu directory (JNDI) do zasobów na określonym serwerze. Jeśli chcesz, możesz zadeklarować właściwości JNDI do <resource-ref> i <resource-env-ref> i łącząc się je za pomocą <ResourceLink>. Wyniki tej metody są równoważne z <resource-ref> elementów w aplikacji "/ WEB-INF/web.xml" pliku. W przypadku korzystania z tej techniki, należy zdefiniować dodatkowe parametry potrzebne do określenia i skonfigurowania fabryki (factory) obiektu i jego właściwości.

Realm⌘

Ten element, który może być zagnieżdżony wewnątrz każdego elementu Container, definiuje bazę danych zawierającą nazwy użytkowników, hasła, i role. Zagnieżdżone wewnątrz hosta lub elementu silnika, zdefiniowane w elemencie Realm są dziedziczone przez wszystkie kontenery niższego szczebla. Ważne jest, aby poprawnie ustawić "className". Ustawienia te stosowane są w celu wystawienie Catalina do innych systemów zarządzania bezpieczeństwem użytkownika, takich jak JDBC, JNDI i DataSource.

Resources⌘

Ten element ma jedno proste zadanie - kierowanie Catalina do zasobów statycznych wykorzystywanych przez aplikacje internetowe. Zasoby te obejmują klasy, HTML i pliki JSP. Wykorzystując ten element pozwalamy Tomcatowi na dostęp do plików znajdujących się w innych miejscach niż w systemie plików, np. zasobów zawartych w plikach WAR archiwów i baz danych JDBC. Ważne jest, aby pamiętać, że ta technika pozwala aplikacji internetowej na dostęp do zasobów znajdujących się poza systemem plików. Może być używana tylko w przypadku, o którym mowa.

Valve⌘

Elementy Valve są zagnieżdżone wewnątrz silnika, hosta, i elementów Context, by przesłać poszczególne funkcje w potoku przetwarzania żądań. Jest to bardzo uniwersalny mechanizm. Zaworki mają szerokie spektrum zastosowań, od uwierzytelnienia do filtrów błędów dla WebDAV. Wiele z tych typów zaworów może być zagnieżdżone. Trzeba wiedzieć, zwracając uwagę na ten element, że atrybut "className" jest niezbędny.

Web.xml⌘

Plik ten pochodzi ze specyfikacji Servlet i zawiera informacje używane do instalowania i konfigurowania komponentów aplikacji internetowych. Podczas konfigurowania serwera Tomcat po raz pierwszy, jest to miejsce gdzie można definiować mapowania serwletów do centralnych elementów, takich jak JSP. Różnicą w obsłudze tego pliku przez serwer Tomcat jest to, że użytkownik ma możliwość wykorzystania TOMCAT-HOME/conf/web.xml, by zdefiniować wartości domyślne dla wszystkich kontekstów. Jeśli ta droga jest wykorzystywana, Tomcat użyje TOMCAT-HOME/conf/web.xml w podstawowej konfiguracji, które z kolei mogą być nadpisane przez specyficzne wpisy dla aplikacji w plikach WEB-INF/web.xml.

Inne ważne pliki konfiguracyjne⌘

Jak można się domyślić, gdy Tomcat uruchomiony jest po raz pierwszy - ustawione mamy domyślne listy ról, nazwy użytkowników i hasła. UserDatabaseRealm Tomcat będą używać do uwierzytelniania wpisów, które można znaleźć w tomcat-users.xml. Jeśli chcesz uzyskać dostęp do każdego z narzędzi administracyjnych, które są pakowane z Tomcat, można edytować ten plik, aby dodać admina i dostęp do menedżera. Ustawienia domyślnego kontekstu, stosowane do wszystkich wdrożonych aplikacjach swojej instancji Tomcata, można ustawiać w pliku context.xml. Plik catalina.policy, który zastępuje plik java.policy dostarczone wraz z wybranym JDK, zawiera ustawienia uprawnień dla elementów serwera Tomcat. Można edytować ten plik ręcznie lub przy pomocy policytool, zapakowanym wraz z aplikacjami Java 1.2 lub późniejszą dystrybucją.

Zmienne środowiskowe⌘

Podczas konfigurowania serwera Tomcat po raz pierwszy, ustawianych jest kilka zmiennych środowiskowych, które powinny być modyfikowane w zależności od potrzeb.

JAVA_OPTS⌘

Korzystanie z tej zmiennej, można określić rozmiar sterty JVM. Ustawienie odpowiedniej wartości dla tej zmiennej jest niezbędne podczas wdrażania nowej aplikacji, które mogą wymagać więcej rozmiar heap, aby funkcjonować poprawnie. Znalezienie odpowiednich wartości dla tych ustawień może pomóc wyeliminować lub zmniejszyć awarie aplikacji.

CATALINA_HOME⌘

Zmienna określa lokalizację instalacji Tomcata. Skrypty startowe Tomcat próbują odszukać wartość tej zmiennej, ale to jest dobry pomysł, aby po prostu ustawić go na odpowiednią , znaną sobie wartość i uniknąć problemów.

CATALINA_OPTS⌘

Zmienna ta służy do ustawiania różnych opcji specyficznych Tomcata. Zmienna ta może być użyta do ustawienia zmiennych środowiskowych, które zastępują JAVA_OPTS.

Tomcat Manager⌘

Uruchamiamy przeglądarkę internetową i łączymy się z adresem http://localhost:8080. Po kliknięciu na odnośnik Tomcat Manager w lewej górnej części okna. Wprowadzamy nazwę i hasło użytkownika, którego stworzyliśmy podczas instalacji.

Tomcat10.png

Okno przedstawia listę wszystkich aplikacji, które są aktualnie zainstalowane w serwerze aplikacji. Kliknij prawym przyciskiem myszy na odnośniku /jsp-examples i wybierz opcję Otwórz w nowym oknie. Możemy poświęcić chwilę na obejrzenie prostych przykładów zastosowania języka JSP, plików znaczników, dokumentów JSP XML, i innych.

Zarządzanie aplikacjami na serwerze⌘

Tomcat11.png

Następnie wracamy do okna głównego panelu zarządzania aplikacjami i wybieramy komendę Stop odnoszącą się do aplikacji /jsp-examples. W okienku pop-up naciskamy przycisk OK. Wróć do okna z przykładami JSP i odśwież zawartość okna przeglądarki.

Tomcat12.png

Manager wykonał polecenie Undeploy.

Deployowanie plików *.war⌘

Zainstalujemy teraz przykładową aplikację internetową przygotowaną w postaci gotowego archiwum WAR (Web Archive). W tym celu należy przejść do okna zarządcy serwera aplikacji. Sekcja Deploy pozwala na zainstalowanie aplikacji spakowanej w postaci pliku *.war umieszczonej po stronie serwera lub umieszczonej na komputerze lokalnym. Znajdź pole Select WAR file to upload i kliknij przycisk Przeglądaj… Przejdź następnie do katalogu %CATALINA_HOME%\webapps\tomcatdocs\ appdev\sample (zmienna %CATALINA_HOME% wskazuje na katalog instalacji serwera Tomcat) i zaznacz plik sample.war. Kliknij przycisk Otwórz. Kliknij przycisk Deploy.

Tomcat13.png

Na liście aplikacji zobaczymy nową pozycję o nazwie /sample, w którą oczywiście klikamy, aby obejrzeć nsze dzieło :)

Tomcat14.png

Zobaczmy teraz, jak aplikacja /sample jest fizycznie zlokalizowana na dysku. Przejdź do katalogu %CATALINA_HOME%\webapps. To jest katalog zawierający wszystkie aplikacje zainstalowane w serwerze aplikacji. Archiwum sample.war zostało załadowane właśnie tutaj. Pierwsze odwołanie do adresu URL http://localhost:8080/sample spowodowało automatyczne rozpakowanie tego pliku. Przejdź do katalogu sample. Katalog images zawiera wykorzystany na jednej ze stron obraz tomcat.gif. Katalog META-INF zawiera pusty plik MANIFEST.MF. W tym katalogu, opcjonalnie, mógłby się znaleźć deskryptor kontekstu aplikacji (czyli plik konfiguracyjny aplikacji internetowej). Katalog WEB-INF zawiera deskryptor wdrożenia aplikacji internetowej web.xml. Otwórz i zapoznaj się z zawartością tego pliku.

Tomcat15.png

W pliku zdefiniowano jeden serwlet o nazwie HelloServlet zaimplementowany w postaci klasy mypackage.Hello i dostępny pod adresem /hello w ramach kontekstu aplikacji /sample. Otwórz adres http://localhost:8080/sample/hello i sprawdź, czy serwlet tam działa. W katalogu WEB-INF mieszczą się także źródła i postać skompilowana aplikacji internetowej. W podkatalogu classes/mypackage mieści się kod serwletu w pliku Hello.class, a źródło serwletu mieści się w podkatalogu src/mypackage w pliku Hello.java. Pliki *.html i *.jsp są umieszczone bezpośrednio w głównym katalogu sample.

Tomcat16.png

Automatyczne rozpakowanie i instalacja aplikacji były możliwe ze względu na właściwą konfigurację serwera aplikacji. Podstawowym plikiem konfiguracyjnym jest plik %CATALINA_HOME%\conf\server.xml. Otwórz ten plik i znajdź w nim opcję autoDeploy. Poniższy fragment definiuje główny katalog w którym są umieszczane aplikacje (atrybut appBase), automatyczne rozpakowywanie archiwów

  • .war (atrybut unpackWARs), oraz automatyczną instalację rozpakowanych plików

(atrybut autoDeploy).

<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">


Podstawowy system zabezpieczenia zasobów⌘

Wracamy do katalogu %CATALINA_HOME%\webapps\sample\WEB-INF i dodajemy do pliku web.xml poniższy kod:

<security-constraint>
<display-name>Security Constraint</display-name>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/hello</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>helloRole</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Basic Authentication Area</realm-name>
</login-config>


Następnie przechodzimy do okna zarządcy serwera aplikacji i przeładowujemy aplikację /sample (odnośnik Reload) Otwórz w przeglądarce adres http://localhost:8080/sample/hello

Tomcat17.png

Kod wprowadzony do deskryptora wdrożenia web.xml definiuje ograniczenie bezpieczeństwa nazwane Security Constraint i obejmujące sobą adres URL /hello w kontekście aplikacji. Ograniczenie dotyczy wołania tego adresu za pomocą metody GET. Jedynie użytkownicy posiadający rolę helloRole otrzymują dostęp do chronionego zasobu. Sposób logowania został ustawiony na Basic, co oznacza wykorzystanie wewnętrznego mechanizmu przeglądarki. Aby ustawić login i hasło do zasobu nalezy przejść do katalogu %CATALINA_HOME%\conf\ , otworzyć w dowolnym edytorze plik tomcat-users.xml i dodać do pliku poniższe linie

<role rolename="helloRole"/>
<user username="scott" password="tiger" roles="helloRole"/>

Niedogodnością jest to, że aby nasze zmiany odniosły skutek musimy zrestartować serwer Tomcat (z wiersza poleceń lub z managera usług windows)

Logi⌘

Logowanie przychodzących połączeń HTTP w serwerze Apache Tomcat⌘

Standardowo nie są śledzone przychodzące połączenia HTTP. Może to wprowadzać pewną konsternację , na szczęście łatwo to zmienić. Odpowiednie modyfikacje należy wprowadzić w pliku server.xml. Logowanie odbywa się przez klasę AccessLogValve uruchomianą jako valve ( kranik, zaworek z angielska, ale nie mam pojęcia jak to będzie po polsku). Należy więc odszukać definicję z tą klasą i ją po prostu odkomentować. Wygląda ona następująco:

<Valve className="org.apache.catalina.valves.AccessLogValve"
   prefix="localhost_access_log." suffix=".log"
   pattern="common" directory="${jboss.server.log.dir}" 
   resolveHosts="false" />


Konstrukcję tę można umieścić w dowolnym kontenerze (Context, Host, Engine) i będą wtedy zapisywane wszystkie połączenia przechodzące przez dany komponent.
Dopuszczalne parametry konfiguracyjne:
className
Nazwa klasy, która ma odpowiadać za obsługę logowania. Do wyboru są dwie wartości:
org.apache.catalina.valves.AccessLogValve – bardziej ogólna, umożliwia zdefiniowanie zakresu logowanych informacji
org.apache.catalina.valves.FastCommonAccessLogValve – klasa przeznaczona do wykorzystania na systemach produkcyjnych, umożliwia jedynie na logowanie informacji w formacie common lub combined
prefix
Ciąg znaków dodawany na początku nazwy pliku z logiem. Domyślną wartością jest access_log.
suffix
Ciąg znaków dodawany na końcu nazwy pliku z logami.
pattern
Ciąg znaków zawierający informacje o tym, co powinno zostać zapisane w pliku z logami. Może to być definicja używający specjalnych znaczników lub też słowa common lub combined oznaczające jeden ze standardów logowanych informacji. Dokładną specyfikację można znaleźć w dokumentacji Tomcata.
directory
Ścieżka dostępu do katalogu w którym powinny być zapisywane pliki z logami.
resolveHosts
Jeżeli zostanie ustawiona na true to adresy IP zostaną zamienione na nazwy domenowe (będzie to negatywnie wpływało na wydajność, ponieważ będą potrzebne dodatkowe zapytania do serwera DNS). Jeżeli parametr przyjmie wartość false, zostaną użyte adresy IP.
rotatable
Parametr określa, czy plik z logami ma być rotowany. Domyślnie przyjmuje wartość true. Jeżeli zostanie ustawiony na false, plik z logiem nigdy nie będzie rotowany oraz zawartość pola fileDateFormat zostanie zignorowana.
condition
Włączenie logowania warunkowego. Jeżeli parametr zostanie ustawiony na jakąś wartość, to informacja o połączeniu zostanie zalogowań tylko wtedy, gdy ServletRequest.getAttribute() będzie równe null. Jeżeli wartością parametru będzie loguj, to połączenie zostanie zalogowane tylko wtedy, gdy będzie spełniony ten warunek: ServletRequest.getAttribute("loguj") == null.
fileDateFormat
Pozwala na określenie formatu daty w nazwie pliku z logiem. Jednocześnie decyduje o tym, jak często plik ten będzie rotowany. Aby włączyć rotowanie co godzinę, można ustawić wartość parametru tak: yyyy-MM-dd.HH.

LOG4j⌘

W Tomcat 5.5 zniesiono localhost_log które możemy znać jako stos dziennika śledzenia. Te rodzaje błędów są zwykle wyrzucane przez niewychwycone wyjątki, ale są nadal cenne dla dewelopera. Teraz mogą się znaleźć w dzienniku stdout. Jeśli chcesz ustawić cross-context rejestrowanie z kodem serwera Tomcat, a następnie można użyć log4j. Należy pamiętać, że logi mogą zawierać bardzo duże ilości tekstu. Należy również zauważyć, że konfiguracja log4j nie będzie umożliwiać rejestrowania śladu stosu: te ślady stosu są wysyłane na standardowe wyjście, jak wspomniano powyżej.

Konfiguracja LOG4j⌘

Aby skonfigurować plik o nazwie tomcat.log, wykonaj następujące kroki:

Utwórz plik o nazwie log4j.properties o następującej treści i zapisz go do common/classes.

log4j.rootLogger=DEBUG, R 
log4j.appender.R=org.apache.log4j.RollingFileAppender 
log4j.appender.R.File=${catalina.home}/logs/tomcat.log 
log4j.appender.R.MaxFileSize=10MB 
log4j.appender.R.MaxBackupIndex=10 
log4j.appender.R.layout=org.apache.log4j.PatternLayout 
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n

Pobierz Log4J (v1.2 lub ​​nowsze) i umieścić log4j plik jar w $CATALINA_HOME/common/lib. Pobierz Commons Logging i umieścić commons-logging-xyz.jar (nie commons-logging-api-xyz.jar) w $CATALINA_HOME/common/lib z log4j .jar. Uruchom serwer Tomcat,ta konfiguracja log4j ustawia plik o nazwie tomcat.log w folderze dzienników Tomcat o maksymalnej wielkości pliku 10 MB i do 10 kopii zapasowych. Poziom DEBUG jest określony co spowoduje najbardziej szczegółowe dane na wyjściu z Tomcata.

Tomcat 5.5 wykorzystuje rejestratory i definiuje przez Engine i nazwy hostów. Na przykład, dla Catalina w domyślnym dzienniku - lokalnie można dodać do końca log4j.properties.

  • log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=DEBUG, R
  • log4j.logger.org.apache.catalina.core=DEBUG, R
  • log4j.logger.org.apache.catalina.session=DEBUG, R

Należy pamiętać, że są znane problemy z zastosowaniem konwencji nazewnictwa (w nawiasach kwadratowych) w bazie LOG4J plików XML konfiguracji, więc zalecamy użycie pliku właściwości


Poziom DEBUG będzie powodem powolnego uruchamiania Tomcata, gdyż produkowane będą pliki z logami, dużych rozmiarów. Poziom ten powinien być stosowany z umiarem podczas debugowania operacji wewnętrznych. Twoje aplikacje internetowe z pewnością powinny wykorzystywać własne konfiguracje log4j. Można by umieścić plik podobny log4j.properties w aplikacji sieciowej Web w folderze WEB-INF/classes i log4j1.2.8.jar do WEB-INF/lib. Następnie należałoby określić poziom rejestrowania pakietów. Jest to podstawowa konfiguracja log4j która nie wymaga Commons Logging - więcej opcji znajduje się w dokumentacji.

JULI⌘

Domyślna implementacja modułu java.util.logging w JDK jest zbyt ograniczona, aby być użyteczna. W rezultacie, Tomcat w domyślnej konfiguracji, musi zostać uzupełniony klasą z kontenera realizacji, o przyjaznej nazwie JULI, która niweluje te braki. Obsługuje te same mechanizmy konfiguracji co standardowy java.util.logging, przy użyciu umożliwia podejście programowe, lub korzystanie z plików właściwości. Główną różnicą jest to, że ClassLoader pozwala ustawić właściwości plików(co umożliwia łatwą konfigurację webapp) i obsługuje nieco inne konstrukcje, które pozwalają na większą swobodę w określaniu obsługi i przypisania ich do rejestratorów.

JULI jest domyślnie włączona w Tomcat 5.5 i obsługuje za konfigurację ClassLoader, oprócz regularnej konfiguracji globalnej java.util.logging. Oznacza to, że rejestrowanie może być skonfigurowane dla następujących warstw:

Konfiguracja JULI⌘

Sprawdź ustawienia zmiennej środowiskowej JAVA_HOME, aby zobaczyć, którego JDK Tomcat używa. Plik będzie w $JAVA_HOME/jre/lib. Alternatywnie, można również skorzystać z globalnego pliku konfiguracyjnego znajduje się w innym miejscu za pomocą java.util.logging.config.file właściwości systemu lub programową konfigurację za pomocą java.util.logging.config.class. W każdym classloader używając pliku logging.properties. Oznacza to, że można mieć konfigurację rdzenia Tomcata, a także oddzielne konfiguracji dla każdego webapps, które mają taki sam cykl życia jako aplikacje webowe. Logging.properties domyślnie określa ConsoleHandler dla routingu, po zalogowaniu na standardowe wyjście, a także FileHandler. Procedury obsługi w progu poziom logowania można ustawić jako: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST or ALL. W logging.properties dostarczane z JDK jest ustawiony na INFO. Można też kierować konkretne pakiety zbierać info po zalogowaniu. Oto jak można ustawić debugowanie z Tomcat. Trzeba sprawdzić czy ConsoleHandler jest ustawiony na zbieranie tego typu informacji, więc powinien być ustawiony na TRUE lub ALL.

org.apache.catalina.level = FINEST


Plik konfiguracyjny używany przez Juli jest bardzo podobny, ale korzysta kilka rozszerzeń, aby umożliwić większą elastyczność w przypisywaniu rejestratorów. Główne różnice to:

Przedrostek: można wprowadzać do pamięci modułu obsługi, tak, że może wystąpić wiele uchwytów do jednej grupy. Prefix jest Stringiem, który zaczyna się od cyfry, a kończy się '.'. Na przykład, 22foobar. Podobnie jak w Javie 5.0, rejestratory mogą zdefiniować listę obsługi, za pomocą właściwości loggerName.handlers. Domyślnie, rejestratory nie przekazują ich rodziców, jeśli nie wiąże się ich obsługi. To może być zmienione na rejestratorze używając właściwości

loggerName.useParentHandlers, 

która przyjmuje wartość logiczną. Właściwość systemu wymiany wartości właściwości, które zaczynają się od

${sytstemPropertyName}.Logging.properties 

Przykład: plik należy umieścić w common/classes:

handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler, \
           3manager.org.apache.juli.FileHandler, 4admin.org.apache.juli.FileHandler, \
           java.util.logging.ConsoleHandler
.handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

1catalina.org.apache.juli.FileHandler.level = FINE
1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.FileHandler.prefix = catalina.

2localhost.org.apache.juli.FileHandler.level = FINE
2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
2localhost.org.apache.juli.FileHandler.prefix = localhost.

3manager.org.apache.juli.FileHandler.level = FINE
3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
3manager.org.apache.juli.FileHandler.prefix = manager.

4admin.org.apache.juli.FileHandler.level = FINE
4admin.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
4admin.org.apache.juli.FileHandler.prefix = admin.

java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter


############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################

org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = \
   2localhost.org.apache.juli.FileHandler

org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = \
   3manager.org.apache.juli.FileHandler

org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/admin].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/admin].handlers = \
   4admin.org.apache.juli.FileHandler

# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
#org.apache.catalina.startup.ContextConfig.level = FINE
#org.apache.catalina.startup.HostConfig.level = FINE
#org.apache.catalina.session.ManagerBase.level = FINE

Przykładowy plik logging.properties dla servletu, powinien być umieszczony w katalogu WEB-INF/classes, wewnątrz aplikacji: handlers = org.apache.juli.FileHandler, java.util.logging.ConsoleHandler

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

org.apache.juli.FileHandler.level = FINE
org.apache.juli.FileHandler.directory = ${catalina.base}/logs
org.apache.juli.FileHandler.prefix = servlet-examples.

java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

Klaster Tomcat + mod_jk + sticky session + session replication

Definiujemy klaster złożony z dwóch instacji Tomcata połączonego load balancerem apache mod_jk i jak uruchomić replikację sesji oraz sticky-session. System operacyjny to ubuntu 11.10.

Konfiguracja⌘

Adres IP ustawiamy na 10.0.0.90

Instalujemy paczki:

apt-get install apache2 libapache2-mod-jk2-mod-jk



Tworzymy katalog:

/tcluster/instance1



Pobieramy Tomcata i rozpakowujemy zawartość do tego katalogu.

Konfiguracja Apache mod_jk⌘

tworzymy plik /etc/apache2/workers.properties:

worker.list=loadbalancer,mystat
worker.worker1.type=ajp13
worker.worker1.host=10.0.0.90
worker.worker1.port=8881
worker.worker1.lbfactor=50
worker.worker1.cachesize=10
worker.worker1.cache_timeout=600
worker.worker1.socket_keepalive=1
worker.worker1.socket_timeout=300
worker.worker2.type=ajp13
worker.worker2.host=10.0.0.90
worker.worker2.port=8882
worker.worker2.lbfactor=50
worker.worker2.cachesize=10
worker.worker2.cache_timeout=600
worker.worker2.socket_keepalive=1
worker.worker2.socket_timeout=300
worker.loadbalancer.type=lb
worker.loadbalancer.sticky_session=true
worker.loadbalancer.balance_workers=worker1,worker2
worker.mystat.type=status



Ważna jest nazwa workera ( worker1 oraz worker2 ) adres IP oraz port.

do pliku /etc/apache2/ports.conf dodajemy:

Listen 8585

zmieniamy zawartość pliku: /etc/apache2/mods-enabled/jk.conf na:

JKWorkersFile /etc/apache2/workers.properties
JkLogFile /var/log/apache2/mod_jk.log
JkLogLevel debug
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
JkRequestLogFormat "%w %V %T"


dodajemy nasłuch na porcie 8585 dla mod_jk:

/etc/apache2/sites-enabled/000-default
<VirtualHost *:8585>
        JkMount /* loadbalancer
        JkMount /jkstatus mystat
</VirtualHost>



Konfiguracja instancji nr 1⌘

- Zmieniamy plik /tcluster/instance1/conf/server.xml tak aby przypominał:

<Connector port="8871" protocol="HTTP/1.1" /> 
.......
<Connector port="8881" protocol="AJP/1.3" redirectPort="8443" />

....
<Engine name="Catalina" defaultHost="localhost" jvmRoute="worker1">
....
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>



Connectora się odkomentowywuje, jvmRoute trzeba dopisać, pole cluster się odkomentowywuje.

- Ściągamy z internetu http://psi-probe.googlecode.com/files/probe-2.3.3.zip plik war i umieszczamy go w katalogu webapps. Jest to aplikacja która może się później przydać.

-Dodajemy użytkowników Tomcata:

/tcluster/instance1/conf/tomcat-users.xml
<tomcat-users>
...
  <role rolename="manager"/>
  <user username="admin" password="jakieshaslo" roles="manager"/>
</tomcat-users>



Przechodzimy do katalogu: /tcluster/instance1/webapps modyfikujemy examples/WEB-INF/web.xml dodając distributable:

<web-app ....>
  <distributable/>
</web-app>



Konfiguracja instancji nr 2⌘

kopiujemy zawartość pliku /tcluster/instance1 do /tcluster/instance2 zmieniamy plik /tcluster/instance2/conf/server.xml tak aby przypominał:

<Server port="8006" shutdown="SHUTDOWN">
...
<Connector port="8872" protocol="HTTP/1.1" /> 
...
<Connector port="8882" protocol="AJP/1.3" redirectPort="8443" />
....
<Engine name="Catalina" defaultHost="localhost" jvmRoute="worker2">



Testowanie⌘

Uruchamiamy wszystko:

/etc/init.d/apache start
/tcluster/instance1/bin/startup.sh
/tcluster/instance2/bin/startup.sh



Testy przeprowadzić najlepiej za pomocą aplikacji z przykładów: W naszym przypadku jest to:

http://10.0.0.90:8871/examples/servlets/servlet/SessionExample



Mamy trzy porty HTTP:

- 8871 - instancja nr 1
- 8872 - instancja nr 2
- 8585 - load balancer

Po dodaniu jakiegoś aktrybutu sesji i zmianie portu z 8871 na 8872 powinniśmy mieć ten sam SessionID (Sticky-session) oraz te same atrybuty(Replikacja sesji).

Dodatkowa analiza⌘

Panel z informacja o mod_jk:

http://10.0.0.90:8585/jkstatus

Probe (narzędzie do monitorowania) dostępne na danej instancji:

http://10.0.0.90:8871/probe
http://10.0.0.90:8872/probe


Loadbalancing - HAProxy⌘

Opis⌘

Wyobraźmy sobie sytuację, że mamy serwis z dość dużą oglądalnością, wszelkie optymalizacje już zawodzą, programiści przepisali 50% zapytań SQL, administratorzy baz danych wrzucili 75% jej zawartości do pamięci RAM, memcache robi się czerwony od ilości GET’ów a serwis i tak działa coraz wolniej… rozkładamy ręce i szukamy rozwiązania do balansowania ruchu na kilka serwerów.
Haproxy – jak możemy wyczytać z dokumentacji, jest to reverse proxy TCP/HTTP dla środowisk wysokiej dostępności, potrafiące m.in:

  • route’ować pakiety HTTP na podstawie zawartych Cookie
  • przełączać ruch na inny serwer w przypadku wykrycia awarii
  • blokować requesty HTTP na podstawie analizy nagłówków
  • generować statystyki ruchu/usług
  • modyfikować nagłówki HTTP w locie (coś dodać, coś usunąć, coś zmodyfikować)
  • zatrzymać przyjmowanie nowych połączeń bez zrywania nawiązanych
  • i wiele wiele więcej

Opiszę prosty przykład konfiguracji haproxy, który będzie można użyć do balansowania ruchu HTTP do dwóch serwerów.
HAProxy 1.png
Schemat konfiguracji Hostów dla HAProxy

  • xen2 – serwer z HTTP Apache – 192.168.1.241
  • xen3 – serwer z HTTP Lighttpd – 192.168.1.242
  • xen4 – serwer z HTTP Nginx – 192.168.1.124
  • xen7 – serwer z haproxy – 192.168.1.220

Nie chcę opisywać sposobu instalacji haproxy, bo każdy wybierze swoją drogę, apt-get install haproxy, emerge haproxy, wget haproxy-1.3.17.tar.gz; ./configure; make; make install, itd… mając zainstalowane haproxy, możemy zacząć konfigurację:

  1. vi /etc/haproxy.cfg
  • global – ustawienia typu logowania, ilości maksymalnej połączeń, uid’a, gid’a, itd…
  • default – ustawienia domyślne dla wszystkich usług frontend/backed.
  • listen – sekcja właściwa która nas będzie interesowała w tym momencie

Nasza przykładowa konfiguracja wygląda następująco:

root@xen7:~# cat /etc/haproxy.cfg
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
maxconn 4096
user haproxy
group haproxy
defaults
log global
mode http
option httplog
option dontlognull
retries 3
redispatch
maxconn 2000
contimeout 5000
clitimeout 50000
srvtimeout 50000
option httpclose
listen xen 192.168.1.220:80
balance roundrobin
server xen2 192.168.1.241:80
server xen3 192.168.1.242:80
server xen4 192.168.1.125:80

Czyli mamy sekcję listen (nazwa usługi xen) słuchająca na adresie IP load-balancer’a, na potrzeby tego opisu tak może być, ale najlepiej jest każdą usługę (klaster) bindować do innego adresu IP, balance roundrobin oznacza, że requesty będą rozdzielane kolejno do każdego node’a xen2, xen3, xen4 i niżej jest już sama definicja node’ów, server xen2, 3, 4, oraz IP do których należy przekierować requesty.
Uruchamiany daemona (dla testów w trybie foreground i debug):

root@xen7:~# haproxy -dV -f /etc/haproxy.cfg
Available polling systems :
select : pref=150, test result OK
sepoll : disabled, test result OK
epoll : disabled, test result OK
poll : disabled, test result OK
Total: 4 (1 usable), will use select.
Using select() as the polling mechanism.

W praktyce 3 requesty wyglądają tak:

sampler:~ jamzed$ lwp-request -Sde xen7|grep Server
Server: lighttpd/1.4.19
sampler:~ jamzed$ lwp-request -Sde xen7|grep Server Server: nginx/0.5.33 sampler:~ jamzed$ lwp-request -Sde xen7|grep Server Server: Apache/2.2.8 (Ubuntu)

W konsoli widzimy debug:

00000002:xen.accept(0003)=0005 from [192.168.1.182:54865]
00000002:xen.clireq[0005:ffff]: GET / HTTP/1.1
00000002:xen.clihdr[0005:ffff]: TE: deflate,gzip;q=0.3
00000002:xen.clihdr[0005:ffff]: Connection: TE, close
00000002:xen.clihdr[0005:ffff]: Host: xen7
00000002:xen.clihdr[0005:ffff]: User-Agent: lwp-request/5.810
00000002:xen.srvrep[0005:0006]: HTTP/1.1 200 OK
00000002:xen.srvhdr[0005:0006]: Server: nginx/0.5.33
00000002:xen.srvhdr[0005:0006]: Date: Fri, 19 Jun 2009 17:32:57 GMT
00000002:xen.srvhdr[0005:0006]: Content-Type: text/html
00000002:xen.srvhdr[0005:0006]: Content-Length: 151
00000002:xen.srvhdr[0005:0006]: Last-Modified: Wed, 30 Aug 2006 10:39:17 GMT
00000002:xen.srvhdr[0005:0006]: Connection: close
00000002:xen.srvhdr[0005:0006]: Accept-Ranges: bytes

przychodzący request (GET / HTTP/1.1) – nagłówki od klienta xen.clihdr i pełną odpowiedź serwera xen.srvhdr.
Takim sposobem udało nam się szybko zrobić w prosty sposób load-balancer HTTP, jest to tylko ułamek tego co potrafi haproxy.

A jakie są Wasze preferencje co do balanserów? LVS? A może jakieś sprzętowe?

Kierowanie ruchu HTTP na podstawie żądanego contentu/typu danych⌘

<br\><br\>HAProxy2.png<br\><br\> Mamy jeden serwis w jednej domenie http://yoursite.pl/ i posiadamy tylko jeden adres IP, ale chcemy podawać content w zależności od żądanego pliku z różnych serwerów, apache sprawdzi się przy (.php .html), lighttpd lekki, szybki, zwinny, etc. doskonale poradzi sobie z obrazkami (.gif .jpg), a nginx’a chcemy użyć bo też jest modny, do podawania (.js .css), <br\>bez balancera w postaci haproxy który pracuje w 7 warstwie i potrafi analizować i wykonywać przeróżne akcje niczym ninja z filmów z dzieciństwa na nagłówkach HTTP byłoby to trochę bardziej skomplikowane. <br\>Zakładam, że mamy działające haproxy i pozostałe serwery httpd, jeśli tak to można troszkę pobawić się konfiguracją.<br\> Zacznę od wyjaśnienia kilku pojęć:<br\>

  • frontend – zgodnie z dokumentacją, frontendem jest nasza usługa która przyjmuje połączenia od użytkowników i je proxy’uje dalej do backendów.<br\>
  • backend – to definicja serwerów które odbierają ruch od balancer’a i zwracają wyniki, w naszym przypadku backendami są serwery Apache, Lighttpd, Nginx.<br\>
  • acl – Access List, dzięki acl’kom możemy zmatchować dany request np. na podstawie src, dst, path_reg, path_end<br\>

Nasza konfiguracja haproxy będzie wyglądać następująco:<br\>

root@xen7:~# cat /etc/haproxy.cfg
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
maxconn 4096
user haproxy
group haproxy>
defaults
log global
mode http
option httplog
option dontlognull
retries 3
maxconn 2000
contimeout 5000
clitimeout 50000
srvtimeout 50000
option httpclose
frontend frontend_xen
bind 192.168.1.220:80
option forwardfor
acl acl_apache path_end .jsp .html
acl acl_lighttpd path_end .gif .jpg
acl acl_nginx path_end .css .js
use_backend backend_xen2 if acl_apache
use_backend backend_xen3 if acl_lighttpd
use_backend backend_xen4 if acl_nginx
default_backend backend_xen2
backend backend_xen2
mode http
balance roundrobin
server xen2 192.168.1.241:80 check
backend backend_xen3
mode http
balance roundrobin
server xen3 192.168.1.242:80 check
backend backend_xen4
mode http
balance roundrobin
server xen4 192.168.1.125:80 check

Po starcie daemona przeprowadzamy mały test:

$ lwp-request -Sde http://xen7/test.jsp | grep Server
Server: Apache/2.2.8 (Ubuntu)
$ lwp-request -Sde http://xen7/test.css | grep Server
Server: nginx/0.5.33
$ lwp-request -Sde http://xen7/test. jpg | grep Server
Server: lighttpd/1.4.19<br\><br\>

Kluczową rolę odegrały definicje frontendu oraz backendów, ale bez ACL nie moglibyśmy powiedzieć balancer’owi jaki ruch gdzie kierować. Definiujemy więc 3 ACLe (acl_apache, acl_lighttpd, acl_nginx) gdzie warunkiem jest rozszerzenie:<br\><br\>

acl acl_apache path_end .jsp .html
acl acl_lighttpd path_end .gif .jpg
acl acl_nginx path_end .css .js

składnia:<br\> acl nazwa_acla sposób_matchowania warunek<br\> Kolejny bardzo ważny element konfiguracji to wskazanie balancerowi gdzie ma kierować ruch po dopasowaniu do konkretnej acl’ki:<br\>

use_backend backend_xen2 if acl_apache
use_backend backend_xen3 if acl_lighttpd
use_backend backend_xen4 if acl_nginx
default_backend backend_xen2

Jeśli request pasuje do ACL acl_apache to kieruj do backend_xen2, jeśli pasuje do acl_lighttpd to kieruj do backend_xen3, itd… jeśli nie dopasuje do żadnej acl kieruje do default’owego backendu backend_xen2. Bardzo proste do wdrożenia i daje nam ogromne możliwości zarządzania streamem HTTP, operowanie na rozszerzeniach to ułamek możliwości tego load balancer’a, będę starał się co jakiś czas, opisywać inne/pozostałe ciekawe przykłady wykorzystania haproxy.<br\><br\>