Bu örneğimizde redisi symfony uygulamasında nasıl kullanacağımızı göreceğiz. Örnekte sadece temel özellikleri kullanacağım ama siz isterseniz genişletebilirsiniz. Komutların listesine buradan ve dökümantasyona da buradan ulaşabilirsiniz.


Redis hakkında


Redis ön bellek olarak bilinen bir veri depolama unitesidir (NoSQL veritabanı olarakta anılır). Memcached'in aksine, mevcut durumunu istenildiği zaman diske yazabildiği için, bilgisayar yeniden başlatmalarda veri kaybı olmaz. Veriler ön bellekte (RAM) tutulduğu için, veri toplamı RAM toplamından fazla olamaz. Bu günlerde çoğu kişi, performans nedeniyle memcached ve MongoDB yerine redis kullanmayı tercih ediyor. Redis strings, hashes, lists, sets, sorted sets vs. veri tiplerine sahip ama memcached sadece strings kullanıyor.



Örneğimizde yapılanlar



Kurulum


$ sudo apt-get update
$ sudo apt-get install redis-server
$ sudo service redis-server status

Konfigürasyon dosyası /etc/redis/redis.conf yolundadır.


$ ps aux | grep redis
redis 31748 0.1 0.3 38576 7248 ? Ssl 13:42 0:00 /usr/bin/redis-server 127.0.0.1:6379
vagrant 31917 0.0 0.0 10472 904 pts/0 R+ 13:47 0:00 grep --color=auto redis

Yukarıda da gördüğümüz gibi, host 127.0.0.1 ve port ise 6379'dir. Redis komut satırına ulaşmak için aşağıdaki komutu kullanabilirsiniz. Redis hakkında bilgi almak için info komutunu kullanın.


$ redis-cli
127.0.0.1:6379>

Test


127.0.0.1:6379> monitor
1495812054.054517 [0 127.0.0.1:59164] "SET" "a" "1" # Persistent
1495812054.054517 [0 127.0.0.1:59164] "SETEX" "b" "10" "2" # Expire in 10 seconds

Yukarıda da gördüğümüz gibi, sisteme daha önceden a ve b olmak üzere iki tane anahtar-değer bilgisi girdim. Sistemde o an için çalıştırılan tüm komutları anlık olarak görmek isterseniz monitor komutunu kullanabilirsiniz.


127.0.0.1:6379> scan 0
1) "0"
2) 1) "a"
3) 2) "b"

127.0.0.1:6379> GET a
"1"
127.0.0.1:6379> TTL a
(integer) -1 # Persistent

127.0.0.1:6379> GET b
"2"
127.0.0.1:6379> TTL b # Run this command 3 seconds later
(integer) 7 # 7 seconds to expire
127.0.0.1:6379> TTL b # Run this command 20 seconds later
(integer) -2 # Expired

Eğer TTL'i belirlemezseniz, yarattığınız anahtarın zamanı hiçbir zaman dolmayacak, yani otomatik olarak TTL -1 olarak atanacaktır. Buda teknik olarak "kalıcı" anahtar anlamına gelir.


Redis'i PHP'de aktifleştirme


$ sudo apt-get install php5-redis
$ sudo service apache2 restart

Symfony konfigürasyonu


Composer.json dosyasına "ext-redis": "*" ekleyin ve composer update ext-redis komutunu çalıştırın.


Uygulama


Config.yml


parameters:
redis.host: 127.0.0.1
redis.port: 6379

Controllers.yml


services:
app.controller.redis:
class: AppBundle\Controller\RedisController
arguments:
- "@app.util.redis_helper"

Utils.yml


services:
app.util.redis_helper:
class: AppBundle\Util\RedisHelper
arguments:
- '%redis.host%'
- '%redis.port%'

RedisController


namespace AppBundle\Controller;

use AppBundle\Util\RedisHelper;
use RedisException;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
* @Route("/redis", service="app.controller.redis")
*/
class RedisController
{
private $redisHelper;

public function __construct(RedisHelper $redisHelper)
{
$this->redisHelper = $redisHelper;
}

/**
* @param Request $request
*
* @Method({"GET"})
* @Route("/set")
*
* @return Response
*/
public function setAction(Request $request)
{
$key = $request->query->get('key');
$value = $request->query->get('value');
$ttl = $request->query->get('ttl');

$result = null;

try {
if ($key && $value) {
$this->redisHelper->set($key, $value, $ttl);
$result = ['key' => $key, 'value' => $value, 'ttl' => $ttl];
}
} catch (RedisException $e) {
$result = $e->getMessage();
}

return new Response(json_encode($result));
}

/**
* @param Request $request
*
* @Method({"GET"})
* @Route("/get")
*
* @return Response
*/
public function getAction(Request $request)
{
$key = $request->query->get('key');

$result = null;

try {
if ($key) {
$result = ['key' => $key, 'value' => $this->redisHelper->get($key)];
}
} catch (RedisException $e) {
$result = $e->getMessage();
}

return new Response(json_encode($result));
}

/**
* @param Request $request
*
* @Method({"GET"})
* @Route("/ttl")
*
* @return Response
*/
public function ttlAction(Request $request)
{
$key = $request->query->get('key');

$result = null;

try {
if ($key) {
$result = ['key' => $key, 'ttl' => $this->redisHelper->getTtl($key)];
}
} catch (RedisException $e) {
$result = $e->getMessage();
}

return new Response(json_encode($result));
}

/**
* @param Request $request
*
* @Method({"GET"})
* @Route("/persist")
*
* @return Response
*/
public function persistAction(Request $request)
{
$key = $request->query->get('key');

$result = null;

try {
if ($key) {
$result = ['key' => $key, 'persist' => $this->redisHelper->persist($key)];
}
} catch (RedisException $e) {
$result = $e->getMessage();
}

return new Response(json_encode($result));
}

/**
* @param Request $request
*
* @Method({"GET"})
* @Route("/expire")
*
* @return Response
*/
public function expireAction(Request $request)
{
$key = $request->query->get('key');
$ttl = $request->query->get('ttl');

$result = null;

try {
if ($key) {
$result = ['key' => $key, 'expire' => $this->redisHelper->expire($key, $ttl)];
}
} catch (RedisException $e) {
$result = $e->getMessage();
}

return new Response(json_encode($result));
}

/**
* @param Request $request
*
* @Method({"GET"})
* @Route("/delete")
*
* @return Response
*/
public function deleteAction(Request $request)
{
$key = $request->query->get('key');

$result = null;

try {
if ($key) {
$result = ['key' => $key, 'expire' => $this->redisHelper->delete($key)];
}
} catch (RedisException $e) {
$result = $e->getMessage();
}

return new Response(json_encode($result));
}
}

RedisHelper


Yazan dip notları okuyun!


namespace AppBundle\Util;

use Redis;

class RedisHelper
{
const MIN_TTL = 1;
const MAX_TTL = 3600;

/** @var Redis $redis */
private $redis;
private $host;
private $port;

public function __construct($host, $port)
{
$this->host = $host;
$this->port = $port;
}

/**
* Get the value related to the specified key.
*/
public function get($key)
{
$this->connect();

return $this->redis->get($key);
}

/**
* set(): Set persistent key-value pair.
* setex(): Set non-persistent key-value pair.
*/
public function set($key, $value, $ttl = null)
{
$this->connect();

if (is_null($ttl)) {
$this->redis->set($key, $value);
} else {
$this->redis->setex($key, $this->normaliseTtl($ttl), $value);
}
}

/**
* Returns 1 if the timeout was set.
* Returns 0 if key does not exist or the timeout could not be set.
*/
public function expire($key, $ttl = self::MIN_TTL)
{
$this->connect();

return $this->redis->expire($key, $this->normaliseTtl($ttl));
}

/**
* Removes the specified keys. A key is ignored if it does not exist.
* Returns the number of keys that were removed.
*/
public function delete($key)
{
$this->connect();

return $this->redis->del($key);
}

/**
* Returns -2 if the key does not exist.
* Returns -1 if the key exists but has no associated expire. Persistent.
*/
public function getTtl($key)
{
$this->connect();

return $this->redis->ttl($key);
}

/**
* Returns 1 if the timeout was removed.
* Returns 0 if key does not exist or does not have an associated timeout.
*/
public function persist($key)
{
$this->connect();

return $this->redis->persist($key);
}

/**
* The ttl is normalised to be 1 second to 1 hour.
*/
private function normaliseTtl($ttl)
{
$ttl = ceil(abs($ttl));

return ($ttl >= self::MIN_TTL && $ttl <= self::MAX_TTL) ? $ttl : self::MAX_TTL;
}

/**
* Connect only if not connected.
*/
private function connect()
{
if (!$this->redis || $this->redis->ping() != '+PONG') {
$this->redis = new Redis();
$this->redis->connect($this->host, $this->port);
}
}
}