Got a tip? Let us know

                 


Caching in Yii2 and speed comparisons

June 26,2019 0 comments

Most of the time developers tend to ignore caching completely without realizing that it could make or break their applications. Users are easily distracted. Even a single second delay in load time could mean you lose a customer or a user to a competitor.

Yii2 framework stands out for supporting caching out of the box. It supports fragment caching, data caching, page caching and dynamic content. The caching storage component can be swapped without having to change the code that uses the cache

In this tutorial, we are going to discuss the most commonly used caching components supported in Yii2, learn how to configure them and finally use basic examples to test and compare the speeds of the components.

Cache Configure

The first step is to configure the cache component to use one of the Yii2 available components. This is done in the config cache section. For example, to use file caching component, all we need to do is to configure the section as shown below:


'cache'           => [
  'class' => 'yii\caching\FileCache',
],

The most commonly used cache components are:

  • FileCache
  • DbCache
  • Array cache
  • Memcache
  • Redis Cache

DbCache Config

To set up Dbcache, we first have to create a cache table. You can find the schema required by Dbcache in Yii2 project directory under vendor\yiisoft\yii2\caching\migrations. Next, configure the application to use Dbcache as is shown below:


'cache' => [
  'class' => 'yii\caching\DbCache',
  // 'db' => 'mydb',
  // 'cacheTable' => 'cache',
],

Memcached Config

It uses PHP Memcache or Memcached extensions.

The installation is pretty straightforward in a Linux environment. However, in a windows environment, you are likely to face a few challenges. You can use this tutorial guide to install it in windows.

Next, configure your application to use Memcache as shown below:


'cache'           => [
  'class'   => 'yii\caching\MemCache',
  'useMemcached' => true,
  'servers' => [
     
        'host'   => 'server1',
        'port'   => 11211,
        'weight' => 60,
     ],
  ],
],

Redis Cache

The first step is to install Redis extension for Yii. Open the project in the console and run the command below:


composer require --prefer-dist yiisoft/yii2-redis:"~2.0.0"  

Next, configure your application to use Redis as shown below:


'redis'     => [
  'class' => 'yii\redis\Connection',
  'hostname' => 'localhost',
  'port' => 6379,
  'database' => 0,

],
'session' => [
  'class' => 'yii\redis\Session',
],
'cache' => [
  'class' => 'yii\redis\Cache',
],

Cache Basic Usage

The cache component class has methods we could use to create, update, get and delete cached data. Let us go through a few of the methods are that are commonly used.

Create/Update Cache

We can create and update cache value using the set() method. It accepts four arguments:

  • Key
  • Value
  • Duration
  • Dependency

For example:


Yii::$app->cache->set( 'key', 'value',20 );

As from version 2.0.11, we can use getOrSet() to get, calculate and store cache. The method first checks if the key exists if not, it creates the key and returns the value as is shown below:


$data = Yii::$app->cache->getOrSet($key, function () {
  return 'data';
});

Retrieve Cache

We can retrieve the value of a cache using the get() method. It requires a key argument to be passed.


 Yii::$app->cache->get( 'key');

Check for Existence

Using the exists() method we can check whether the specified key exists in the cache.


if(Yii::$app->cache->exits( 'key')){
  Yii::$app->cache->get( 'key');
}else{
  Yii::$app->cache->set( 'key', 'value',20 );
}

Remove Cache

We can remove a data item identified by a key using the delete() method.


Yii::$app->cache->delete( 'key')

To remove all data from the cache, you can use the flush() method.

 Yii::$app->cache->flush()

Cache Example

We are going to use a simple example to compare the time it takes to process the request with or without cache. Install a Yii2 project and follow along.

Create Migration

Create a migration called create_posts_table using the command below:


 yii migrate/create create_posts_table

Open the migration file created in the @app/migrations directory and update it as shown below:



use yii\db\Migration;

/**
* Handles the creation of table `posts`.
*/
class m190227_131404_create_posts_table extends Migration
{
   /**
    * {@inheritdoc}
    */
   public function safeUp()
   
       $this->createTable('posts', [
           'id' => $this->primaryKey(),
           'title' => $this->string()->notNull(),
           'content' => $this->text(),
       ]);
   }

   /**
    * {@inheritdoc}
    */
   public function safeDown()
   
       $this->dropTable('posts');
   }
}

Run the command below to create the table:


yii migrate

Create Model and Controller

Using Gii create a model named Posts and a controller PostsController

Gii comes already installed and configured to be used locally in the latest version of Yii2. For more information, you can check out the documentation.

Once all is set up, you can add data to our posts table either manually or create a method to add fake data to the table.

Add the method below to PostsController and use it to generate fake data:



use app\models\Posts;

class PostsController extends \yii\web\Controller
{
  public function actionFake()
  
     $faker = \Faker\Factory::create();

     $posts = new Posts();
     for ( $i = 1; $i <= 500; $i++ ){
     
        $posts->setIsNewRecord(true);
        $posts->id = null;
        $posts->title = $faker->sentence;
        $posts->content = $faker->realText();
        $posts->save(false);
     }

}

Testing Responses Without Cache

Let’s see the time it takes to make a simple database fetch for posts without using a cache component. Add index() function to PostsController as shown below.


/**
* @return array|\yii\db\ActiveRecord[]
*/
public function actionIndex(){
  $posts=Posts::find()->all();
  \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  return $posts;
}

Hit the endpoint(localhost:8080/posts/index) from your browser or Postman as seen below.

WIthout Cache

Testing Responses With Cache

Let’s change the index() method to use caching and see if there will be any significant difference in the response time. Update the method as shown below.


   /**
   * @return array|\yii\db\ActiveRecord[]
   */
  public function actionIndex(){
     $posts = Yii::$app->cache->getOrSet('posts', function () {
        return Posts::find()->all();
     });
     \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
     return $posts;
  }

We are using the getOrSet() method discussed earlier. Hit the URL again and observe the time it takes.

With cache

Results

From the small test done from my laptop, I can safely conclude that a response time when using most cache components are shorter compared to when not using the cache as shown in the table:

Without Cache

Server Hits Response Time
Ist 268ms
2nd 228ms
3rd 224ms
4th 152ms
5th 189ms
Average 212ms

With Cache (File Cache)

Server Hits Response Time
Ist 232ms
2nd 206ms
3rd 130ms
4th 225ms
5th 105ms
Average 180ms

With Cache (DbCache)

Server Hits Response Time
Ist 298ms
2nd 254ms
3rd 198ms
4th 179ms
5th 171ms
Average 240ms

With Cache (Memcached)

Server Hits Response Time
Ist 240ms
2nd 165ms
3rd 130ms
4th 109ms
5th 104ms
Average 150ms

With Cache (Redis)

Server Hits Response Time
Ist 250ms
2nd 112ms
3rd 108ms
4th 96ms
5th 90ms
Average 131ms

Conclusion and Final Thoughts

The response time difference is dismal when we use file and DB cache components but become very significant when we use Redis and Memcached.

It is, therefore, recommended that you use Redis and Memcached when building large applications to improve on the speed.

It is also important to choose the right caching system depending on the kind of applications you are developing. Caching should also be properly designed and tested during development to prevent serving your users with inconsistent data.



Mike Lidbary

You can find me on twitter @mikelidbary.


More in this category: Upvote/Downvote Weighted Ranking System in Laravel Using Bayesian Formula »


Comments

Add Comment