How to deal with Route caching in Laravel 5.2

As we all know caching helps site to load faster . When a new visitor comes to your site a saved or cached page is served instead sending bulk request to a server ! you can learn more here about caching https://en.wikipedia.org/wiki/Cache_%28computing%29 . so today you will learn abouut Route caching in laravel 5.2 . which helps to speed things up. In Laravel 5.2 , a caching mechanism was introduced to speed up the execution

Lets take a simple example of routes.php

Route::post('reserve-room', 'ReservationController@store');

Route::controllers([
  'auth' => 'Auth\AuthController',
  'password' => 'Auth\PasswordController',
]);
Route::post('/bookRoom','ReservationsController@reserve', ['middleware' => 'auth', 'domain'=>'booking.hotelwebsite.com']);

Route::resource('rooms', 'RoomsController');

Route::group(['middleware' => ['auth','whitelist']], function()
{

  Route::resource('accommodations', 'AccommodationsController');
  Route::resource('accommodations.amenities', 'AccommodationsAmenitiesController');
  Route::resource('accommodations.rooms', 'AccommodationsRoomsController');
  Route::resource('accommodations.locations', 'AccommodationsLocationsController');
  Route::resource('amenities', 'AmenitiesController');
  Route::resource('locations', 'LocationsController');
});

By running the following command, Laravel will cache the routes:

$ php artisan route:cache

Then, place them into the following directory:

/vendor/routes.php

Here is a small portion of the resultant file:

<?php

/*

| Load The Cached Routes
|--------------------------------------------------------------------------
|
| Here we will decode and unserialize the RouteCollection instance that
| holds all of the route information for an application. This allows
| us to instantaneously load the entire route map into the router.
|
*/
app('router')->setRoutes(
  unserialize(base64_decode('TzozNDoiSWxsdW1pbmF0ZVxSb3V0aW5nXF JvdXRlQ29sbGVjdGlvbiI6NDp7czo5OiIAKgByb3V0ZXMiO2E6Njp7czozOiJH RVQiO2E6NTA6e3M6MToiLyI7TzoyNDoiSWxsdW1pbmF0ZVxSb3V0aW5nXFJvdX RlIjo3OntzOjY6IgAqAHVyaSI7czoxOiIvIjtzOjEwOiIAKgBtZXRob2RzIjth OjI6e2k6MDtzOjM6IkdFVCI7aToxO3M6NDoiSEVBRCI7fX
...
Db250cm9sbGVyc1xBbWVuaXRpZXNDb250cm9sbGVyQHVwZGF0ZSI7cjoxNDQx O3M6NTQ6Ik15Q29tcGFueVxIyb2xsZXJzXEhvdGVsQ29udHJvbGxlckBkZXN0c m95IjtyOjE2MzI7fX0='))
);

As the DocBlock states, the routes are encoded in base64 and then serialized:

unserialize(base64_decode( … ));

This performs some precompilation. If we base64 decode the contents of the file, we obtain the serialized data. The following code is an extract of the file:

O:34:"Illuminate\Routing\RouteCollection":4:{s:9:"*routes"; a:6:{s:3:"GET";a:50:{s:1:"/";O:24:"Illuminate\Routing\Route": 7:{s:6:"*uri";s:1:"/";s:10:"*methods";a:2:{i:0;s:3:"GET";i:1; s:4:"HEAD";}s:9:"*action";a:5:{s:4:"uses";s:50:"MyCompany \Http\Controllers\WelcomeController@index";s:10:"controller"; s:50:"MyCompany\Http\Controllers\WelcomeController@index"; s:9:"namespace";s:26:"MyCompany\Http\Controllers";s:6:"prefix"; N;s:5:"where";a:0:{}}s:11:"*defaults";a:0:{}s:9:"*wheres"; a:0:{}s:13:"*parameters";N;s:17:"*parameterNames";N; }s:4:"home";O:24:"Illumin…

"MyCompany\Http\Controllers\HotelController@destroy";r:1632;}}

If the /vendor/routes.php file exists, it is used instead of the routes.php file that is located at /app/Http/routes.php. If at some point using the route caching file is no longer desired, use the following artisan command:

$ php artisan route:clear

This command will delete the cached routes file and Laravel will begin using the /app/Http/routes.php file again.

Tip

It is important to note that if there are any closures used in the routes.php file, then caching will fail. Here is an example of a closure in a route:

Route::get('room/{$id}', function(){
  return Room::find($id);
});

It is inadvisable to use closure in the routes.php file for any reason. To be able to use route caching, relocate the code used within the closure into a controller.

Illuminate routing

All of this work speeds up an important part of the request life cycle, the routing. In Laravel, the routing class is located inside the illuminate/routing namespace:

<?php namespace Illuminate\Routing;
use Closure;
use LogicException;
use ReflectionFunction;
use Illuminate\Http\Request;
use Illuminate\Container\Container;
use Illuminate\Routing\Matching\UriValidator;
use Illuminate\Routing\Matching\HostValidator;
use Illuminate\Routing\Matching\MethodValidator;
use Illuminate\Routing\Matching\SchemeValidator;
use Symfony\Component\Routing\Route as SymfonyRoute;
use Illuminate\Http\Exception\HttpResponseException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

Examining the use operators, it is clear that the routing mechanism consists of quite a few classes. The most important line is as follows:

use Symfony\Component\Routing\Route as SymfonyRoute;

Laravel uses Symfony’s routing class. However, a new routing package written by Nikita Popov has emerged. FastRoute is a fast request router that is faster than other routing packages and addresses some of the issues of the existing routing packages. This component is one of the major advantages of the of the Lumen microframework

Lean application development

We will use an example, a simple public-facing RESTful API. This RESTful API displays the names and addresses of a list of accommodations in JSON format to any user via GET:

  • If no passwords are to be used, then ext/mcrypt is not needed.
  • If no date calculations are to performed, then nesbot/carbon is not needed. Since there is no HTML interface, then the following libraries involved in testing the HTML of an application, symfony/css-selector and symfony/dom-crawler, will not be needed.
  • If no e-mail is to be sent to the user, then neither illuminate/mail nor swiftmailer/swiftmailer is needed.
  • If no special interaction with the filesystem is needed, then there is no need for league/flysystem.
  • If not commands that are to run from the command line, then the symfony/console is not needed.
  • If Redis is not needed, then illuminate/redis may be left out.
  • If specific configuration values will not be needed for different environments, then vlucas/phpdotenv is not needed.

Tip

The vlucas/phpdotenv package is a suggested package in the composer.json file.

It is clear that the decision to remove certain packages has been done carefully so as to lighten up Lumen as needed with the simplest of applications in mind.

Read/write

Laravel has another great mechanism for helping its performance in the enterprise: read and write. This is related to database performance, but the functionality is so easy to set up that any application can take advantage of its usefulness.

Regarding MySQL, the original MyISAM database engine required a lock on the entire table during inserts, updates, and deletes. This caused massive bottlenecks during large operations that modified the data and select queries waited to access these tables. With the introduction of InnoDB, UPDATE, INSERT, and DELETE SQL statements required a lock only at the row-level. This tremendously impacted performance, since selects could read from various parts of a table where other operations were taking place.

MariaDB, a MySQL fork, claims faster performance than the traditional MySQL. Replacing the database engine with TokuDB will give even higher performance, especially in a big data setting.

Another mechanism to speed up performance of the database is the use of a master/slave configuration. In the following diagram, all of the operations are performed on a single table. The inserts and updates will lock down single rows and the select statements will be performed as allocated.

Traditional database table actions

 

Master table

The master/slave configuration uses a master table that allows SELECT, UPDATE, and DELETE statements. These statements modify the table or write to it. There may also be multiple master tables. Each master table is kept continually synchronized: changes made to any table needs to be communicated to the master table.

Slave table

The slave table is a slave to the master. It depends on the master table for its changes. SQL clients can only perform read operations (SELECT) from it. There may also be multiple slaves that depend on one or more multiple master tables. The master table communicates all of its changes to all the slaves. The following diagram shows the basic architecture of a master/slave setup:

Master and slave (read/write setup)

This continual synchronization adds slight overhead to the database structure; however, it presents important advantages:

Since only SELECT statements can be performed on the slave table while INSERT, UPDATE, and DELETE statements can be performed on the master table, the slave table is free to accept many SELECT statements freely, without having to “wait” for any operations involving the same rows to finish.

An example of this would be a currency exchange rate or stock price table. This table would be continually updated in real time with the latest values, possibly even many times per second. Obviously, a website that allows many users to access this information could potentially have thousands of visitors. Also, the web page used to display this data may make continual multiple requests per user.

Performing many SELECT statements would be slightly slower when there are UPDATE statements that need to access the same data at the same time.

By using a master/slave configuration, the SELECT statements would be performed only on the slave table. This table receives only the data that has changed in an extremely optimized way.

In plain PHP using a library such as mysqli, there could be two database connections configured:

$master=mysqli_connect('127.0.0.1:3306','dbuser','dbpassword','mydatabase');
$slave=mysqli_connect('127.0.0.1:3307','dbuser','dbpassword','mydatabase');

In this simplified example, the slave is set up on the same server machine. In a real application, it would most likely be set up on another server machine to take advantage of separate hardware.

Then, all of the SQL statements which involve a write statement would be performed on the slave and read would be performed on the master.

This would add some overhead to the programming efforts, as a different connection would need to be passed into each SQL statement:

$result= mysqli_real_query($master,"UPDATE exchanges set rate='1.345' where exchange_id=2");
$result= mysqli_query($slave,"SELECT rate from exchanges where exchange_id=2");

In the preceding code example, it would be prudent to remember which SQL statements should be used for the master and which SQL statements should be used for the slave.

Configuring read/write

As stated before, code written in Eloquent is converted into fluent query-builder code. This code is then converted to PDO, which is a standard wrapper around the various database drivers.

Laravel provides the ability to manage master/slave configurations though its read/write configuration. This allows programmers to write Eloquent and fluent query-builder code without having to worry about whether the queries will be executed on the master or slave table. Also, a software project that starts out with a non-master/slave configuration and later needs to scale up to a master/slave setup will only need to change one aspect of the database configuration. The database configuration file is located at config/database.php.

As an element of the connections array, an entry with the key mysql will be created with the following configuration:

'connections' =>
'mysql' => [
    'read' => [
        'host' => '192.168.1.1',
     'password'  => 'slave-Passw0rd', 
    ],
    'write' => [
        'host' => '196.168.1.2',
    'username'  => 'dbhostusername'    
    ],
    'driver'    => 'mysql',
    'database'  => 'database',
    'username'  => 'dbusername',
    'password'  => 's0methingSecure',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
],

The read and write represent slave and master respectively. Since the parameters cascade, if the username, password, and database name are the same, then only the IP address of the host name needs to be listed. However, any values can be overridden. In this example, the read has a password that is different from that of the master and the write has a username that is different from the slave.

Deven Rathore

Deven is an Entrepreneur, and Full-stack developer, Constantly learning and experiencing new things. He currently runs CodeSource.io and Dunebook.com.

Published by
Deven Rathore
Tags: laravel

Recent Posts

3 Ways to Get the Most Out of Your University’s Virtual Computer Lab

IT is more important than ever in the world of higher education, and yet with…

20 hours ago

Top Tips for Learning Java Programming

If you’re here for the top tips, we assume you’re ahead of the “how to…

1 day ago

Neural Networks for Creating Blog Texts

The world is progressing at unprecedented rates at the current moment, especially in terms of…

2 days ago

Top 20 Opensource Python Tkinter Projects

This article will highlight the Top 20 Opensource Python Tkinter Projects which we believe will…

4 days ago

Beginners guide to Sneaker Proxies

With their numerous applications in streamlining the data flow, securing both the servers and the…

1 week ago

Top 20 Node.js dashboard templates

In this article, We will be looking at some of the top Node.js dashboard templates.…

1 week ago