Klastrowanie to może zbyt dumnie powiedziane. Rozwiązanie to wyszukałem gdy chcąc skonfigurować dwa serwery apache do współpracy na rzecz jednego serwisu okazało się, że sejse trzymane są tylko przez jeden serwer a drugi nic o nich nie wie. To oczywiście nie pozwalało na prawidłowe działanie jakiegokolwiek serwisu korzystającego z sesji.

Pomysł jest taki, że zastępujemy domyśny mechanizm przechowywania sesji w plikach na dysku mechanizmem memcache. Ponieważ memcached działa jako usługa sieciowa, różne serwery mogą się odwoływać do puli memcached i odczytywać zapisane w niej dane. W przypadku sesji - nie jest ważne, kto ją utworzył - bo po jej wysłaniu do puli memcached staje się dostępna dla wszystkich klientów php z niej korzystających.

Jednym z pierwszych pytań nasuwających się do takiej kofiguracji jest: a co jeśli serwer memcached padnie? W chwili gdy wiele serwerów apache zależy od jednego serwera memcached jego awaria unieruchamia kaskadowo wszystkie.

Dlatego wykorzystałem konfigurację z dwoma serwerami memcached. Gdy php zapisuje dane w puli memcached dane są wysyłane do wszystkich podanych serwerów (w tym przypadku dwóch). A odczytywanie polega na odpytaniu pierwszego podanego serwera, a jeśli to się nie uda to drugiego. Układ nie jest idealny (jak mamy dwa działające serwery to aż się prosi o loadbalancing) ale zmniejsza prawdopodobieństwo, że awaria pojedynczego elementu położy wszystko.

Z moim problemem moża było sobie poradzić też inaczej, np. zmieniając mechanizm sesji na stronie na taki, który korzysta z bazy danych. O ile w przypadku jednego serwisu nie jest to duży kłopot, to już przy kilku/kilkunastu byłoby to już spore przedsięwzięcie.

Ważną zaletą tego rozwiązanie jest fakt, że nie są wymagane żadne zmiany w istniejących serwisach. Po zmianie mechanizmu w konfiguracji php wszystko powinno działać bez zmian.

Instalacja/Konfiguracja

Najpierw trzeba zainstalować i uruchomić memcached oraz rozszerzenie php5-memcachedo php’a, które da nam możliwość korzystania z niego. U mnie robi się to tak:

apt-get install memcached php5-memcache

Teraz trzeba by wyedytować konfigurację /etc/memcached.conf. Poniżej wycinek z tego pliku z opcjami, które należy ustawić:

# Maksymalna wartość pamięci w MB jaka może być
# wykorzystana przez demona.
# Warto dostosować do swoich potrzeb.
-m 128

# Interfejs, na którym nasłuchiwać będzie usługa.
# Ja dla wygody wybiorę wszystkie :)
-l 0.0.0.0

# można też dostosować port do nasłuchiwania
-p 11211

# użytkownika nieuprzywilejowanego
# (memcached domyślnie startuje jako root)
-u nobody

Wprowadzamy i zapisujemy zmiany. Trzeba zrestartować serwer memcached uruchamiając:

invoke-rc.d memcached restart

Do tego momentu musimy powtórzyć konfigurację na drugiej maszynie (bo inaczej po co klastrować sesje).

Teraz trzeba skonfiguraować php’a aby zamiast używać sesji zapisywanych do plików, korzystał z memcached. Edytujemy php.ini, u mnie akurat w lokalizacji:/etc/php5/apache2/php.ini. Odszukujemy opcje:

session.save_handler = files
;session.save_path = /var/lib/php5

I zamieniamy na:

session.save_handler = memcache
; adresy oczywiście należy dostosować do własnych ustawień
session.save_path = "tcp://localhost:11211, tcp://remotehost:11211"

W kolejnym kroku edytujemy plik konfiguracyjny rozszerzenia php’a dla memcache w /etc/php5/conf.d/memcache.ini dodając takie ustawienia:

extension=memcache.so

[memcache]
memcache.dbpath="/var/lib/memcache"
memcache.maxreclevel=0
memcache.maxfiles=0
memcache.archivememlim=0
memcache.maxfilesize=0
memcache.maxratio=0

; to jedyna wymagana opcja - resztę można dostosować pod siebie
; albo zostawić domyślnie
memcache.allow_failover=1

memcache.max_failover_attempts=20
memcache.default_port=11211
memcache.chunk_size=8192
memcache.hash_strategy=standard
memcache.hash_function="crc32"

Więcej po poszczególnych opcjach można się dowiedzieć z dokumentacji phpexternal link .

Test

Jeżeli zrobiliśmy wszystko jak trzeba to sesje powinny zapisywać się z pamięci memcachedi dystrybuować na wszystkie wpisane w polu save_path serwery. Możemy to sprawdzić wykorzystując np. taki skrypt:

<?php
session_start();

print "Opcja save_handler: "
     . ini_get("session.save_handler") . "<br>";
print "Opcja save_path: "
     . ini_get("session.save_path") . "<br>";

if(isset($_SESSION['testowa'])) {
    print "Testowa sesja jest już ustawiona: " .
        $_SESSION['testowa'] . "<br>";
} else {
    $_SESSION['testowa'] = "i wygląda, że działa dobrze";
    print "Ustawiamy testową sesją wartością: " .
        $_SESSION['testowa'] . "<br>";
}
?>

Wystarczy odświeżyć skrypt kilka razy. Za pierwszym razem sesja zostanie ustawiona a kolejne odświeżenia będą już zwracały jej wartość.

Proponuję też wyłączyć jeden z serwerów memcached aby sprawdzić czy php poprawnie odwoła się do drugiego serwera.