Route caching

Route caching helps to speed things up. In Laravel 5, a caching mechanism was introduced to speed up the execution.

The example routes.php is shown here:

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

Route::controllers([
  'auth' => 'AuthAuthController',
  'password' => 'AuthPasswordController',
]);
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:"IlluminateRoutingRouteCollection":4:{s:9:"*routes"; a:6:{s:3:"GET";a:50:{s:1:"/";O:24:"IlluminateRoutingRoute": 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 HttpControllersWelcomeController@index";s:10:"controller"; s:50:"MyCompanyHttpControllersWelcomeController@index"; s:9:"namespace";s:26:"MyCompanyHttpControllers";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…

"MyCompanyHttpControllersHotelController@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 IlluminateRouting;
use Closure;
use LogicException;
use ReflectionFunction;
use IlluminateHttpRequest;
use IlluminateContainerContainer;
use IlluminateRoutingMatchingUriValidator;
use IlluminateRoutingMatchingHostValidator;
use IlluminateRoutingMatchingMethodValidator;
use IlluminateRoutingMatchingSchemeValidator;
use SymfonyComponentRoutingRoute as SymfonyRoute;
use IlluminateHttpExceptionHttpResponseException;
use SymfonyComponentHttpKernelExceptionNotFoundHttpException; 

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 SymfonyComponentRoutingRoute 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.

Lumen

In soda marketing terms, Lumen could be considered Laravel Light or Laravel Zero. In addition to using the FastRoute routing package, many packages have been removed from Lumen, allowing it to be minimal and reduce its footprint.

Comparison between Laravel and Lumen

The packages in Laravel and Lumen were compared and listed in the following table. These packages are installed when the following command is run:

$ composer update –-no-dev

The preceding command is used when the development is completed and the application is ready for deployment on the server. Tools such as PHPUnit and PHPSpec are obviously excluded at this stage.

The package names are aligned to illustrate where the packages are present in both Laravel and Lumen:

Laravel Packages

Lumen Packages

-

nikic/fast-route

illuminate/cache

-

illuminate/config

illuminate/config

illuminate/console

illuminate/console

illuminate/container

illuminate/container

illuminate/contracts

illuminate/contracts

illuminate/cookie

illuminate/cookie

illuminate/database

illuminate/database

illuminate/encryption

illuminate/encryption

illuminate/events

illuminate/events

illuminate/exception

-

illuminate/filesystem

illuminate/filesystem

illuminate/foundation

-

illuminate/hashing

illuminate/hashing

illuminate/http

illuminate/http

illuminate/log

-

illuminate/mail

-

illuminate/pagination

illuminate/pagination

illuminate/pipeline

-

illuminate/queue

illuminate/queue

illuminate/redis

-

illuminate/routing

-

illuminate/session

illuminate/session

illuminate/support

illuminate/support

illuminate/translation

illuminate/translation

illuminate/validation

illuminate/validation

illuminate/view

illuminate/view

jeremeamia/superclosure

-

league/flysystem

-

monolog/monolog

monolog/monolog

mtdowling/cron-expression

mtdowling/cron-expression

nesbot/carbon

-

psy/psysh

-

swiftmailer/swiftmailer

-

symfony/console

-

symfony/css-selector

-

symfony/debug

-

symfony/dom-crawler

-

symfony/finder

-

symfony/http-foundation

symfony/http-foundation

symfony/http-kernel

symfony/http-kernel

symfony/process

-

symfony/routing

-

symfony/security-core

symfony/security-core

symfony/var-dumper

symfony/var-dumper

vlucas/phpdotenv

-

classpreloader/classpreloader

-

danielstjules/stringy

-

doctrine/inflector

-

ext-mbstring

-

ext-mcrypt

-

At the time of writing, there are 51 packages (shown in the left column) that are installed in Laravel 5.0 using the nondevelopment configuration. Compare this number of packages to the number of packages installed in Lumen (shown in the right column)—there are just 24.

The aforementioned nikic/fast-route package is the only package that Lumen has which Laravel does not. The symfony/routing package is the complimentary package found in Laravel.

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.

Read/write

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:

Slave table

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset