Context
When you scale a PHP application you have to consider several aspects of runtime environment such us:
- Bytecode caching (e.x. APC or Zend Optimizer Plus or eAccelerator), more;
- Reading project files from RAM instead of HDD;
- Caching and minify static content etc.
- One additional aspect is storing sessions.
By default, PHP stores sessions in files. There are also several approaches to speed up saving sessions, such us memcached, mapping save_path folder as ramdisc, etc.
In scaling approaches there is important that many worker nodes (with deployed application) runs the same code, round-robin selected or load-ballanced, but have the same space to store sessions, because there is no guarantee in distributes architecture, that next user’s request will be handled by the same node. This implies, that session memory have to be shared between nodes, unfortunately storing these data in local RAM doesn’t meet this requirement.
Redis as PHP Session Handler
One of additional approach to storing sessions in fast-memory is Redis – key-value store. This could be configured as centralized or distributed database.
There is available a Redis session_handler for PHP. To use it:
- install Redis first as a service [more]
- copy/compile redis.so PHP extension [more information]
- register an extension in php.ini configuration file
- reconfigure session.save_handler in your php.ini configuration file, or set it directly on runtime by writing for e.x.:
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', 'tcp://localhost:6379'); |
Redis Session Handler in Symfony 2
I am using Symfony 2 framework. Unfortunately, 4th step don’t affects the application. You have to register own SessionHandler in config.yml file:
framework:
session:
handler_id: session_handler_redis |
This configuration uses new SessionHandler registered ad session_handler_redis Symfony Service (more).
We have to write own SessionHandler in Symfony. I have found the Redis SessionHandler proposed by Andrej Hudec on GitHub (original code here). I have decided to use and improve existing implementation.
Declare new SessionHandler class somewhere in your project:
<?php
namespace Fokus\Webapp\CommonBundle\SessionHandler;
use \Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler;
/**
* NativeRedisSessionStorage.
*
* Driver for the redis session save hadlers provided by the redis PHP extension.
*
* @see https://github.com/nicolasff/phpredis
*
* @author Andrej Hudec <pulzarraider@gmail.com>
* @author Piotr Pelczar <me@athlan.pl>
*/
class NativeRedisSessionHandler extends NativeSessionHandler
{
/**
* Constructor.
*
* @param string $savePath Path of redis server.
*/
public function __construct($savePath = "")
{
if (!extension_loaded('redis')) {
throw new \RuntimeException('PHP does not have "redis" session module registered');
}
if ("" === $savePath) {
$savePath = ini_get('session.save_path');
}
if ("" === $savePath) {
$savePath = "tcp://localhost:6379"; // guess path
}
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', $savePath);
}
} |
Now, add the entry that declares the class as a Symfony Service in services.yml file:
Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...
Zwiń
Czytaj na blogu autora...