Ez a kis segédlet, vagy best practice doksi bemutatja, hogy amikor infrastruktúrát tervezünk egy webalkalmazás alá, akkor mi az alap, amiből kiindulunk. Hasznos lehet rendszermérnöknek, konzultánsnak, fejlesztőnek is.
A leírásban szereplő szoftverkomponensek a SUSE Linux Enterprise Server-ben megtalálhatóak. Számos más webkiszolgáló szoftvert lehet használni a lent leírt feladatokra (lighttpd, nginx), amik akár hatékonyabban is képesek működni. A nagyvállalati SLE termékcsaládhoz Apache2 támogatás jár, ezért a doksiban végig Apache-ra, vagy Apache2-re fogok hivatkozni és nem írom le, hogy mi a különbség prefork és a worker között.
Az elgépeléseket és magyartalanságokat kéretik nem kritizálni, csak jelezni, természetesen megoldási javaslattal. A helyesírási hibákért lehet beszólni.
Van egy webalkalmazásunk, amit az ügyfél szeretne elérhetővé tenni a saját belső hálózatán, vagy az interneten, mint publikus weboldal. Általában mindig fel kell készülni arra, hogyha belső webalkalmazást tervezünk, hogy azt ki is kell tudnunk fordítani az internetre, vagy elérhetővé kell tenni egy másik belső hálózatból is (pl. DMZ), tehát mindig olyan infrastruktúrát tervezünk, hogy több hálózatból is elérhető legyen az alkalmazás.
Amikor webalkalmazásról beszélek, akkor az a legtöbb esetben egy, vagy több, Tomcat-be, vagy JBoss-ba bedobott alkalmazást jelent, esetleg egy adag PHP szkriptet. A Tomcat/JBoss/PHP általában fedi a vállalati alkalmazások 90-95%-át.
Egy Tomcat, vagy JBoss konténerbe bedobott alkalmazást sosem engedünk ki az internetre közvetlenül, minden esetben egy "reverse proxy" segítségével tesszük elérhetővé az alkalmazást. Könyvet tudnék írni csak az érvekből, hogy miért kell reverse proxy, de a három legfontosabb érv: biztonság, teljesítmény, rugalmasság. SUSE Linux Enterprise Serveren erre a feladatra az Apache2 webszolgáltatás a támogatott és kijárt út.
Az alábbi ábráról leolvasható a kliens által indított lekérésnek az útvonala.
Ábra: kapcsolat a komponensek között
A kliens megszólítja HTTP-n, vagy HTTPS-en az Apache2 webszolgáltatást. Az Apache2 opcionálisan redirectelhet HTTP-ről HTTPS-re. Az Apache2 továbbítja a kérést a Tomcat/JBoss konténer felé.
Az Apache2 és a Tomcat/JBoss között a AJP kapcsolaton történik a kommunikáció, mert az egy hatékony, bináris protokoll. Az Apache2 és a Tomcat/JBoss közötti 1 AJP kapcsolatba számos kliens által kezdeményezett HTTP session-t bele lehet tömöríteni, akár több százat is.
A kiszolgáló teljesítménye jelentősen megnövekedik, hogyha egy Apache2 végződteti a HTTP kapcsolatot és AJP-n továbbítja a kéréseket a Tomcat/JBoss konténer felé.
Az ábráról leolvasható továbbá, hogy a kliens milyen URL-eken érheti el az alkalmazást és az egyéb erőforrásokat. Az esetek jelentős részében, nagyvállalati tűzfal miatt, a kliens nem is érhet el a 80 és a 443-as TCP porton kívül más portot a kiszolgálón, ezért rossz gyakorlat az, hogyha a klienstől elvárjuk, hogy más portokra is csatlakozzon.
Amint azt később látni fogjuk, az Apache2 és a Tomcat/JBoss konténer nem feltétlenül fut ugyanazon a kiszolgálón. Ebben az esetben, esetleg felmerülhet, hogy az AJP protokollt nem lehet titkosítani, ezért a Tomcat/JBoss konténeren be kell állítani egy HTTPS connectort, és AJP helyett HTTPS csatolón keresztöl kell továbbítani a kliensektől érkező kéréseket. Ez nem javasolt, ugyanis nagyon lassú. Inkább érdemes sok energiát áldozni az Apache2 és a Tomcat/JBoss kiszolgálók közötti hálózat biztonságossá tételére, és az így már biztonságos hálózaton használni az AJP csatornát.
Nem feltételezhetjük azt, hogy a kliens a 80-as és 443-as portokon kívűl más porton is eléri a kiszolgálónkat. Hogyha speciális funkciót lát el az alkalmazásunk (pl. képernyő átvétel, hang/videó átvitel, multicast, stb), amit nem lehet HTTP csatornába terelni, akkor az alkalmazás leírásában a követelmények szakaszban a fejlesztők/terjesztők jelezni szokták, hogy milyen speciális hálózati igényei vannak az alkalmazásnak.
A Tomcat/JBoss konténerben futó webalkalmazásnak a legtöbb esetben nem szabad IP címmel megszólítania a belső erőforrásokat, hanem DNS nevet kell használnia. Az Apache2-ben majd az üzemeltető beállítja, hogyha a kliens a /MyWebApp/index.jsp-t kéri le, akkor az egyik Tomcat/JBoss konténer felé küldje a forgalmat, hogyha a /BackendService/... kezdetű URL-t szeretné a kliens elérni, akkor pedig egy másik Tomcat/JBoss konténer felé küldje a forgalmat. Ezt URL mappelésnek nevezzük. Ilyesmi szabályokat szoktunk létrehozni pl.:
/BackenService/ -> localhost:8180/BackendService/
/Downloads/ -> ! Ne mappelődjön. Ezt az Apache2 szolgálja ki, mert a statikus adatokat gyorsabban kezeli, mint a Tomcat/JBoss
/images/ -> ! Ne mappelődjön.
/css/ -> ! Ne mappelődjön.
/ -> localhost:8080/MyWebApp/
A fenti példában minden URL a helyi Tomcat/JBoss konténerben futó MyWebApp alkalmazásra mappelődik, kivéve a /css, /images, /Donwloads URL-eket, mert azokat az Apache2 szolgálja ki, illetve a /BackendService/ kezdetú URL-eket, mert azokat egy másik Tomcat/JBoss konténer BackendService alkalmazása felé továbbítjuk.
Ábra: URL mappelése
Nagyon sok webalkalmazás fejlesztője követ el olyan hibát, hogy belső erőforrás URL-jét megpróbálja "kitalálni", ekkor születnek a következőhöz hasonló URL-ek http://192.168.17.22:8180/BackendService/api.jsp?foo=bar, amit nem nehéz belátni, hogy az internet irányából érkező felhasználó nem érhet el. Az esetek döntő többségében webalkalmazásnak elég, ha relatív URL-t generál, pl /BackendService/api.jsp?id=123, az URL mappelésnek köszönhetően ez el fog találni arra a helyre, ahova mennie kell.
Fontos cél, hogy a kliens felé küldött link a lehető legtöbb esetben relatív URL legyen. Az abszolút linkekkel csak a baj van, csak speciális esetben szabad használni.
A való életben az Apache2 és a Tomcat/JBoss konténer nem feltétlenül fut azonos kiszolgálón, illetve a komponensek száma is eltérő lehet. Általában a Tomcat/JBoss konténerből több példány is kell, mind dedikált kiszolgálókon, hogy a kliensektől érkező terhelést el tudjuk osztani a Tomcat/JBoss konténerek között.
Ábra: 1 Apache2 "mögött" több Tomcat/JBoss konténer
Az Apache2 webszolgáltatás használható terheléselosztóként több Tomcat/JBoss konténer előtt. Ennek az a feltétele, hogy a konténerben futó alkalmazás képes legyen több példányban futni. Ez egy trükkös feltétel, nagyon figyelni kell azokra az erőforrásokra, amit a konténerben futó alkalmazás használ, ilyenek pl.: helyi fájlok, helyi, vagy távoli adatbázisok, távoli egyéb szolgáltatások.
Távoli adatbázis esetén fontos, hogy az adatbázis integritásának megőrzése céljából vagy nagyon egyszerűre kell tervezni az adatbázist, vagy zárolási eljárást kell implementálnia a fejlesztőnek, hogy elkerüljük a "race condition" hibákat.
Az Apache2 nem túl jó választás terheléselosztónak, mert viszonylag kicsi hozzá a teljesítménye, de kisebb terheltségű oldalaknál nagyon megfelelő lehet, mert nagyon rugalmas és sok funkciója van.
Ábra: Apache2 webszolgáltatás terheléselosztóként működik Tomcat/JBoss alkalmazások előtt
Az egyik legjobb megoldás, hogyha a webalkalmazásunk elé egy hardveres terheléselosztót, vagy loadbalancert teszünk. Ezt a funkciót az ún. L4 switchek tudják (gyk. pl. nagyon drága Cisco switch). Ezek az eszközök képesek párban működni a magas rendelkezésre állás érdekében.
Ilyenkor célszerű minden Tomcat/JBoss konténer elé egy Apache2 előtétet állítani, ugyanis abban az esetben, ha csak egy Apache2 kiszolgálót használunk, akkor az ún. SPOF (Single Point of Failure) lesz, ami azt jelenti, hogy annak az egy komponensnek a meghibásodása esetén a teljes rendszerünk elérhetetlen lesz.
A legtöbb ilyen konfiguráció esetén az összetartozó Apache2 és a Tomcat/JBoss konténer egy közös kiszolgálón fut. Az alábbi ábrán láthat négy-négy Apache2 és Tomcat/JBoss összesen négy kiszolgálón futhat. A teljesítmény növelésének érdekében szét lehet választani nyolc kiszolgálóra rendszert.
Ábra: L4 terheléselosztó használata a terhelés elosztására
Rendszeresen előfordul az is, hogy a Tomcat/JBoss alkalmazást több különböző hálózatból is szeretnék elérni. Ilyenkor van egy belső és egy külső Apache is, melyek rossz esetben különböző névvel érhetőek el.
Ábra: Apache2 és Tomcat/JBoss rendszer elérése különböző hálózatokból
Ilyenkor a szokásosnál is fontosabb, hogy a Tomcat/JBoss alkalmazás megfelelő módon generálja az URL-eket, különben csak 1 meghatározott domén néven lesz elérhető az alkalmazás.