Views: 11934
Last Modified: 22.09.2014

Caching

Caching - Caching is a technique which permits to cache results of work of rarely updated and resource-intensive parts of code (e.g., those actively working with the database).

By providing for an intensive use of caching technique at the terms of reference stage of a project it will be possible to keep database load to a minimum. It will permit your project to support significant loads later on.

Note: The use of caching in a project should be stipulated in the terms of reference in advance, because once the project is launched, the implementation of caching will be significantly more expensive and complex.

Two classes are created in the system in order to implement caching:

Caching results are stored as files in the catalog /bitrix/cache/. If the caching time has not expired, a preliminary created cache file will be connected instead of a resource-intensive code.

The correct use of cache permits to significantly increase general performance of a website. However, it must be taken into account that unreasonable use of cache may result in a serious enlargement of the /bitrix/cache/ catalog.

Example of HTML Caching

<?
// create an object
$obCache = new CPageCache; 

// caching time - 30 minutes
$life_time = 30*60; 

// form cache identifier depending on all parameters
// which may affect the resulting HTML
$cache_id = $ELEMENT_ID.$IBLOCK_TYPE.$USER->GetUserGroupString(); 

// initialize output buffering
if($obCache->StartDataCache($life_time, $cache_id, "/")):

    // select infoblock element parameters from the base
    if($arIBlockElement = GetIBlockElement($ELEMENT_ID, $IBLOCK_TYPE)):
        echo "<pre>"; print_r($arIBlockElement); echo "</pre>";
    endif;

    // write preliminary buffered output in the cache file
    $obCache->EndDataCache(); 

endif;
?>

In this example, the method CPageCache::StartDataCache will check the availability of unexpired and valid cache file. If such file exists, it will be connected and displayed on the screen. Otherwise, buffering will be on. Buffering results will be written in the cache file using the method CPageCache::EndDataCache.

The first parameter of the method CPageCache::StartDataCache sets up a time interval in seconds during which the cache file will be considered valid and unexpired (time interval is counted from the time when the cache file is created).

The second parameter indicates the unique identifier of this cache instance. Here, it must be stressed that if any variables can affect the result of the cached code execution, their values must be included in this identifier.

For example:

  • If the current user authorization can affect the result of the cached code, the result of execution of the function CUser::GetUserGroupString which returns a string with current user group IDs must be added to the identifier.
  • If you use page navigation in the cached code, this identifier must contain the result of work of the function CDBResult::NavStringForCache.
  • If sorting is used, do not forget that the identifier must contain values of the variables which store the field by which sorting is made and the sorting order (e.g., $by.$sort).

Example of Caching of HTML and PHP Variables

<?
// create an object
$obCache = new CPHPCache; 

// caching time – 30 minutes
$life_time = 30*60; 

// form cache identifier depending on all parameters
// which may affect the resulting HTML
$cache_id = $ELEMENT_ID.$SECTION_ID.$USER->GetUserGroupString(); 

// if cache exists and it has not expired
if($obCache->InitCache($life_time, $cache_id, "/")):
    // obtain cached variables
    $vars = $obCache->GetVars();
    $SECTION_TITLE = $vars["SECTION_TITLE"];
else :
    // otherwise access the base
    $arSection = GetIBlockSection($SECTION_ID);
    $SECTION_TITLE = $arSection["NAME"];
endif;

// add a menu option to the navigation chain
$APPLICATION->AddChainItem($SECTION_TITLE, $SECTION_URL."SECTION_ID=".$SECTION_ID);

// start output buffering
if($obCache->StartDataCache()):

    // select parameters of the infoblock element from the base
    if($arIBlockElement = GetIBlockElement($ELEMENT_ID, $IBLOCK_TYPE)):
        echo "<pre>"; print_r($arIBlockElement); echo "</pre>";
    endif;

    // write preliminary buffered output to the cache file
    // along with the additional variable
    $obCache->EndDataCache(array(
        "SECTION_TITLE" => $SECTION_TITLE
        )); 
endif;
?>

This example differs from the previous one because in addition to HTML PHP variable $SECTION_TITLE is also cached. The structure and type of cached PHP variables can be arbitrary. The method CPHPCache::InitCache checks the availability of an unexpired and valid cache file. If such a file is found, it is connected, and all the cached variables will be available after using the method CPHPCache::GetVars. The method CPHPCache::EndDataCache, in addition to buffered HTML code, also writes PHP variables to the cache file.

In order to deactivate caching on one page you have to log in with administrative rights and call this page with the parameter &clear_cache=Y. If, having logged in with administrative rights, you call any page with the parameter &clear_cache_session=Y, the cache will be deactivated for all pages which will be viewed during the session. Cache files can be deleted in the administrative parts on the settings page of the main module.


Alternative Ways for Cache Storage

Now that we have made sure that the use of caching technique for a website is needed and caching must be planned when preparing the terms of reference, let us consider the following situation.

Let us assume that after a certain time your website will become a popular resource. By actively using the caching technique you have secured the database against high load, and it will be able to withstand a three to fivefold overload.

However, due to the website specifics, you have collected a large volume of cached data (tens of thousands of files) which are inconvenient for use because the load on the disc subsystem has also increased. Also, unfortunately, some errors were made at the developing stage, and cached data are not deleted in full, that is why their volume on the disc keeps on growing.

There is a solution:


memcached

When using memcached , temporary data will be stored in RAM. An inexpensive server with a capacity of several gigabytes can be allocated for cache storage.

At the same time, outdated data will be forced out automatically. Let us assume that you have allocated 4 GB in memcached for caching. That way you can be sure that cache will not exceed 4 GB, and the data used less frequently will be forced out (LRU algorithm). It is a very convenient and efficient procedure.

memcached is connected in the file dbconn.php.

Default settings must be changed to ensure efficient operation of the system. Examples:

// Memcached with a storage capacity of 2GB, 8 streams, and operation through tcp
PORT="11211"
USER="memcached"
MAXCONN="10240"
CACHESIZE="2048"
OPTIONS="-t 8"

// settings in dbconn.php
define("BX_CACHE_TYPE", "memcache");
define("BX_CACHE_SID", $_SERVER["DOCUMENT_ROOT"]."#01");
define("BX_MEMCACHE_HOST", "127.0.0.1");
define("BX_MEMCACHE_PORT", "11211");
// Memcached with a storage capacity of 2GB, 8 streams, and operation through socket
PORT="11211"
USER="bitrix"
MAXCONN="10240"
CACHESIZE="2048"
OPTIONS="-t 8 -s /tmp/memcached.sock"

// настройки в dbconn.php
define("BX_CACHE_TYPE", "memcache");
define("BX_CACHE_SID", $_SERVER["DOCUMENT_ROOT"]."#01");
define("BX_MEMCACHE_HOST", "unix:///tmp/memcached.sock");
define("BX_MEMCACHE_PORT", "0");

If memcached is used on one computer at the same place where the web server is located, the use of a socket will be faster.

Links on the Subject:


Alternative PHP Cache (APC)

APC is connected in the file dbconn.php:

// settings in dbconn.php
define("BX_CACHE_TYPE", "apc");
define("BX_CACHE_SID", $_SERVER["DOCUMENT_ROOT"]."#01");

For more information about installation and setup of the PHP accelerator, please refer to the documentation at http://php.net/manual/en/book.apc.php.


Caching in Own Components

Detailed description of caching in components is described in the lesson Caching in Own Components in the chapter Components.


Recommendations for Working with Cache

  • Optimize the project so that complexity and amount of queries be minimal if no caching is used. For example, specific indexes may be required for the project in order to simplify queries. Also, sometimes breaking down one complex query by several more simple and easy ones may prove to be the most efficient solution. It will reduce the general load on the database and permit using cache more efficiently.
  • Choose the appropriate caching time. A short time will make the cache update more frequently, and it will create additional (excessive) server load, especially if the data do not change.

    A bigger caching time is preferable. Actuality of data in cache shall be maintained using Tagged caching. In this case cache will be updated only in case of data change, and, accordingly, there will be no excessive server load as when the time is short and when the cache is created upon the expiry of the indicated time period irrespective of the data actuality.

  • When generating the cache identifier only the necessary parameters shall be taken into account; excessive variability shall be avoided.
    An incorrect identifier will result in inefficient caching because the majority of hits will strike outside the cache.

    The example of cache for news, when the activity term of a piece of news will expire soon, and it is sufficient to create cache for the entire day only once:

    // Incorrect ID, because in this case a new cache will be created for each hit.
    // (Provided that we have to select all elements which are active on this day.)
    
    $arFilter = array(
        'IBLOCK_ID' => 19,
        'ACTIVE' => 'Y',
        '>=PROPERTY_end_date' => date("Y-m-d H:i:s")
    );
    
    $CACHE_TIME = 86400;
    $CACHE_ID = "some_key_iblock".implode('_', $arFilter);
    $obCache = new CPHPCache;
    
    if($obCache->InitCache($CACHE_TIME, $CACHE_ID, "/"))
    {
        $arVars = $obCache->GetVars();
    }
    
    // Correct ID, because in this case cache will be created for the entire day.
    // (Provided that we have to select all elements which are active on this day.)
    $arFilter = array(
        'IBLOCK_ID' => 19,
        'ACTIVE' => 'Y',
        '>=PROPERTY_end_date' => date("Y-m-d 00:00:00")
    );
    
    $CACHE_TIME = 86400;
    $CACHE_ID = "some_key_iblock".implode('_', $arFilter);
    $obCache = new CPHPCache;
    
    if($obCache->InitCache($CACHE_TIME, $CACHE_ID, "/"))
    {
        $arVars = $obCache->GetVars();
    }
    



Courses developed by Bitrix24