Laravel 5 oferuje prosty i elastyczny mechanizm obsługi pamięci cache. Od klasycznego opartego o system plików, przez bazę danych, aż po mechanizmy bazujące na pamięci - Memcached i Redis. Na szczególną uwagę zasługują te dwa ostatnie.
Różnice pomiędzy tymi dwoma usługami są dobrze opisane, zalety i wady każdego z nich bez problemu odszukacie w Sieci. Generalnie Redis cieszy się zasłużoną opinią lepszego - jest bardziej wydajny, uniwersalny i niezawodny. Jednak decyzja, który z nich wybrać jest powiązana z rodzajem aplikacji, którą ma wspierać.
Dla stron z dominującymi treściami statycznymi, gdzie aktualizacje są sporadyczne, a struktury niezbyt skomplikowane (memcached serializuje przechowywane obiekty), memcached będzie dobrym i wystarczającym rozwiązaniem. Także tam, gdzie ilość treści jest bardzo duża. Współcześnie większość dystrybycji Linuxa i innych *nixów ma tę usługę dostępną z klucza, a nawet jeżeli tak nie jest, to instalacja z pakietów jest banalna.
Jeżeli jednak chcemy z pamięci cache korzystać przy bardziej skomplikowanych i dynamicznych projektach, w których planujemy w cache przechowywać obiekty o różnych właściwościach i typach (sie tylko string), to zdecydowanie Redis wykazuje tu swoją przewagę.
Instalacja serwera Redis
(za Digital Ocean)
W środowisku Ubuntu pakiet możemy zainstalować klasycznie używając:
sudo add-apt-repository ppa:chris-lea/redis-server
sudo apt-get update
sudo apt-get install redis-server
Jednak warto w tym przypadku istalację wykonać ze źródeł i może to wyglądać tak:
$ sudo apt update
$ sudo apt full-upgrade
$ sudo apt install build-essential tcl
#pobranie najnowszej wersji stabilnej
$ curl -O http://download.redis.io/redis-stable.tar.gz
#rozpakowanie do katalogu redis-stable
$ tar xzvf redis-stable.tar.gz
#instalacja
$ cd redis-stable
$ make
$ make test
$ sudo make install
Konfiguracja
Jeżeli wszystko zakończy się powodzeniem, to możemy przystąpić do podstawowej konfiguracji.
#tworzymy katalog, w którym będą nasze pliki konfiguracyjne
$ sudo mkdir /etc/redis
#kopiujemy wzorcowy plik konfiguarcji dostarczony z pakietem
$ sudo cp /ścieżka-do-źródła/redis-stable/redis.conf /etc/redis
#otwieramy w edytorze
$ sudo nano /etc/redis/redis.conf
Teraz wprowadzimy tylko dwie zmiany:
# 1. odszukujemy linię z parametrem "supervised" i nadajemy mu wartość "systemd"
. . .
# If you run Redis from upstart or systemd, Redis can interact with your
# supervision tree. Options:
# supervised no - no supervision interaction
# supervised upstart - signal upstart by putting Redis into SIGSTOP mode
# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
# supervised auto - detect upstart or systemd method based on
# UPSTART_JOB or NOTIFY_SOCKET environment variables
# Note: these supervision methods only signal "process is ready."
# They do not enable continuous liveness pings back to your supervisor.
supervised systemd
. . .
# 2. odszukujemy linię z parametrem "dir" (working directory) i przypisujemy mu ścieżkę w naszym systemie plików
. . .
# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir /var/lib/redis
. . .
Po wykonaniu tych dwóch zmian nasz serwer Redis jest właściwie gotowy do pracy. Pozostało nam jeszcze zadbać o jego automatyczne uruchomianie. Do tego celu zgodnie z wcześniejszym wpisem w pliku konfiguracyjnym, użyjemy systemd:
#tworzymy plik startowy w katalogu /etc/systemd/system/ (Ubuntu)
$ sudo nano /etc/systemd/system/redis.service
#i umieszczamy w nim wymagane definicje
[Unit]
Description=Redis Cache Server
After=network.target
[Service]
User=redis
Group=redis
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
ExecStop=/usr/local/bin/redis-cli shutdown
Restart=always
[Install]
WantedBy=multi-user.target
Pozostało nam jeszcze stworzenie dedykowanego użytkownika i grupy oraz utworzenie katalogu roboczego, którego ścieżkę podaliśmy w pliku konfiguracyjnym.
$ sudo adduser --system --group --no-create-home redis
$ sudo mkdir /var/lib/redis
$ sudo chown redis:redis /var/lib/redis
$ sudo chmod 770 /var/lib/redis
Uruchomienie i testy
Dotarliśmy do końca procesu instalacji, możemy uruchomić nasz serwer Redis i go przetestować.
# uruchomienie ręczne
$ sudo systemctl start redis
# sprawdzamy status
$ sudo systemctl status redis
Jeżeli wszysko jest ok, to otrzymamy taki komunikat:
● redis.service - Redis In-Memory Data Store
Loaded: loaded (/etc/systemd/system/redis.service; enabled; vendor preset: enabled)
Active: active (running) since pon 2018-05-07 03:13:43 CEST; 13h ago
Main PID: 23562 (redis-server)
CGroup: /system.slice/redis.service
└─23562 /usr/local/bin/redis-server 127.0.0.1:6379
Zadowoleni możemy jeszcze sprawdzić działanie używając do tego celu narzedzia redis-cli:
$ redis-cli
$ 127.0.0.1:6379> set test "Działa !!!"
$ OK
$ 127.0.0.1:6379> get test
$ Działa !!!
$ exit
Pozostało jeszcze przystosowanie serwera Redis do automatycznego uruchamiania.
$ sudo systemctl enable redis
Created symlink from /etc/systemd/system/multi-user.target.wants/redis.service to /etc/systemd/system/redis.service.
I to wszystko, serwer jest gotowy do działania. Jeżeli planujemy korzystać z jego zalet w projektach PHP, to na początek warto zapoznać się z tym artykułem, który w prostych żołnierskich słowach opisuje pierwsze kroki. Zresztą serwer Redis ma imponującą dokumentację, a w Sieci bez problemu można znaleźć porady na każdy temat z nim związany.
Laravel i Redis
Mając poprawnie skonfigurowany serwer Redis możemy korzystać z jego usług w swoich projektach Laravel. Tradycyjnie, konfiguracja jest prosta i logiczna, odbywa się w dwóch krokach:
1. Plik config/cache.php
Otwieramy w edytorze i odszukujemy w sekcji "sotres" pozycję "redis":
'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
# i definiujemy np. dwa nowe "magazyny"
'redis-model' => [
'driver' => 'redis',
'connection' => 'model-cache',
],
'redis-responsecache' => [
'driver' => 'redis',
'connection' => 'response-cache',
],
Nazwy identyfikują kolejne bazy danych serwera Redis, których bedziemy uzywali do różnych celów. Dzięki temu zyskamy dodatkową elastyczność przy zarządzaniu zawartością cache z poziomu naszych skryptów - działania w odrębnych bazach danych są niezależne, nie wpływają na zasoby przechowywane w innych.
W powyższym przykładzie 'redis' jest magazynem podstawowym, a dwa kolejne zostały utworzenie w celu przypisania ich do:
- przechowywania modeli (pakiet Laravel-model-caching)
- przechowywania odpowiedzi żądań GET (pakiet Laravel-responsecache)
2. Plik config/database.php
Teraz musimy jeszcze zdefiniować bazy danych powiązane z magazynami. Otwieramy plik w edytorze, odszukujemy sekcję "redis" i do definicji domyślej dopisujemy dwie kolejne skojarzone z nazwami zapisanymi w poprzednim kroku:
'redis' => [
'client' => 'predis',
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
'model-cache' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 1,
],
'response-cache' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 2,
],
],
Ważne jest nadanie wartości parametrom 'database', nie muszą być kolejne, ważne, żeby były różne.
I to by było na tyle. Dzięki takiej konfiguracji zyskujemy możliwość korzystania z szybkiego i wydajnego mechanizmu cache, do którego w swoich skryptach mamy dostęp na kilka sposobów, w tym także bezpośrednio, co dobrze opisane jest w dokumentacji. Możemy oczywiście zdefiniować w globalnej konfiguracji serwer Redis jako podstawowy cache - wystarczy zmienić odpowiednie wartości w pliku .env. Możemy także dać dostęp pakietom, które mogą na tym skorzystać, jak np. te dwa opisane przeze mnie powyżej.
Po uruchomieniu możemy sprawdzić status Redis poleceniem info:
$ redis-cli
127.0.0.1:6379>info
# Server
redis_version:4.0.9
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:7478e950d9b8196
redis_mode:standalone
os:Linux 3.14.32-xxxx-grs-ipv6-64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:5.4.0
process_id:23562
run_id:4ccad9419e3a4a46dc4e5b36e4f7dfef059b6c22
tcp_port:6379
uptime_in_seconds:52900
uptime_in_days:0
hz:10
lru_clock:15759083
executable:/usr/local/bin/redis-server
config_file:/etc/redis/redis.conf
...
...
...
# CPU
used_cpu_sys:25.01
used_cpu_user:12.47
used_cpu_sys_children:0.12
used_cpu_user_children:1.25
# Cluster
cluster_enabled:0
# Keyspace
db0:keys=5,expires=0,avg_ttl=0
db1:keys=192,expires=0,avg_ttl=0
db2:keys=2,expires=0,avg_ttl=0
Na pożegnanie
Jak widać, instalacja nie jest szczególnie wymagająca, w kilka minut można tchnąć nowe życie w nasz projekt. Warto spróbować.