Näytetään tekstit, joissa on tunniste clustering. Näytä kaikki tekstit
Näytetään tekstit, joissa on tunniste clustering. Näytä kaikki tekstit

lauantai 21. tammikuuta 2012

Tomcat clustering and session persistency in AWS


Tomcat supports clustering out-of-the-box (see http://tomcat.apache.org/tomcat-7.0-doc/cluster-howto.html). However, since Amazon EC2 environment has some pecualiar features such as not supporting IP multicasting (http://aws.amazon.com/vpc/faqs/#R4), the traditional(?) way of Tomcat clustering cannot be used. Instead of using direct communication between different cluster nodes, you can use HTTP session sharing via database. Although this is not as fast or flexible as direct communication, it's still better than no clustering.

How session sharing works

Tomcat copies session data to a database when it's shut down. It also makes a periodical copying of idle sessions every now and then (the configuration given below doesn't define the exact maximum session idle time before Tomcat does replication to database. The configured maximum time is about maxIdleBackup + processExpiresFrequency * engine.backgroundProcessorDelay. Google for more details...).

Because all the Tomcats are sharing a commong session repository i.e. database, they all have access to each other's sessions that have been persisted at least once. Whenever a new Tomcat instance starts, it reads the existing sessions from common session repository and is then able to serve any request to any Tomcat in the cluster up to start-up time of the instance.

Because of delays in sharing the sessions, you should enable sticky sessions in you load balancer. This means that each request from a user will be directed to the same Tomcat as long as user HTTP session exists.

Use application generated cookie in ELB

In order to use database session sharing, you must use sticky sessions in your load balancer. Amazon ELB has the options of using either ELB generated session cookie or application generated session cookie. I think that in this case one should use application generated session cookie (JSESSIONID), because ELB generated session cookie may have different expiration time than your application's session. If ELB cookie expires before you application's session, user may get served by different Tomcat, although application's session has not changed. This may lead into nasty problems.

Setup RDS based database for Tomcat session storing

The easiest way of using a common session replication database in Amazon is RDS service. Of course you may also set up your own database on one EC2 instance, but this would be a single point of failure. So, I'm using RDS and MySQL in this example. Create a session database and a session table in the database.
CREATE DATABASE tomcat_data DEFAULT CHARACTER SET UTF8 COLLATE utf8_swedish_ci;
GRANT ALL ON tomcat_data.* TO "tomcat"@"%" IDENTIFIED BY "tomcat";


create table tomcat_data.tomcat_sessions (
  session_id varchar(100) not null primary key,
  valid_session char(1) not null,
  max_inactive int not null,
  last_access bigint not null.
  app_name varchar(255),
  session_data mediumblob,
  KEY kapp_name(app_name)
);

MySQL connection from Tomcat

You need to copy the mysql-connector-java-x.x.xx.jar under $CATALINA/lib (on Ubuntu, it's /usr/share/tomcat6/lib/ depending on your Ubuntu/Tomcat version). This JAR is needed to create connection from Tomcat to MySQL.

Here's context.xml you need. Remember to change localhost to something more meaningful in the XML file.

<Context>

...

    <!-- The idle time in seconds before persisting session is
         maxIdleBackup + processExpiresFrequency * engine.backgroundProcessorDelay.
         The backgroundProcessorDelay is around 10 seconds. This configuration should make Tomcat
         to persist sessions after 20 seconds of idling and hold them in memory as long as each
         instance wants -->
    <Manager className="org.apache.catalina.session.PersistentManager"
      saveOnRestart="true"
      minIdleSwap="-1"
      maxIdleSwap="-1"
      maxIdleBackup="20"
      processExpiresFrequency="1">
      <Store className="org.apache.catalina.session.JDBCStore"
        connectionURL="jdbc:mysql://localhost/tomcat_data"
        driverName="com.mysql.jdbc.Driver"
        connectionName="tomcat"
        connectionPassword="tomcat"
        sessionIdCol="session_id"
        sessionValidCol="valid_session"
        sessionMaxInactiveCol="max_inactive"
        sessionLastAccessedCol="last_access"
        sessionTable="tomcat_sessions"
        sessionAppCol="app_name"
        sessionDataCol="session_data"
      />
    </Manager>
...

</Context>


Problems in this solution

If Tomcat dies unexpectedly, the new sessions served by dead instance are lost. Most likely with the configuration above, sessions newer than 30 seconds will disappear. Also new changes that have been done to session data will be lost.

Session related database traffic could grow quite high in a busy web site. I have no cure for this, but of course you can at least use a different database for sessions than what's being used for other data.

sunnuntai 1. tammikuuta 2012

Kevyt klusterointi Amazon Web Servicessä



Kokeillaan rakentaa kahden weppipalvelimen klusteri yllä olevan kuvan mukaisesti ja käyttää Amazonin tarjoamaa kuormantasaajaa (ELB, Elastic Load Balancing) komentorivikomennoilla. Weppipalvelimena toimivat kaksi Apachea, jotka tarjoilevat molemmat yhtä sivua.

Klusterin palvelimien pystytys
Klusterin palvelimet voisi pystyttää yksitellen edellisen blogauksen ohjeiden perusteella. On kuitenkin mielenkiintoisempaa rakentaa image, jolta molemmat koneet käynnistetään.

Luodaan ensin yksi EC2-instanssi Ubuntu 10.04:n AMI:n pohjalta.

$ ec2-run-instances ami-cc0e3cb8 --instance-count 1 --instance-type t1.micro --key testkeypair --group public_access
RESERVATION r-adfdf5db 093338577702 public_access
INSTANCE i-14cc735d ami-cc0e3cb8 pending testkeypair 0 t1.micro 2011-12-04T16:59:46+0000 eu-west-1a aki-4feec43b monitoring-disabled ebs paravirtual xen sg-12ac4965 default

Asennetaan koneelle Apache-palvelin. Apachen asentaminen vaatii koneelle kirjautumista ja koneelle kirjautuminen edellyttää koneen nimen tietämistä, joten selvitetään nimi ensin.

$ ec2-describe-instances
RESERVATION r-adfdf5db 093338577702 public_access
INSTANCE i-14cc735d ami-cc0e3cb8 ec2-46-137-22-203.eu-west-1.compute.amazonaws.com ip-10-48-9-210.eu-west-1.compute.internal running testkeypair 0 t1.micro 2011-12-04T16:59:46+0000 eu-west-1a aki-4feec43b monitoring-disabled 46.137.22.203 10.48.9.210 ebs paravirtual xen sg-12ac4965 default
BLOCKDEVICE /dev/sda1 vol-7551591c 2011-12-04T17:00:04.000Z

Kirjaudutaan koneelle ja asennetaan Apache.

$ ssh -i certs/testkeypair_private.key ubuntu@ec2-46-137-22-203.eu-west-1.compute.amazonaws.com
$ sudo apt-get update
$ sudo apt-get install apache2

Todetaan selaimella, että Apache toimii eli mennään osoitteeseen http://ec2-46-137-22-203.eu-west-1.compute.amazonaws.com..

Tehdään luodusta Ubuntu-asennuksesta asennusmedia, josta on helppo luoda klusteriin uusia instansseja.

$ ec2-stop-instances i-14cc735d
INSTANCE i-14cc735d running stopping
$ ec2-create-image i-14cc735d --name "weppipalvelin" --description "Klusterin weppipalvelimien luomiseen image"
IMAGE ami-73073b07

Imagen olemassaolon voi vielä tarkistaa näin.

$ ec2-describe-images
IMAGE ami-73073b07 093338577702/weppipalvelin 093338577702 available private x86_64 machine aki-4feec43b ebs paravirtual xen
BLOCKDEVICEMAPPING /dev/sda1 snap-aaef70c2 8

Sitten pitäisi käynnistää klusterin koneet. Poistetaan ensin kuitenkin aiemmin luotu instanssi sotkemasta muuta säätöä.

$ ec2-terminate-instances i-14cc735d

Uusien koneiden käynnistäminen.

$ ec2-run-instances ami-73073b07 --instance-count 2 --instance-type t1.micro --key testkeypair --group public_access
RESERVATION r-2b89815d 093338577702 public_access
INSTANCE i-10bf0059 ami-73073b07 pending testkeypair 0 t1.micro 2011-12-04T18:09:57+0000 eu-west-1c aki-4feec43b monitoring-disabled ebs paravirtual xen sg-12ac4965 default
INSTANCE i-12bf005b ami-73073b07 pending testkeypair 1 t1.micro 2011-12-04T18:09:57+0000 eu-west-1c aki-4feec43b monitoring-disabled ebs paravirtual xen sg-12ac4965 default

Koneiden status käynnistyksen jälkeen.

$ ec2-describe-instance-status
INSTANCE i-10bf0059 eu-west-1c running 16
INSTANCE i-12bf005b eu-west-1c running 16

AWS antoi koneille DNS-nimet ec2-79-125-46-213.eu-west-1.compute.amazonaws.com ja ec2-46-137-144-163.eu-west-1.compute.amazonaws.com. Muutetaan jälkimmäisen koneen tiedostoa /var/www/index.html ja lisätään sinne tunnisteen "Kone 2", jotta koneet voi myöhemmin erottaa kuormantasaajan takaa.

Kuormantasaajan luominen
Aivan ensiksi pitää noutaa kuormantasaajan komentorivityökalut.

$ wget http://ec2-downloads.s3.amazonaws.com/ElasticLoadBalancing.zip

Paketti pitää purkaa ja sen jälkeen vielä editoida aiemmin luotua env.sh-tiedostoa, jotta ELB:n työkalut saadaan polkuun ja jotta ELB:n työkalut tietävät mistä löytyvät. Lisää siis seuraavat rivit.

export AWS_ELB_HOME=~/aws/ElasticLoadBalancing-1.0.15.1
export PATH=$PATH:$EC2_HOME/bin:$AWS_ELB_HOME/bin
export EC2_REGION=eu-west-1

ELB:n luonti.

$ elb-create-lb klusteri-lb --listener "protocol=HTTP, lb-port=80, instance-port=80" --availability-zones eu-west-1c
DNS_NAME klusteri-lb-828561786.eu-west-1.elb.amazonaws.com

Lisätään instanssit ELB:lle.

$ elb-register-instances-with-lb klusteri-lb --instances i-10bf0059,i-12bf005b
INSTANCE_ID i-12bf005b
INSTANCE_ID i-10bf0059

Selaimella voi käydä tarkistamassa, että kuormantasaaja heittelee pyyntöjä molemmille koneille: http://klusteri-lb-828561786.eu-west-1.elb.amazonaws.com.

Jälkien siivoaminen 
Lopuksi poistetaan kaikki varatut resurssit, jotta AWS ei lähettele laskuja perään.

$ elb-delete-lb klusteri-lb
$ ec2-terminate-instances i-12bf005b i-10bf0059

Luodun AMI:n poistaminen on karvan verran hankalampaa.

$ ec2-describe-snapshots
SNAPSHOT snap-aaef70c2 vol-7551591c completed 2011-12-04T17:22:54+0000 100% 093338577702 8 Created by CreateImage(i-14cc735d) for ami-73073b07 from vol-7551591c
$ ec2-deregister ami-73073b07
IMAGE ami-73073b07
$ ec2-delete-snapshot snap-aaef70c2
SNAPSHOT snap-aaef70c2

Voiko kahden koneen klusterin tekeminen mennä vielä paljon helpommaksi?