poniedziałek, 27 września 2010

Oracle Coherence - tworzenie klastra

Żeby w pełni wykorzystać możliwości jakie daje Coherence trzeba utworzyć klaster składający się z wielu węzłów. Mogą być one uruchamiane na jednej maszynie lub wielu - zależnie od potrzeb i możliwości sprzętowych.

Zanim przejdę do tego w jaki sposób jest tworzony klaster przypomnijmy sobie co jest wyświetlane podczas uruchamiania węzła w konsoli:
W pierwszej kolejności konsola wyrzuca informację o używanej wersji Coherence. Później trochę informacji o przyłączaniu węzła do klastra (pierwszy uruchamiany węzeł wyświetla tam informację o tworzonym przez niego klastrze).
Krótka sekcja Group jest bardzo ważna ponieważ zawiera adres multicastowy, port oraz wartość TTL. Coherence podczas uruchamiania węzła używa tych parametrów aby nawiązać komunikację z innymi uruchomionymi węzłami. Jeśli z jakimś nawiąże komunikację (oraz nie będzie innych konfiguracyjnych problemów) przyłączy się do jego klastra. Adres multicastowy jest ściśle związany z wersją Coherence. W moim przypadku wersją jest 3.6.0, więc adresem jest 224.3.6.0, dla 3.5.1 będzie to 224.3.5.1. Podobny mechanizm zastosowany został także co do numeru portu, tylko tam wykorzystywany jest numer builda. Taka numeracja została użyta aby zapobiec łączeniu węzłów obsługiwanych przez różne wersje Coherence.
Sekcja MasterMemberSet zawiera dane o wszystkich węzłach przyłączonych do klastra. W pierwszej kolejności wypisany jest aktualny węzeł oraz węzeł najstarszy (ten który najdłużej znajduje się w klastrze). Następnie wymienione są wszyscy członkowie wraz z adresami sieciowymi i portami na których działają.

Jeśli występuje jakiś problem podczas uruchamiania węzła, to najczęściej jest to problem z mutlicastem. W katalogi /bin/ instalacji jest dostępny skrypt multicast-test umożliwiający przetestowanie czy mechanizm ten działa prawidłowo na Twojej maszynie.
Aby uruchomić test tak aby sprawdził działanie na pojedynczej maszynie (najczęstsza konfiguracja podczas tworzenia oprogramowania) można uruchomić skrypt z parametrem -ttl 0:
mutlicast-test -ttl 0
Konsola w odpowiedzi zwróci nam jeśli wszystko jest ok:
Jeśli coś jest nie tak to powinno się sprawdzić konfigurację firewalla oraz inne ustawienia sieciowe.

Domyślnie użycie multicastu do odnajdywania innych węzłów może zostać zastąpione poprzez skonfigurowanie konkretnych adresów IP serwerów (w terminologii Coherence: Well Known Addressess - WKA). Dla ograniczenia klastra tylko do maszyny lokalnej należy w skrypcie cache-server dodać wpis dla parametrów JAVA_OPTS:
-Dtangosol.coherence.wka=localhost
Całkowicie wyłączy to multicast, co może być bardzo pożądane w fazie produkcyjnej projektu.
Po tej operacji zamiast sekcji Group podczas uruchamiania węzła znajdować się będzie sekcja WellKnownAddressesList, np:

WellKnownAddressList(Size=1,
    WKA{Address=192.168.0.2, Port=8088}
    )

Kolejną kwestią podczas tworzenia klastra są porty na których działają węzły. Domyślnie pierwszy węzeł uruchamiany jest na porcie 8088 i jest on zwiększany o 1 dla każdego kolejnego węzła na tej samej maszynie. Jeśli jakaś inna aplikacja zajmuje już dany port możliwe jest skonfigurowanie Coherence aby użył innego numeru jako początkowy poprzez parametr:

-Dtangosol.coherence.localport=[numer portu]

Opcje te mogą być także konfigurowane za pomocą pliku XML, ale o tym już w jednym z następnych odcinków ;-)

sobota, 11 września 2010

Oracle Coherence - działający przykład

Po krótkim wstępie do Oracle Coherence, czas uruchomić prosty przykład z użyciem Javy. Coherence jest dość duży i wymagane jest wprowadzenie w wiele rzeczy zanim będzie można go sprawnie używać, jednak mam nadzieje, że uda mi się wszystko opisać w miarę kolejnych wpisów. Jak na razie zróbmy sobie prosty przykład bez używania konsoli ;-)

Projekt Javy można utworzyć w dowolnym IDE.Ważne tylko aby dodać do niego bibliotekę coherence.jar z paczki pobranej ze strony Oracle.
Zacznijmy od stworzenia klasy która będzie przechowywana w klastrze Coherence. Niech to będzie wałkowany wszędzie pracownik.
Employee.java:
package pl.lstachowiak.coherence.example1;

import java.io.Serializable;
import java.math.BigDecimal;

public class Employee implements Serializable, Comparable {

 private int id;
 private String name;
 private String surname;
 private BigDecimal salary;
 private String city;

 public Employee() {
 }

 public Employee(int id, String name, String surname,
     BigDecimal salary, String city) {
  this.id = id;
  this.name = name;
  this.surname = surname;
  this.salary = salary;
  this.city = city;
 }

 public String getCity() {
  return city;
 }

 public void setCity(String city) {
  this.city = city;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public BigDecimal getSalary() {
  return salary;
 }

 public void setSalary(BigDecimal salary) {
  this.salary = salary;
 }

 public String getSurname() {
  return surname;
 }

 public void setSurname(String surname) {
  this.surname = surname;
 }

 @Override
 public String toString() {
  return "Employee{" + "id=" + id + " name=" + name + " surname="
    + surname + " salary=" + salary + " city=" + city + '}';
 }

 public int compareTo(Object o) {
  Employee other = (Employee) o;
  if (id > other.id) {
   return 1;
  } else if (id < other.id) {
   return -1;
  } else {
   return 0;
  }
 }
}
Jak widać klasa nie różni się niczym w stosunku to standardowych klas typu POJO. Jedyne co zostało dodane to implementacja interfejsu Serializable, ponieważ obiekt będzie przesyłany przez sieć oraz Comparable, żeby było po czym sortować, gdy będzie to potrzebne.
Napomnę tutaj, że Coherence wprowadził swój własny format serializacji obiektów. Jest od  bardziej wydajny, a obiekty po serializacji mniejsze. Więcej o tym w jednym z kolejnych wpisów.

Operacje na Coherence przeprowadźmy w metodzie main...
CoherenceExample1.java:
package pl.lstachowiak.coherence.example1;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import java.math.BigDecimal;
import java.util.Map;
import java.util.Set;

public class CoherenceExample1 {

    public static void main(String[] args) {
  // #1
        NamedCache employees = CacheFactory.getCache("employees");

  // #2
  employees.put(1, new Employee(1, "John", "Travolta", new BigDecimal(300000.0), "New York"));
  employees.put(2, new Employee(2, "Jason", "Statham", new BigDecimal(550000.0), "Chicago"));
  employees.put(3, new Employee(3, "Sylvester", "Stalone", new BigDecimal(600000.0), "Miami"));
  employees.put(4, new Employee(4, "Bruce", "Willis", new BigDecimal(780000.0), "Los Angeles"));
  employees.put(5, new Employee(5, "Chuck", "Norris", new BigDecimal(1300000.0), "Kansas"));
  employees.put(6, new Employee(6, "Steven", "Seagal", new BigDecimal(20100.0), "Lansing"));

  // #3
  System.out.println("Pracownik o ID=1: " + employees.get(1));
  System.out.println("Rozmiar cache: " + employees.size());
  System.out.println("Usuwam: " + employees.remove(5));
  System.out.println("Rozmiar cache: " + employees.size());

  // #4
  Set<Map.Entry> entries = employees.entrySet();
  for (Map.Entry entry : entries) {
   System.out.println(entry.getKey() + ": " + entry.getValue());
  }
    }
}
#1 - pierwszym co trzeba zrobić to uzyskać referencję do Cache w którym będą przechowywane obiekty pracowników. CacheFactory odpowiada za jego stworzenie jeśli nie istnieje i zwrócenie referencji. Obiekt zwracany jest typu NamedCache, który implementuje standardowy interfejs Map z biblioteki Javy.
2# - umieszczanie elementów jest bardzo proste, zwykły put na mapie.
3# - podobnie wszystkie operacje pobierania oraz usuwania, wszystko bardzo intuicyjne
4# - można też pobrać całą listę obiektów w cache. Metoda entrySet() występuję w kilku wersjach, można jest podać także filtr oraz komparator jeśli szukamy odpowiedniego podzbioru obiektów w cache.

Po uruchomieniu powinno nam się pojawić coś podobnego do poniższego ekranu:
Chciałbym tutaj zwrócić uwagę, że nie napisałem nic o uruchamianiu węzła Coherence przed odpalaniem aplikacji. Pomimo tego wszystko działa! Jest tak ponieważ domyślnie aplikacja którą stworzyliśmy automatycznie staje się pełnoprawnym węzłem w klastrze. Często jest to niepożądane zachowanie i można tego uniknąć poprzez uruchomienie jej z parametrem:
-Dtangosol.coherence.distributed.localstorage=false
co prawda nadal aplikacja będzie pełnoprawnym węzłem w klastrze, ale nie będzie przechowywać danych;) Wymagany jest wtedy co najmniej jeden węzeł to robiący aby uniknąć wyjątków po uruchomieniu.