Oca 22
Sunucular üzerindeki aşırı yüklenmeden kaynaklanan sorunları çözmenin bir yöntemi bu yüklenmeleri bir kaç sunucuya paylaştırmak olacaktır. Aynı işi yapan sunucuların oluşturduğu kümeden (cluster) beklenilen duruma göre küçülebilir/genişleyebilir -ölçeklenebilir- olması (scalability), kümedeki bir sunucunun durması durumunda üzerindeki isteklere başka bir sunucunun cevap vermesidir (availability). Küme yapısını iki şekilde kurabiliriz : Dikey ve Yatay. Dikey küme yapısında tek makina üzerinde birden fazla küme üyesi bulunurken, yatay yapıda üyelerin herbiri ayrı makinalarda bulunur.

Sunucuların kümelenme işlemiyle neleri gerçekleştirebiliriz?

1. İş yükünü dağıtma (Load Balanbcing)Geliştirdiğimiz web tabanlı uygulamalarda bir çoğumuz Apache, Tomcat, J2EE uygulama sunucularını kullanmışızdır. Yazdığımız uygulamaları kullanan sayısı arttıkça, artan isteğe cevap vermeye çalışan sunucuların da istiktrarlı çalışması beklenemez. Bu gibi durumda yazdığımız uygulamadaki dar boğazların neler olduğunu tespit etmeye çalışırız. Bu dar boğazların tespiti ve düzeltilmesi için uygulamalarda ciddi yapısal değişiklikleri yapmamız yazılım maaliyetlerinin artmasına neden olmaktadır.
2. Hata yönetimi (Fault Tolerance)
3. Kullanıcı oturumlarının paylaşılması (Session Persistence)

Tomcat 5 ve Clustering


Tomcat 5 sunucularında küme yapısını aktif hale getirmek için server.xml dosyasındaki tanımlamasını aktif hale getirmemiz gerekmektedir.


                 managerClassName="org.apache.catalina.cluster.session.DeltaManager"
                 expireSessionsOnShutdown="false"
                 useDirtyFlag="true">


Tomcat 5 küme yapısındaki sunucular çalıştıklarını bildirmek (heartbeating) ve kullanıcı oturumlarını (session) aktarmak için birbirleri ile konuşmaya ihtiyaç duymaktadırlar. IP multicast yöntemi ile her bir küme üyesi diğer üyelerin durumu hakkında bilgi almaktadır. Durum sorgu mesajı kümeye gönderildiğinde cevap olarak cevap verenin IP adresi ve port numarası alınmaktadır. Tüm üyeler için MultiCast tanımlaması aynı olmalıdır. Örnek :


            ... 
           
                className="org.apache.catalina.cluster.mcast.McastService"
                mcastAddr="228.0.0.4"
                mcastPort="45564"
                mcastFrequency="500"
                mcastDropTime="3000"/>


IP / Socket iletişimi oturum bilgilerinin diğer üyelere gönderilmesi ve üyelerden alınması için kullanılmaktadır.

 

                className="org.apache.catalina.cluster.tcp.ReplicationListener"
                tcpListenAddress="127.0.0.1"
                tcpListenPort="4000"
                tcpSelectorTimeout="100"
                tcpThreadCount="6"/>
           
                className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
                replicationMode="pooled"/>
 

tcpListenerAddress ve tcpListenPort değerleri herbir küme üyesi için farklı olmalıdır. IP multicast yöntemi ile gelen sorguya cevap olarak bu bilgiler gönderilmektedir. Receiver tanımlaması, tanımlamanın yapıldığı küme üyesinin gelen paylaşım paketlerinin kaç thread tarafından ve hangi port üzerinden alınacağını belirler. Sender tanımlaması, oturum bilgisinin gönderilme yöntemini belirler : synchronous, pooled (default), asynchronous asynchronous : bu modda, oturum bilgisini diğer üyelere gönderen thread, istek geldiğinde paylaşımı işlemini kuyruğa sokup hemen gelen isteğe cevap verme kaygısı içerisindedir. Bu modda kullanıcıya kısa sürede cevap verilmektedir. Oturum bilgisinin paylaşımının başarısız olması çok önemli değildir. synchronous : bu modda, oturum paylaşımı tam anlamıyla gerçekleşmeden kullanıcı isteğine cevap dönülmemektedir. Paylaşım işlemi tek thread üzerinden gerçekleştiğinden, üye sayısı çok olan kümede istemciye cevap verme süresi artacaktır. pooled : bu modda, gönderilecek olan paylaşım bilgisi parçalara ayrılarak her biri farklı thread ve soket üzerinden gönderilmektedir. Gönderme işlemi yapıldıktan sonra istemciye cevap verilmektedir. Oturum bilgisi paylaşımı 3 durumda gerçekleşir:
  1. userDirtyFlag parametresi true olarak ayarlanmışsa veya setAttribute() / removeAttribute() yordamları çağrılmışsa
  2. Oturum yaratıldığında
  3. Valve tanımı içerisindeki uzantı tanımları. Bu uzantılara ait istekler geldiğinde oturum bilgisi paylaşımı gerçekleşmez. userDirtyFlag parametresi true yapıldığında Valve içerisinde tanımlananların dışında istek geldiğinde otomatik olarak paylaşım gerçekleştirilir.

         ...
        

                   filter=".*.gif;.*.js;.*.jpg;.*.htm;.*.html;.*.txt;"/>


Oturum bilgilerinin toplanması için üç yöntem mevcuttur:
  1. Bellekten Belleğe (Memory to Memory) : bir küme üyesi üzerindeki oturum bilgisi değiştiğinde hemen diğer üyelere gönderilir.
  2. Veritabanına Yazmak : Oturum bilgilerini veritabanına yazmak ve buradan okumak.
  3. Dosyaya Yazmak / Dosyadan Okumak: Oturum bilgilerini ortak bir dizin içerisinde dosyaya yazmak ve dosyadan okumak. Bu yöntemde bizi kısıtlayan, disk büyüklüğü olacaktır.
Aynı makina üzerinde 4 Tomcat sunucusundan oluşan dikey bir küme (vertical cluster) oluşturalım. Port çakışmalarını önlemek için her Tomcat'in server.xml dosyasında gerekli portları aşağıdaki gibi değiştirelim.
Konfigurasyon Parametreleriüye 1üye 2üye 3üye 4
Instance TypeLoad BalancerCluster Node 1Cluster Node 2Cluster Node 3
Code nameTC01TC02TC03TC04
Home Directory/tomcat51/tomcat52/tomcat53/tomcat54
Server Port800590051000511005
Connector808090801008011080
Coyote/JK2 AJP Connector800990091000911009
Cluster mcastAddr228.0.0.4228.0.0.4228.0.0.4228.0.0.4
Cluster mcastPort45564455644556445564
tcpListenAddress127.0.0.1127.0.0.1127.0.0.1127.0.0.1
Cluster tcpListenPort4000400140024003
Tüm küme üyelerini aktif hale getirelim. TC01'den alınan log çıktısında, TC01 'in küme içerisinde hangi üyelerin olduğunu ve yaşadığını tespit etmek için gönderdiği ve aldığı mesajları görmekteyiz. Bu işlemleri tüm küme üyeleri kendileri için gerçekleştireceklerdir.

2008-02-07 02:25:57,320 (McastServiceImpl.java:280) org.apache.catalina.cluster.mcast.McastService - Mcast send ping from member org.apache.catalina.cluster.mcast.McastMember[tcp://127.0.0.1:4000,catalina,127.0.0.1,4000, alive=2426682] 2008-02-07 02:25:57,320 (McastServiceImpl.java:244) org.apache.catalina.cluster.mcast.McastService - Mcast receive ping from member org.apache.catalina.cluster.mcast.McastMember[tcp://127.0.0.1:4000,catalina,127.0.0.1,4000, alive=2426948] 2008-02-07 02:25:57,450 (McastServiceImpl.java:244) org.apache.catalina.cluster.mcast.McastService - Mcast receive ping from member org.apache.catalina.cluster.mcast.McastMember[tcp://127.0.0.1:4003,catalina,127.0.0.1,4003, alive=4118285] 2008-02-07 02:25:57,452 (McastServiceImpl.java:244) org.apache.catalina.cluster.mcast.McastService - Mcast receive ping from member org.apache.catalina.cluster.mcast.McastMember[tcp://127.0.0.1:4002,catalina,127.0.0.1,4002, alive=4122490] 2008-02-07 02:25:57,820 (McastServiceImpl.java:244) org.apache.catalina.cluster.mcast.McastService - Mcast receive ping from member org.apache.catalina.cluster.mcast.McastMember[tcp://127.0.0.1:4001,catalina,127.0.0.1,4001, alive=2783164]

TC01 de clusterapp uygulamasını açalım ve birkaç giriş yapalım. Aynı pencerede URL üzerinden HTTP portunu 10080 yaparak isteği TC03 e yönlendirelim. Aynı pencereden istek yaptığımızdan sunucuya aynı oturum kimliği gidecektir. Bu kimlik JSESSIONID isminde çerez olarak tutulmaktadır.
TC01 da 8080 portu üzerinden yapılan işlemlerAynı browser penceresindeki URL'in portunu 10080 yapınca TC03 den gelen cevap
Isteği TC03 e yönlendirdiğimizde, TC01 üzerinden eklediğimiz ad ve soyad özelliklerini içeren aynı oturum bilgisi gelmektedir. Peki arka tarafta neler oldu? TC01 deki log dosyasına bir bakalım. 4002 portlu TC03 üzerinden 7C792502AA128b28866E7E37AB6A31E8 numaralı oturum bilgisine erişilmek istendiğini görmekteyiz. İlk adımda 15 ms'lik bir sürede oturum bilgisi diğer üyelere gönderilmiş, ikinci adımda TC03'ün oturum bilgisine erişmek istediği mesajı alınmış ve üçüncü adımda bu oturum bilgisine erişilmiştir..

2008-02-07 02:25:57,054 (SimpleTcpCluster.java:1163) org.apache.catalina.cluster.tcp.SimpleTcpCluster - Assuming clocks are synched: Replication for 7C792502AA128b28866E7E37AB6A31E8-1202343957039 took=15 ms. 2008-02-07 02:25:57,054 (DeltaManager.java:1521) org.apache.catalina.cluster.session.DeltaManager - Manager [/clusterapp]: Received SessionMessage of type=(SESSION-ACCESSED) from [org.apache.catalina.cluster.mcast.McastMember[tcp://127.0.0.1:4002,catalina,127.0.0.1,4002, alive=4122078]] 2008-02-07 02:25:57,055 (DeltaManager.java:1618) org.apache.catalina.cluster.session.DeltaManager - Manager [/clusterapp]: received session [7C792502AA128b28866E7E37AB6A31E8] accessed.

Uygulama Yükleme (Deploying)
Tomcat sunucusuna uygulama yükleme işlemini ya Manager üzerinden yada elle war dosyasını webapps altına taşıyarak v.b. gerçekleştirebiliriz. Bunu küme yapısı içerisinde birden fazla küme üyesine (sayısı 5-6 ve ya daha fazla da olabilir) yaptığımızı düşünelim.
  1. yeni war dosyasını tüm üyelere kopyala
  2. her bir üyenin çalıştığı makinaya teker teker login ol
  3. mevcut war dosyasını yedekle
  4. yeni war dosyasını, webapps içerisine taşı
Tamamiyle zaman kaybı, yorgunluk ve sonucunda en ufak bir hata... Küme yapısında uygulama yükleme işlemini tek bir yerden gerçekleştirebiliriz. Bunun için catalina-cluster.jar içerisindeki org.apache.catalina.cluster.deploy.FarmWarDeployer sınıfını yükleme işleminden sorumlu hale getiriyoruz. Server.xml dosyasında

 

       className="org.apache.catalina.cluster.deploy.FarmWarDeployer"

                   watchDir="/home/tdiler/clustering/deploy/watch"

                   deployDir="/home/tdiler/clustering/tomcat51/webapps"

     watchEnabled="true"/>



tanımlamasını yapmamız gerekmektedir. Burada watchDir olarak tanımladığımız dizin sürekli org.apache.catalina.cluster.deploy.WarWatcher tarafından dinlenmektedir. watchEnabled özelliği false yapıldığında dinleme gerçekleşmeyecektir. watchDir dizininde war dosyası ekleme, silme veya güncelleme işlemi yapıldığında aynı işlem deployDir dizininde otomatik olarak gerçekleştirilecektir. WatchEnabled özelliği true yapılan küme üyesi deployDir dizinindeki bir değişikliği tüm üyelere bildirmektedir. Eğer war dosyası eklenmiş veya güncellenmiş ise bu war dosyası diğer üyelere TCP üzerinden gönderilmektedir. TC01 üyesinde watchEnabled özelliğini true, diğerlerinde ise false (diğer üyeleri false yapma zorunluluğumuz yoktur.) yapalım. Böylece TC01 güncel WAR dosyalarının takibinden sorumlu olsun. Burada kritik bir nokta TC01 kapandığında diğer üyeler güncellemelerden haberdar olamayacaklardır. WatchDir dizinine clustering_test-0.0.2.war dosyasını koyduğumda TC01 deki log dosyasında :

Feb 26, 2008 12:30:48 AM org.apache.catalina.cluster.deploy.WarWatcher check INFO: check cluster wars at /home/tdiler/Documents/Tomcat_Clustring_Calisma/deploy/watch Feb 26, 2008 12:30:48 AM org.apache.catalina.cluster.deploy.FarmWarDeployer fileModified INFO: Installing webapp[/clustering_test-0.0.2] from /home/tdiler/Documents/Tomcat_Clustring_Calisma/tomcat51/webapps/clustering_test-0.0.2.war Feb 26, 2008 12:30:48 AM org.apache.catalina.cluster.deploy.FarmWarDeployer remove INFO: Cluster wide remove of web app /clustering_test-0.0.2 Feb 26, 2008 12:30:48 AM org.apache.catalina.startup.HostConfig deployWAR INFO: Deploying web application archive clustering_test-0.0.2.war Feb 26, 2008 12:30:48 AM org.apache.catalina.cluster.session.DeltaManager start INFO: Starting clustering manager...:/clustering_test-0.0.2 Feb 26, 2008 12:30:48 AM org.apache.catalina.cluster.session.DeltaManager start INFO: Register manager /clustering_test-0.0.2 to cluster element Host with name localhost Feb 26, 2008 12:30:48 AM org.apache.catalina.cluster.session.DeltaManager start INFO: Starting clustering manager at /clustering_test-0.0.2

Burada org.apache.catalina.cluster.deploy.WarWatcher ile watchDir sürekli kontrol edilmektedir. War dosyası eklendiğinde ya da güncellendiğinde öncelikle tüm kümedeki üyelere eskisinin silinmesi için mesaj yollanmış ve sonrasında war dosyası diğer küme üyelerine gönderilmiştir. İşlem gerçekleştikten sonra bu uygulama için küme işlemleri başlatılmıştır. Dinleyici moddaki TC02 deki log dosyasına baktığımızda :

Feb 26, 2008 12:30:48 AM org.apache.catalina.cluster.session.DeltaManager stop INFO: Manager [/clustering_test-0.0.2] expiring sessions upon shutdown Feb 26, 2008 12:30:48 AM org.apache.catalina.startup.HostConfig checkResources INFO: Undeploying context [/clustering_test-0.0.2] Feb 26, 2008 12:30:48 AM org.apache.catalina.startup.HostConfig deployWAR INFO: Deploying web application archive clustering_test-0.0.2.war Feb 26, 2008 12:30:48 AM org.apache.catalina.cluster.session.DeltaManager start INFO: Starting clustering manager...:/clustering_test-0.0.2 Feb 26, 2008 12:30:48 AM org.apache.catalina.cluster.session.DeltaManager start INFO: Register manager /clustering_test-0.0.2 to cluster element Host with name localhost Feb 26, 2008 12:30:48 AM org.apache.catalina.cluster.session.DeltaManager start INFO: Starting clustering manager at /clustering_test-0.0.2

Var olan war dosyası silinmeden önce bu uygulama için başlatılan küme işlemleri durdurulmuş, yeni war dosyası alınmış ve işlemler yeniden başlatılmıştır.

Taner Diler
taner.diler[et]gmail.com

Kaynaklar

1. Clustering and Load Balancing in Tomcat 5, Part 1; Srini Penchikala
2. Session Replication in Tomcat 5 Clusters, Part 1; Srini Penchikala
3. Apache Tomcat 5.5 Clustering/Session Replication HOW-TO