vteam #678 has been working on a telephony web application. To increase the capacity (concurrent users) and reliability of the application, the client required load balancing so that the agents (users) can login from any of the three servers. Additionally, the application’s admin panel was required to display and control the status of all the active agents on any of the three servers.
As the status of agents was changing continuously, some real time features were required. In addition to it, the real time data (like 100 changes per second) must be stored somewhere so that it could be accessed and manipulated later quickly. The following could be the possible solutions to store real time data but it is recommended not to:
- Make dozens of database queries per second
- Share the sessions of the three servers
- Share the files of the three servers
.
Solution
After doing some R&D, it was proposed and later decided to use Redis because it supports many data structures including:
- Strings
- Sets
- Lists
- Hashes, etc.
.
vteams engineer stored the real time data of the client’s application in Redis Hashes. To hold the database, the application already had a dedicated server. The same server was used for this. It was then configured to accept external connections.
To implement the above mentioned solution, setup redis as per the instructions given in the laravel docs. This setup included the “predis/predis” package for Laravel. Since the application had two user guards i.e. “user” and “admin”, it was decided to define a trait which would be responsible for all the communication with It.
<?php
namespace AppTraits;
/**
* Class HasStatusInCache
* @package AppTraits
*/
trait HasStatusInCache
{
/**
* @var string
* Default key used to identify user records
*/
public $cacheKey = 'id';
/**
* @return IlluminateRedisDatabase
* In case we decide to replace Redis with some other cache driver
*/
protected function cacheClient()
{
return app('redis');
}
/**
* @return string
* Used to group objects in the Cache
* e.g. You can set cacheTag for Users as "users" and for Admins as "admins"
* Helpful when if need all the users or admins at once:
* $keys = app("redis")->keys("agents*");
* foreach ( $keys as $key ) {
* $users[] = app("redis")->get($key);
*/
protected function cacheTag()
{
return get_called_class();
}
/**
* @return string
* Actual cache key stored, as a combination of cacheKey and cacheTag
*/
protected function cacheField()
{
$key = $this->{$this->cacheKey};
return "{$this->cacheTag()}:{$key}";
}
/**
* @return mixed
* Get all the key value pairs of the hashed data
*/
public function getCachedStatus()
{
return $this->cacheClient()->hgetall($this->cacheField());
}
/**
* @param $data
* @return mixed
* Sets the key value pairs provided in $data
* By default Redis hashes work in a way that $data is set in such a way that only provided keys are over-written.
* So you only need to provide the fields that you need to set / update
*/
public function setCachedStatus($data)
{
return $this->cacheClient()->hmset($this->cacheField(), $data);
}
/**
* @param $key
* @return mixed
* Get the value for a specific key
*/
public function getCachedStatusValue($key)
{
return $this->cacheClient()->hget($this->cacheField(), $key);
}
/**
* @param $key
* @param $value
* @return mixed
* Set the value for a specific key
*/
public function setCachedStatusValue($key, $value)
{
return $this->cacheClient()->hset($this->cacheField(), $key, $value);
}
}
Now the class (User / Admin) that has status in cache:
class User extends Authenticatable
{
use HasStatusInCache;
public function cacheTag()
{
return "agents";
}
Start Using it:
example: when logging in
private function logIn($user)
{
Auth::login($user);
…
// set status to cache
$user->setCachedStatus($user->toArray());
…
}
example: when something changes
$user->setCachedStatusValue('station', $station->title);
or
// save the current status to cache
$agentStatusData = [
'auxCode' => $status->name,
'auxCodeId' => $status->id
];
$agent->setCachedStatus($agentStatusData);
Conclusion
As a result, the three servers were then able to share their data in an extremely fast data store.
0 Comments