A Zend_Cache backend for Redis with full support for tags (works great with Magento)

Overview

Zend_Cache backend using Redis with full support for tags

This Zend_Cache backend allows you to use a Redis server as a central cache storage. Tags are fully supported without the use of TwoLevels cache so this backend is great for use on a single machine or in a cluster. Works with any Zend Framework project including all versions of Magento!

FEATURES

  • Uses the phpredis PECL extension for best performance (requires master branch or tagged version newer than Aug 19 2011).
  • Falls back to standalone PHP if phpredis isn't available using the Credis library.
  • Tagging is fully supported, implemented using the Redis "set" and "hash" datatypes for efficient tag management.
  • Key expiration is handled automatically by Redis.
  • Supports unix socket connection for even better performance on a single machine.
  • Supports configurable compression for memory savings. Can choose between gzip, lzf and snappy and can change configuration without flushing cache.
  • Uses transactions to prevent race conditions between saves, cleans or removes causing unexpected results.
  • Supports a configurable "auto expiry lifetime" which, if set, will be used as the TTL when the key otherwise wouldn't expire. In combination with "auto expiry refresh on load" offers a more sane cache management strategy for Magento's Enterprise_PageCache module.
  • Unit tested!

REQUIREMENTS

As this backend uses Credis there are no additional requirements, but for improved performance you can install phpredis which is a compiled extension.

  • For 2.4 support you must use the "master" branch or a tagged version newer than Aug 19, 2011.
  • phpredis is optional, but it is much faster than standalone mode
  • phpredis does not support setting read timeouts at the moment (see pull request #260). If you receive read errors (“read error on connection”), this might be the reason.

INSTALLATION (Composer)

$ composer require colinmollenhour/cache-backend-redis

INSTALLATION (Magento)

You may use the Composer installation (above) or you can install via modman:

* `modman clone https://github.com/colinmollenhour/Cm_Cache_Backend_Redis`

Magento Configuration:

Edit app/etc/local.xml to configure:

    <!-- This is a child node of config/global -->
    <cache>
      <backend>Cm_Cache_Backend_Redis</backend>
      <backend_options>
        <server>127.0.0.1</server> <!-- or absolute path to unix socket -->
        <port>6379</port>
        <persistent></persistent> <!-- Specify unique string to enable persistent connections. E.g.: sess-db0; bugs with phpredis and php-fpm are known: https://github.com/nicolasff/phpredis/issues/70 -->
        <database>0</database> <!-- Redis database number; protection against accidental data loss is improved by not sharing databases -->
        <password></password> <!-- Specify if your Redis server requires authentication -->
        <force_standalone>0</force_standalone>  <!-- 0 for phpredis, 1 for standalone PHP -->
        <connect_retries>1</connect_retries>    <!-- Reduces errors due to random connection failures; a value of 1 will not retry after the first failure -->
        <read_timeout>10</read_timeout>         <!-- Set read timeout duration; phpredis does not currently support setting read timeouts -->
        <automatic_cleaning_factor>0</automatic_cleaning_factor> <!-- Disabled by default -->
        <compress_data>1</compress_data>  <!-- 0-9 for compression level, recommended: 0 or 1 -->
        <compress_tags>1</compress_tags>  <!-- 0-9 for compression level, recommended: 0 or 1 -->
        <compress_threshold>20480</compress_threshold>  <!-- Strings below this size will not be compressed -->
        <compression_lib>gzip</compression_lib> <!-- Supports gzip, lzf, lz4 (as l4z), snappy and zstd -->
        <use_lua>0</use_lua> <!-- Set to 1 if Lua scripts should be used for some operations (recommended) -->
        <load_from_slave>tcp://redis-slave:6379</load_from_slave> <!-- Perform reads from a different server --> 
      </backend_options>
    </cache>

    <!-- This is a child node of config/global for Magento Enterprise FPC -->
    <full_page_cache>
      <backend>Cm_Cache_Backend_Redis</backend>
      <backend_options>
        <server>127.0.0.1</server> <!-- or absolute path to unix socket -->
        <port>6379</port>
        <persistent></persistent> <!-- Specify unique string to enable persistent connections. E.g.: sess-db0; bugs with phpredis and php-fpm are known: https://github.com/nicolasff/phpredis/issues/70 -->
        <database>1</database> <!-- Redis database number; protection against accidental data loss is improved by not sharing databases -->
        <password></password> <!-- Specify if your Redis server requires authentication -->
        <force_standalone>0</force_standalone>  <!-- 0 for phpredis, 1 for standalone PHP -->
        <connect_retries>1</connect_retries>    <!-- Reduces errors due to random connection failures -->
        <lifetimelimit>57600</lifetimelimit>    <!-- 16 hours of lifetime for cache record -->
        <compress_data>0</compress_data>        <!-- DISABLE compression for EE FPC since it already uses compression -->
        <auto_expire_lifetime></auto_expire_lifetime> <!-- Force an expiry (Enterprise_PageCache will not set one) -->
        <auto_expire_refresh_on_load></auto_expire_refresh_on_load> <!-- Refresh keys when loaded (Keeps cache primed frequently requested resources) -->
      </backend_options>
    </full_page_cache>

High Availability and Load Balancing Support

There are two supported methods of achieving High Availability and Load Balancing with Cm_Cache_Backend_Redis.

Redis Sentinel

You may achieve high availability and load balancing using Redis Sentinel. To enable use of Redis Sentinel the server specified should be a comma-separated list of Sentinel servers and the sentinel_master option should be specified to indicate the name of the sentinel master set (e.g. 'mymaster'). If using sentinel_master you may also specify load_from_slaves in which case a random slave will be chosen for performing reads in order to load balance across multiple Redis instances. Using the value '1' indicates to only load from slaves and '2' to include the master in the random read slave selection.

Example configuration:

    <!-- This is a child node of config/global -->
    <cache>
      <backend>Cm_Cache_Backend_Redis</backend>
      <backend_options>
        <server>tcp://10.0.0.1:26379,tcp://10.0.0.2:26379,tcp://10.0.0.3:26379</server>
        <timeout>0.5</timeout>
        <sentinel_master>mymaster</sentinel_master>
        <sentinel_master_verify>1</sentinel_master_verify>
        <load_from_slaves>1</load_from_slaves>
      </backend_options>
    </cache>

Load Balancer or Service Discovery

It is also possible to achieve high availability by using other methods where you can specify separate connection addresses for the master and slave(s). The load_from_slave option has been added for this purpose and this option does not connect to a Sentinel server as the example above, although you probably would benefit from still having a Sentinel setup purely for the easier replication and failover.

Examples would be to use a TCP load balancer (e.g. HAProxy) with separate ports for master and slaves, or a DNS-based system that uses service discovery health checks to expose master and slaves via different DNS names.

Example configuration:

    <!-- This is a child node of config/global -->
    <cache>
      <backend>Cm_Cache_Backend_Redis</backend>
      <backend_options>
        <server>tcp://redis-master:6379</server>
        <load_from_slave>tcp://redis-slaves:6379</load_from_slave>
        <master_write_only>0</master_write_only>  <!-- Use 1 to prevent reads from master -->
        <timeout>0.5</timeout>
      </backend_options>
    </cache>

Static Configuration

You may also statically specify the master and slave servers by passing either an array to load_from_slave or a string with multiple addresses separated by a comma.

    <!-- This is a child node of config/global -->
    <cache>
      <backend>Cm_Cache_Backend_Redis</backend>
      <backend_options>
        <server>tcp://redis-master:6379</server>
        <load_from_slave>tcp://redis-slave1:6379,tcp://redis-slave2:6379</load_from_slave>
        <master_write_only>0</master_write_only>  <!-- Use 1 to prevent reads from master -->
        <timeout>0.5</timeout>
      </backend_options>
    </cache>

ElastiCache

The following example configuration lets you use ElastiCache Redis (cluster mode disabled) where the writes are sent to the Primary node and reads are sent to the replicas. This lets you distribute the read traffic between the different nodes.

The instructions to find the primary and read replica endpoints are here.

    <!-- This is a child node of config/global/cache -->
    <backend_options>
      <server>primary-endpoint.0001.euw1.cache.amazonaws.com</server>
      <port>6379</port>
      <database>0</database>                    <!-- Make sure database is 0 -->
      <master_write_only>1</master_write_only>
      <load_from_slave>
        <node-001>
          <server>replica-endpoint-1.jwbaun.0001.euw1.cache.amazonaws.com</server>
          <port>6379</port>
        </node-001>
        <node-002>
          <server>replica-endpoint-2.jwbaun.0001.euw1.cache.amazonaws.com</server>
          <port>6379</port>
        </node-002>
      </load_from_slave>
    </backend_options>

DEPRECATION NOTICE

Previously the ElastiCache config instructions suggested setting up a <cluster> node but this functionality was flawed and is no longer supported. The config is still parsed and loaded for backwards-compatibility but chooses a random slave to read from rather than using md5 hash of the keys.

RELATED / TUNING

  • The recommended "maxmemory-policy" is "volatile-lru". All tag metadata is non-volatile so it is recommended to use key expirations unless non-volatile keys are absolutely necessary so that tag data cannot get evicted. So, be sure that the "maxmemory" is high enough to accommodate all of the tag data and non-volatile data with enough room left for the volatile key data as well.
  • Automatic cleaning is optional and not recommended since it is slow and uses lots of memory.
  • Occasional (e.g. once a day) garbage collection is recommended if the entire cache is infrequently cleared and automatic cleaning is not enabled. The best solution is to run a cron job which does the garbage collection. (See "Example Garbage Collection Script" below.)
  • Compression will have additional CPU overhead but may be worth it for memory savings and reduced traffic. For high-latency networks it may even improve performance. Use the Magento Cache Benchmark to analyze your real-world compression performance and test your system's performance with different compression libraries.
    • gzip — Slowest but highest compression. Most likely you will not want to use above level 1 compression.
    • lzf — Fastest compress, fast decompress. Install: sudo pecl install lzf
    • snappy — Fastest decompress, fast compress. Download and install: snappy and php-snappy
  • Monitor your redis cache statistics with my modified munin plugin.
  • Enable persistent connections. Make sure that if you have multiple configurations connecting the persistent string is unique for each configuration so that "select" commands don't cause conflicts.
  • Use the stats.php script to inspect your cache to find oversized or wasteful cache tags.

Example Garbage Collection Script (Magento)

<?php PHP_SAPI == 'cli' or die('<h1>:P</h1>');
ini_set('memory_limit','1024M');
set_time_limit(0);
error_reporting(E_ALL | E_STRICT);
require_once 'app/Mage.php';
Mage::app()->getCache()->getBackend()->clean('old');
// uncomment this for Magento Enterprise Edition
// Enterprise_PageCache_Model_Cache::getCacheInstance()->getFrontend()->getBackend()->clean('old');

Release Notes

  • March 2017: Added support for Redis Sentinel and loading from slaves. Thanks @Xon for the help!
  • Sometime in 2013: Ceased updating these release notes...
  • November 19, 2012: Added read_timeout option. (Feature only supported in standalone mode, will be supported by phpredis when pull request #260 is merged)
  • October 29, 2012: Added support for persistent connections. (Thanks samm-git!)
  • October 12, 2012: Improved memory usage and efficiency of garbage collection and updated recommendation.
  • September 17, 2012: Added connect_retries option (default: 1) to prevent errors from random connection failures.
  • July 10, 2012: Added password authentication support.
  • Mar 1, 2012: Using latest Credis_Client which adds auto-reconnect for standalone mode.
  • Feb 15, 2012: Changed from using separate keys for data, tags and mtime to a single hash per key.
  • Nov 10, 2011: Changed from using phpredis and redisent to Credis (which wraps phpredis). Implemented pipelining.
@copyright  Copyright (c) 2012 Colin Mollenhour (http://colin.mollenhour.com)
This project is licensed under the "New BSD" license (see source).
Comments
  • Cache keys go missing from tags over time

    Cache keys go missing from tags over time

    Hi, I have been using this backend in my production server quite successfully for the past 1 month. The only problem I have spotted so far is that after a few days without restarting redis (I do not use persistence, so restart=flush), some cache keys disappear from their tag's list, which leads to them not being deleted upon a cache clean by tags.

    So far, I have not managed to reproduce this behavior on purpose, it seems to be quite random. I am thinking of 2 scenarios:

    1. The gc script is not working properly (I am running it every 3 hours)
    2. While a tag clean is being executed, another request is inserting new keys to the same tag and something goes wrong (no locking?)

    I have not yet thoroughly reviewed the code, so I do not have a complete view of how (or if) locking is implemented for writes/flushes, will do so as soon as possible.

    In the meanwhile, has this behavior been spotted before?

    opened by nemphys 45
  • Periodic 100% CPU usage on front-end servers

    Periodic 100% CPU usage on front-end servers

    Hi,

    after deploying REDIS to the production servers, periodically at random times and unrelated to the load at that moment, the frontend servers end up using 100% CPU usage making the front-end unresponsive.

    The site is set-up to have 3 app servers specifically for the frontend, and 1 app servers specifically for the backend admin. Sine the backend server is unaffected, I am thinking it is the FPC is cache-trashing.

    Clearing or restarting REDIS has no effect. Restarting the zend services on the frontend servers seems to fix it. The unfortunate thing is this is not happening on the test environment (which is configured exactly the same).

    Any help please? I cannot figure out what the issue could be. For the next steps I was going to switch off phpredis, and enable automatic cleaning factor, to see if it keeps happening, but of these will slow down the system.

    Magento version is 1.9.0.0 EE Redis version is 2.6.12 phpredis is installed on the app servers, latest from repository (2.2.3?) lzf compression is installed We set a cron job on the redis server that clears the cache completely using "redis-cli flushall" at 6am

    Configuration on all 4 servers is the same <cache> <backend>Cm_Cache_Backend_Redis</backend> <backend_options> <server>xxx.xxx.xxx.xxx</server> <!-- or absolute path to unix socket --> <port>6379</port> <persistent>cache-db0</persistent> <!-- Specify a unique string like "cache-db0" to enable persistent connections. --> <database>0</database> <password></password> <force_standalone>0</force_standalone> <!-- 0 for phpredis, 1 for standalone PHP --> <connect_retries>1</connect_retries> <!-- Reduces errors due to random connection failures --> <read_timeout>10</read_timeout> <!-- Set read timeout duration --> <automatic_cleaning_factor>0</automatic_cleaning_factor> <!-- Disabled by default --> <compress_data>1</compress_data> <!-- 0-9 for compression level, recommended: 0 or 1 --> <compress_tags>1</compress_tags> <!-- 0-9 for compression level, recommended: 0 or 1 --> <compress_threshold>20480</compress_threshold> <!-- Strings below this size will not be compressed --> <compression_lib>lzf</compression_lib> <!-- Supports gzip, lzf and snappy --> </backend_options> </cache>

    Output of "info all" during a non-peak moment (now): redis 127.0.0.1:6379> info all

    Server

    redis_version:2.6.12 redis_git_sha1:00000000 redis_git_dirty:0 redis_mode:standalone os:Linux 2.6.18-348.4.1.el5 x86_64 arch_bits:64 multiplexing_api:epoll gcc_version:4.1.2 process_id:3566 run_id:f7ac169ac2700d731b359ef3cf86ac38e6602780 tcp_port:6379 uptime_in_seconds:147149 uptime_in_days:1 hz:10 lru_clock:707773

    Clients

    connected_clients:25 client_longest_output_list:2 client_biggest_input_buf:0 blocked_clients:0

    Memory

    used_memory:806210760 used_memory_human:768.86M used_memory_rss:865255424 used_memory_peak:847086696 used_memory_peak_human:807.84M used_memory_lua:31744 mem_fragmentation_ratio:1.07 mem_allocator:jemalloc-3.2.0

    Persistence

    loading:0 rdb_changes_since_last_save:10793859 rdb_bgsave_in_progress:0 rdb_last_save_time:1370079388 rdb_last_bgsave_status:ok rdb_last_bgsave_time_sec:-1 rdb_current_bgsave_time_sec:-1 aof_enabled:0 aof_rewrite_in_progress:0 aof_rewrite_scheduled:0 aof_last_rewrite_time_sec:-1 aof_current_rewrite_time_sec:-1 aof_last_bgrewrite_status:ok

    Stats

    total_connections_received:278236 total_commands_processed:100407515 instantaneous_ops_per_sec:463 rejected_connections:0 expired_keys:176335 evicted_keys:0 keyspace_hits:63930946 keyspace_misses:2027440 pubsub_channels:0 pubsub_patterns:0 latest_fork_usec:0

    Replication

    role:master connected_slaves:0

    CPU

    used_cpu_sys:1706.26 used_cpu_user:931.63 used_cpu_sys_children:0.00 used_cpu_user_children:0.00

    Commandstats

    cmdstat_del:calls=407549,usec=3057946,usec_per_call=7.50 cmdstat_sadd:calls=32728843,usec=63358464,usec_per_call=1.94 cmdstat_srem:calls=389842,usec=842764,usec_per_call=2.16 cmdstat_sunion:calls=360857,usec=2499681,usec_per_call=6.93 cmdstat_hget:calls=65101268,usec=325685595,usec_per_call=5.00 cmdstat_hmset:calls=496261,usec=4722766,usec_per_call=9.52 cmdstat_select:calls=426630,usec=1788001,usec_per_call=4.19 cmdstat_expire:calls=496261,usec=1375386,usec_per_call=2.77 cmdstat_flushall:calls=2,usec=4346262,usec_per_call=2173131.00 cmdstat_info:calls=2,usec=566,usec_per_call=283.00

    Keyspace

    db0:keys=19080,expires=14261

    thanks, Stefan

    opened by raptor75 24
  • read error on connection

    read error on connection

    I saw you popped into this issue with PHPRedis here: https://github.com/nicolasff/phpredis/issues/70

    It might completely reside with them but thought I would post here in case you had found a solution outside of PHPRedis to handle this with Cm_Cache_Backend_Redis.

    The only new thing I saw of note in that thread was within the past few weeks:

    "I encountered this same error message. Using the tip from @redzarf - I did some research and found that some of the strings we were trying to store are indeed more than 64KB (65,536 Characters).

    As a quick solution I started gzip'ing data before storing it in redis. Havn't seen the "read error on connection" error since."

    Here are some of my dump(s) when this hits:

    Error: read error on connection

    Trace: #0 /app/code/community/Cm/Cache/Backend/Redis.php(128): Credis_Client->__call('hGet', Array) #1 /app/code/community/Cm/Cache/Backend/Redis.php(128): Credis_Client->hGet('zc:k:139_TRANSL...', 'd') #2 /lib/Zend/Cache/Core.php(303): Cm_Cache_Backend_Redis->load('139_TRANSLATE_E...', false) #3 /app/code/core/Mage/Core/Model/Cache.php(351): Zend_Cache_Core->load('TRANSLATE_EN_US...') #4 /app/code/core/Mage/Core/Model/App.php(1126): Mage_Core_Model_Cache->load('translate_en_US...') #5 /app/code/core/Mage/Core/Model/Translate.php(521): Mage_Core_Model_App->loadCache('translate_en_US...') #6 /app/code/core/Mage/Core/Model/Translate.php(121): Mage_Core_Model_Translate->_loadCache() #7 /app/code/core/Mage/Core/Model/App/Area.php(146): Mage_Core_Model_Translate->init('frontend') #8 /app/code/core/Mage/Core/Model/App/Area.php(121): Mage_Core_Model_App_Area->_initTranslate() #9 /app/code/core/Mage/Core/Model/App/Area.php(93): Mage_Core_Model_App_Area->_loadPart('translate') #10 /app/code/core/Mage/Core/Model/App.php(768): Mage_Core_Model_App_Area->load() #11 /app/code/core/Mage/Core/Controller/Varien/Action.php(493): Mage_Core_Model_App->loadArea('frontend') #12 /app/code/core/Mage/Core/Controller/Front/Action.php(59): Mage_Core_Controller_Varien_Action->preDispatch() #13 /app/code/core/Mage/Core/Controller/Varien/Action.php(409): Mage_Core_Controller_Front_Action->preDispatch() #14 /app/code/core/Mage/Core/Controller/Varien/Router/Standard.php(250): Mage_Core_Controller_Varien_Action->dispatch('view') #15 /app/code/core/Mage/Core/Controller/Varien/Front.php(176): Mage_Core_Controller_Varien_Router_Standard->match(Object(Mage_Core_Controller_Request_Http)) #16 /app/code/core/Mage/Core/Model/App.php(349): Mage_Core_Controller_Varien_Front->dispatch() #17 /app/Mage.php(640): Mage_Core_Model_App->run(Array) #18 /index.php(83): Mage::run('', 'store') #19 {main}

    Error: read error on connection

    Trace: #0 /app/code/community/Cm/Cache/Backend/Redis.php(128): Credis_Client->__call('hGet', Array) #1 /app/code/community/Cm/Cache/Backend/Redis.php(128): Credis_Client->hGet('zc:k:139_DB_PDO...', 'd') #2 /lib/Zend/Cache/Core.php(303): Cm_Cache_Backend_Redis->load('139_DB_PDO_MYSQ...', false) #3 /lib/Varien/Db/Adapter/Pdo/Mysql.php(1442): Zend_Cache_Core->load('DB_PDO_MYSQL_DD...') #4 /lib/Varien/Db/Adapter/Pdo/Mysql.php(1564): Varien_Db_Adapter_Pdo_Mysql->loadDdlCache('eav_attribute', 1) #5 /app/code/core/Mage/Catalog/Model/Resource/Product/Attribute/Collection.php(55): Varien_Db_Adapter_Pdo_Mysql->describeTable('eav_attribute') #6 /app/code/core/Mage/Core/Model/Resource/Db/Collection/Abstract.php(135): Mage_Catalog_Model_Resource_Product_Attribute_Collection->_initSelect() #7 /app/code/core/Mage/Core/Model/Config.php(1350): Mage_Core_Model_Resource_Db_Collection_Abstract->__construct(Array) #8 /app/code/core/Mage/Core/Model/Config.php(1386): Mage_Core_Model_Config->getModelInstance('catalog_resourc...', Array) #9 /app/Mage.php(460): Mage_Core_Model_Config->getResourceModelInstance('catalog/product...', Array) #10 /app/code/core/Mage/Catalog/Model/Layer.php(226): Mage::getResourceModel('catalog/product...') #11 /app/code/core/Mage/Catalog/Block/Layer/View.php(163): Mage_Catalog_Model_Layer->getFilterableAttributes() #12 /app/code/local/Lp/Catalog/Block/Layer/View.php(121): Mage_Catalog_Block_Layer_View->_getFilterableAttributes() #13 /app/code/core/Mage/Core/Block/Abstract.php(238): Lp_Catalog_Block_Layer_View->_prepareLayout() #14 /app/code/core/Mage/Core/Model/Layout.php(430): Mage_Core_Block_Abstract->setLayout(Object(Mage_Core_Model_Layout)) #15 /app/code/core/Mage/Core/Model/Layout.php(446): Mage_Core_Model_Layout->createBlock('catalog/layer_v...', 'catalog.leftnav') #16 /app/code/core/Mage/Core/Model/Layout.php(238): Mage_Core_Model_Layout->addBlock('catalog/layer_v...', 'catalog.leftnav') #17 /app/code/core/Mage/Core/Model/Layout.php(204): Mage_Core_Model_Layout->_generateBlock(Object(Mage_Core_Model_Layout_Element), Object(Mage_Core_Model_Layout_Element)) #18 /app/code/core/Mage/Core/Model/Layout.php(209): Mage_Core_Model_Layout->generateBlocks(Object(Mage_Core_Model_Layout_Element)) #19 /app/code/core/Mage/Core/Controller/Varien/Action.php(345): Mage_Core_Model_Layout->generateBlocks() #20 /app/code/core/Mage/Catalog/controllers/CategoryController.php(150): Mage_Core_Controller_Varien_Action->generateLayoutBlocks() #21 /app/code/core/Mage/Core/Controller/Varien/Action.php(420): Mage_Catalog_CategoryController->viewAction() #22 /app/code/core/Mage/Core/Controller/Varien/Router/Standard.php(250): Mage_Core_Controller_Varien_Action->dispatch('view') #23 /app/code/core/Mage/Core/Controller/Varien/Front.php(176): Mage_Core_Controller_Varien_Router_Standard->match(Object(Mage_Core_Controller_Request_Http)) #24 /app/code/core/Mage/Core/Model/App.php(349): Mage_Core_Controller_Varien_Front->dispatch() #25 /app/Mage.php(640): Mage_Core_Model_App->run(Array) #26 /index.php(83): Mage::run('', 'store') #27 {main}

    opened by fr0x 22
  • composer vs. git submodules issue

    composer vs. git submodules issue

    hey,

    composer does not support submodules as your modman app therefore the Credis lib folder will stay empty.

    Any other solution except forking and copying the Credis class into the lib folder? Also adding the Credis module to a projects root composer.json is not an option...

    Thanks!

    opened by SchumacherFM 14
  • Redis not accepting connections periodically

    Redis not accepting connections periodically

    I've been using the Redis caching module since last August with no difficulties. We just did an update to EE 1.13, and switched over to using the one that came packaged with Magento this last Saturday night, and this problem has happened twice now bringing the site down, once at midnight Monday morning, and then again at 11:11 PM Monday night (I noticed it was the same class essentially, but changed the configuration to point to the Mage one in lib just in case there was an update after the first time this problem happened that might have been the cause).

    The site works fine until... well, I'm not sure what, and that is what I'm hoping to find out or get pointed at something to start figuring out what is wrong. Like a switch, all the page requests start returning with errors. A sample of them is here:

    a:4:{i:0;s:44:"Connection to Redis failed after 2 failures.";i:1;s:1904:"#0 /var/www/html/magento/lib/Credis/Client.php(378): Credis_Client->connect() #1 /var/www/html/magento/lib/Credis/Client.php(463): Credis_Client->connect() #2 /var/www/html/magento/lib/Mage/Cache/Backend/Redis.php(210): Credis_Client->_call('hGet', Array) #3 /var/www/html/magento/lib/Mage/Cache/Backend/Redis.php(210): Credis_Client->hGet('zc:k:449_FPC_DE...', 'd') #4 /var/www/html/magento/lib/Zend/Cache/Core.php(303): Mage_Cache_Backend_Redis->load('449_FPC_DESIGN...', false) #5 /var/www/html/magento/lib/Varien/Cache/Core.php(158): Zend_Cache_Core->load('FPC_DESIGN_EXCE...', false, false) #6 /var/www/html/magento/app/code/core/Mage/Core/Model/Cache.php(379): Varien_Cache_Core->load('FPC_DESIGN_EXCE...') #7 /var/www/html/magento/app/code/core/Enterprise/PageCache/Model/Processor.php(184): Mage_Core_Model_Cache->load('FPC_DESIGN_EXCE...') #8 /var/www/html/magento/app/code/core/Enterprise/PageCache/Model/Processor.php(145): Enterprise_PageCache_Model_Processor->_getDesignPackage() #9 /var/www/html/magento/app/code/core/Enterprise/PageCache/Model/Processor.php(107): Enterprise_PageCache_Model_Processor->_createRequestIds() #10 /var/www/html/magento/app/code/core/Mage/Core/Model/Cache.php(703): Enterprise_PageCache_Model_Processor->__construct() #11 /var/www/html/magento/app/code/core/Mage/Core/Model/Cache.php(685): Mage_Core_Model_Cache->_getProcessor('Enterprise_Page...') #12 /var/www/html/magento/app/code/core/Mage/Core/Model/App.php(340): Mage_Core_Model_Cache->processRequest() #13 /var/www/html/magento/app/Mage.php(683): Mage_Core_Model_App->run(Array) #14 /var/www/html/magento/index.php(87): Mage::run('default', 'store') #15 /var/www/html/magento/index_redir.php(25): require_once('/var/www/html/d...') #16 {main}";s:3:"url";s:1:"/";s:11:"script_name";s:1:"/";}

    The only action I can see in the admin log that happened just before it is a catalog pricing rules trying to be applied, and failing (it seems a bug that if the cron is running when someone tries to apply catalog price rules, it will fail, however, if I turn the off the cron from running in crontab, it always applies no problem). So, maybe something wrong if a reindex process fails (like a catalog pricing rules get reapplied and pricing gets reindexed at midnight automatically I think if I recall correctly, and this rule applying failing probably failed on the reindexing part) something messes up the full page cache that causes the module to hang? I don't know, just guessing at this point.. and the one thing I've done to basically jump start it was restart the redis services... I didn't check trying to go into the admin and flushing the cache.

    Anyway, I'm not passing through a firewall between the web servers and the redis server, and am hoping that there might be a thought on how to best go about debugging this or an idea of what might be going wrong that the redis backend suddenly becomes non-accessible. Hopefully someone has some insight and can help.

    opened by jonnythejap 14
  • PHP Fatal error: Uncaught exception 'CredisException' with message 'Lost connection to Redis server

    PHP Fatal error: Uncaught exception 'CredisException' with message 'Lost connection to Redis server

    Since a few days i get very often the following error

    apache2: PHP Fatal error: Uncaught exception 'CredisException' with message 'Lost connection to Redis server.' in /pathtomagento/lib/Credis/Client.php:693#012Stack trace:#012#0 /pathtomagento/lib/Credis/Client.php(538): Credis_Client->read_reply('select')#012#1 /pathtomagento/lib/Credis/Client.php(440): Credis_Client->__call('select', Array)#012#2 /pathtomagento/app/code/community/Cm/Cache/Backend/Redis.php(135): Credis_Client->select(0)#012#3 /pathtomagento/lib/Zend/Cache.php(153): Cm_Cache_Backend_Redis->__construct(Array)#012#4 /pathtomagento/lib/Zend/Cache.php(94): Zend_Cache::_makeBackend('Cm_Cache_Backen...', Array, true, true)#012#5 /pathtomagento/app/code/local/NBSSystem/Nitrogento/Model/Core/Cache.php(28): Zend_Cache::factory('Varien_Cache_Co...', 'Cm_Cache_Backen...', Array, Array, tr in /pathtomagento/lib/Credis/Client.php on line 693

    This error will make my server crash, because all clients from apache are being used.

    This is on Magento 1.8.1 CE. Apache 2.2.22, PHP 5.3.10-1ubuntu3.15, redis-cli 2.2.12 Does anyone know what is wrong?

    opened by RonnyWo 13
  • Prefix keys and tags

    Prefix keys and tags

    Seems like a great class, but sometimes the same server setup is used for multiple applications, which means that in it's current form the class is not usable. It would be great to have support for a key/tag prefix.

    I. e. so that these prefixes:

    const PREFIX_KEY      = 'zc:k:';
    const PREFIX_TAG_IDS  = 'zc:ti:';
    

    would actually be prefixed some an optional value fetched from configuration, e.g. named "prefix".

    opened by ArtemGoutsoul 13
  • An error occurred connecting to Redis.

    An error occurred connecting to Redis.

    Hey Colin !

    Firstly i wanna thank you for your awesome work on creating this new cache type.

    Sometimes have got this error poping, particulary when traffic is high on the website :

    An error occurred connecting to Redis.

    Trace: prod/.modman/Cm_Cache_Backend_Redis/lib/Credis/Client.php(278): Credis_Client->connect() prod/.modman/Cm_Cache_Backend_Redis/Cm/Cache/Backend/Redis.php(128): Credis_Client->_call('hGet', Array) prod/.modman/Cm_Cache_Backend_Redis/Cm/Cache/Backend/Redis.php(128): Credis_Client->hGet('zc:k:cc4_CORE_C...', 'd') prod/lib/Zend/Cache/Core.php(303): Cm_Cache_Backend_Redis->load('cc4_CORE_CACHE...', false) prod/app/code/local/Mage/Core/Model/Cache.php(330): Zend_Cache_Core->load('CORE_CACHE_OPTI...')

    for only 100 user connected on redis server.

    What's your opinion ?

    Do you think this is somethink related with server configuration ? Have you ever experimented something like that ?

    opened by Thorakh 13
  • Warning: md5()  by cluster

    Warning: md5() by cluster

    In the server logs I have the following errors: Cluster Elasticache by AWS.

    2018-11-27T08:48:45+00:00 ERR (3): Warning: md5() expects parameter 1 to be string, array given in .../lib/Credis/Cluster.php on line 260

    Have you ever encountered this problem.

    Possibly I have 1 primary node and 2 secondary node

    opened by gabi77 12
  • High concurrency race condition?

    High concurrency race condition?

    Hi, I've been having an insane issue with redis that I can't seem to figure out. When load testing my site with redis sometimes magento seems to get stuck in a loop when caching the global config. Doing a redis monitor I can see the following happen:

    del CONFIG_GLOBAL_STORES_DEFAULT hget CONFIG_GLOBAL_STORES_DEFAULT hmset CONFIG_GLOBAL_STORES_DEFAULT sadd CONFIG ONFIG_GLOBAL_STORES_DEFAULT hget CONFIG_GLOBAL_STORES_DEFAULT del CONFIG_GLOBAL_STORES_DEFAULT hget CONFIG_GLOBAL_STORES_DEFAULT hmset CONFIG_GLOBAL_STORES_DEFAULT

    It seems to get stuck in this loop until something "wins". Then about 20 seconds later it happens again. This only happens when the server is under a load and of course causes a huge performance hit. Any idea what could be happening?

    I have tried

    • updating redis and the extension (i am on latest now)
    • updating turpentine (varnish extension)
    • disabling compression
    • changing compression threshold
    • switching to memcached (I got an error that was something like "Illegal character")

    This is happening on php 5.5 with opcache on. one app server with varnish. Mage EE 1.14.1.0. no fpc

    Redis stats: evicted keys - 0 expired keys - 229 keyspace_hits:3521947 keyspace_misses:280737 used_memory:72253024 used_memory_human:68.91M used_memory_rss:160272384 used_memory_peak:77898896 used_memory_peak_human:74.29M used_memory_lua:36864

    ip 6379 1 <force_standalone>0</force_standalone> <connect_retries>4</connect_retries> <read_timeout>10</read_timeout> <automatic_cleaning_factor>0</automatic_cleaning_factor> <compress_data>1</compress_data> <compress_tags>1</compress_tags> <compress_threshold>20480</compress_threshold> <compression_lib>gzip</compression_lib> <use_lua>0</use_lua>

    Any help would be greatly appreciated. I've been toying with the idea of adding a slow backend but I haven't done that before and I'm grasping at air here. This was working a year ago but since then we have added varnish and upgraded magento. I have been using local file cache for now but I can have up to 50 app servers which isn't fun to manage with no centralized cache. If you need anymore info please let me know

    thanks!

    opened by crasx 10
  • An Error occurred connecting to Redis

    An Error occurred connecting to Redis

    Hello,

    We have had Redis running just fine for quite a few weeks and suddenly started getting this error:

    a:4:{i:0;s:38:"An error occurred connecting to Redis.";i:1;s:1627:"#0 /var/www/vhosts/vbc/httpdocs/lib/Credis/Client.php(278): Credis_Client->connect() #1 /var/www/vhosts/vbc/httpdocs/app/code/community/Cm/Cache/Backend/Redis.php(128): Credis_Client->__call('hGet', Array) #2 /var/www/vhosts/vbc/httpdocs/app/code/community/Cm/Cache/Backend/Redis.php(128): Credis_Client->hGet('zc:k:c2e_REQEST...', 'd') #3 /var/www/vhosts/vbc/httpdocs/lib/Zend/Cache/Core.php(303): Cm_Cache_Backend_Redis->load('c2e_REQEST_824F...', false) #4 /var/www/vhosts/vbc/httpdocs/app/code/core/Mage/Core/Model/Cache.php(329): Zend_Cache_Core->load('REQEST_824F9681...') #5 /var/www/vhosts/vbc/httpdocs/app/code/core/Enterprise/PageCache/Model/Processor.php(519): Mage_Core_Model_Cache->load('REQEST_824f9681...') #6 /var/www/vhosts/vbc/httpdocs/app/code/core/Enterprise/PageCache/Model/Processor.php(460): Enterprise_PageCache_Model_Processor->_loadMetadata() #7 /var/www/vhosts/vbc/httpdocs/app/code/core/Enterprise/PageCache/Model/Processor.php(169): Enterprise_PageCache_Model_Processor->getMetadata('cache_subproces...') #8 /var/www/vhosts/vbc/httpdocs/app/code/core/Mage/Core/Model/Cache.php(624): Enterprise_PageCache_Model_Processor->extractContent(false) #9 /var/www/vhosts/vbc/httpdocs/app/code/core/Mage/Core/Model/App.php(292): Mage_Core_Model_Cache->processRequest() #10 /var/www/vhosts/vbc/httpdocs/app/Mage.php(596): Mage_Core_Model_App->run(Array) #11 /var/www/vhosts/vbc/httpdocs/index.php(80): Mage::run('base', 'website') #12 {main}";s:3:"url";s:1:"/";s:11:"script_name";s:10:"/index.php";}

    Funny thing is, even though I have removed all mention of Redis in the app/etc/local.xml and enterprise.xml files, this error occurs unless I completely remove the /app/code/community/Cm directory.

    Any ideas?

    opened by scoreboard 10
  • Error cleaning cache by mode matchingAnyTag

    Error cleaning cache by mode matchingAnyTag

    Since we updated to the newest version of this module, we get the following error every time when flushing the cache:

    Error cleaning cache by mode matchingAnyTag: A pipeline is already in use and only one pipeline is supported

    Any ideas what might go wrong here?

    opened by norgeindian 11
  • Remove set instead of removing set members if only one tag

    Remove set instead of removing set members if only one tag

    https://github.com/colinmollenhour/Cm_Cache_Backend_Redis/blob/1132d905f08e33f24d1d80b775d2c7720b00c239/Cm/Cache/Backend/Redis.php#L748

    If we only have one cache tag (I think that's the usual case, at least for Magento), we can just remove this instead of removing the set members, right?

    opened by joshua-bn 1
  • Unable to use redis cluster + sentinel with Magento 2.3.5

    Unable to use redis cluster + sentinel with Magento 2.3.5

    Hi,

    We are trying to configure Magento 2.3.5 to use Redis cluster + sentinel, but we are getting an error when running bin/magento c:c (for example) :

    ERR unknown command select, with args beginning with: 2

    Here you have the configuration in our env.php file :

        'session' => [
        'save' => 'redis',
        'redis' => [
            'host' => 'redis-sentinel',
            'port' => '16379',
            'password' => '',
            'timeout' => '2.5',
            'persistent_identifier' => '',
            'database' => '0',
            'compression_threshold' => '2048',
            'compression_library' => 'gzip',
            'log_level' => '3',
            'max_concurrency' => '6',
            'break_after_frontend' => '5',
            'break_after_adminhtml' => '30',
            'first_lifetime' => '600',
            'bot_first_lifetime' => '60',
            'bot_lifetime' => '7200',
            'disable_locking' => '0',
            'min_lifetime' => '60',
            'max_lifetime' => '2592000',
            'sentinel_master' => 'master-node',
            'sentinel' => 'redis-sentinel:16379',
            'sentinel_connect_retries' => '5',
            'sentinel_verify_master' => '0',
            'load_from_slave' => '2',
            'retry_reads_on_master' => '1'
        ]
    ],
    'cache' => [
        'frontend' => [
            'default' => [
                'id_prefix' => '40d_',
                'backend' => 'Cm_Cache_Backend_Redis',
                'backend_options' => [
                    'server' => 'redis-sentinel',
                    'database' => '1',
                    'port' => '16379',
                    'password' => '',
                    'load_from_slave' => '2',
                    'retry_reads_on_master' => '1'
                ]
            ],
            'page_cache' => [
                'id_prefix' => '40d_',
                'backend' => 'Cm_Cache_Backend_Redis',
                'backend_options' => [
                    'server' => 'redis-sentinel',
                    'database' => '2',
                    'port' => '16379',
                    'password' => '',
                    'load_from_slave' => '2',
                    'retry_reads_on_master' => '1'
                ]
            ]
        ]
    ]
    

    Any idea what's wrong ?

    Best regards, Pierre

    opened by henry1303 3
  • replace

    replace "DEL" Commands with "UNLINK".

    Implements #158

    This PR replaces DEL Command with UNLINK command like I suggested in #158

    Details about UNLINK can be found here https://redis.io/commands/unlink .

    As noticed here https://github.com/redis/redis/issues/1748#issuecomment-43233084 this will not change the behavior.

    As there is no check of Redis version included, it will break Redis Versions < 4.0 through.

    As Redis 4.0 was released on 2017-07-14 and Redis 3 went EOL with the Redis 5 on 2018-10-17, I don't expect this being an issue.

    opened by jonashrem 1
  • Database connection settings are cached and shared across Redis instances and Magento cluster backend nodes

    Database connection settings are cached and shared across Redis instances and Magento cluster backend nodes

    When running multiple synchronized Redis instances in master+slave or cluster configuration the Magento configuration cache is shared among different Magento backend nodes. When etc/local.xml file differs between nodes shared cache causes nodes miss-configuration issues. I.e. when Node1 is configured to use Mysql1 backend and Node2 to use Mysql2 backend due to shared config cache all nodes will share the same Mysql backend settings (one which was cached first).

    I applied a dirty fix to Core/Model/Config.php to address this issue. See patch attached.

    --- D:/Storage/www/avtoto/html/svn/branches/2.0_staging/app/code/core/Mage/Core/Model/Config.php	Tue Jan 30 09:57:29 2018
    +++ D:/Storage/www/avtoto/html/svn/branches/2.0_staging/app/code/local/Mage/Core/Model/Config.php	Tue Aug 18 11:45:43 2020
    @@ -462,0 +463 @@ class Mage_Core_Model_Config extends Mage_Core_Mod
    +            unset($xml->global->resources->default_setup->connection);
    @@ -1636,0 +1638,23 @@ class Mage_Core_Model_Config extends Mage_Core_Mod
    +
    +    /**
    +     * Enter description here...
    +     *
    +     * @return boolean
    +     */
    +    public function loadCache()
    +    {
    +        if (!$this->validateCacheChecksum()) {
    +            return false;
    +        }
    +
    +        $xmlString = $this->_loadCache($this->getCacheId());
    +        $xml = simplexml_load_string($xmlString, $this->_elementClass);
    +        if ($xml) {
    +            //$this->_xml = $xml;
    +            $this->getNode()->extend($xml, true);
    +            $this->setCacheSaved(true);
    +            return true;
    +        }
    +
    +        return false;
    +    }
    

    Please share your experience on Magento cluster setup, how do you deal with shared configuration among nodes?

    opened by Guard1an 1
  • switch from del() to unklink() for redis >= 4.0

    switch from del() to unklink() for redis >= 4.0

    With redis 4.0 there is a new unlink command intruded ( https://redis.io/commands/unlink ) with is a smarter version of del() as it deletes keys in O(1) and frees the memory in background.

    See also http://antirez.com/news/93 and https://github.com/redis/redis/issues/1748

    This won't change the behavior but only the memory usage as clarified here: https://github.com/redis/redis/issues/1748#issuecomment-43233084 which shouldn't be an issue with most Magento instances

    With this, I recomand replacing DEL operations with UNLINK operations.

    opened by jonashrem 10
Releases(1.15.0)
Owner
Colin Mollenhour
Colin Mollenhour
Automatically load the next page of products in Magento. Easy to install and configure, this module works 100% out of the box with vanilla Magento 1.9.x and earlier.

Automatically load the next page of products in Magento. Easy to install and configure, this module works 100% out of the box with vanilla Magento 1.9.x and earlier.

Strategery 123 Nov 20, 2021
This Magento extension provides a Real Full Page Caching for Magento powered by Varnish with support of Session-Based information caching (Cart, Customer Accounts, ...) via ESI includes

This Magento extension provides a Real Full Page Caching (FPC) for Magento powered by Varnish with support of Session-Based information caching (Cart, Customer Accounts, ...) via ESI includes

Hugues Alary 95 Feb 11, 2022
This Statamic addon allows you to modify the tags rendered by the Bard fieldtype, giving you full control over the final HTML.

Bard Mutator This Statamic addon allows you to modify the tags rendered by the Bard fieldtype, giving you full control over the final HTML. You can ad

Jack Sleight 10 Sep 26, 2022
A great Start for your next Magento Theme's local.xml file

Magento-local.xml-Template A Great Start for your next Magento Theme's local.xml file - <?xml version="1.0"?> <layout> <!-- Add/Remove Items From H

Bryan Littlefield 36 Apr 19, 2021
PHP Japanese string helper functions for converting Japanese strings from full-width to half-width and reverse. Laravel Rule for validation Japanese string only full-width or only half-width.

Japanese String Helpers PHP Japanese string helper functions for converting Japanese strings from full-width to half-width and reverse. Laravel Rule f

Deha 54 Mar 22, 2022
Redis-based session handler for Magento with optimistic locking

Cm_RedisSession A Redis-based session handler for Magento with optimistic locking. Features: Falls back to mysql handler if it can't connect to Redis.

Colin Mollenhour 216 Jan 5, 2023
A Redis-based session handler for Magento with optimistic locking.

Cm_RedisSession A Redis-based session handler for Magento with optimistic locking. Features: Falls back to mysql handler if it can't connect to Redis.

Colin Mollenhour 215 Jan 28, 2022
GDPR compliant TYPO3 content elements which work great with PIWIK Consent Manager.

PIWIK Consent Manager TYPO3 extension PIWIK Consent Manager integration in order to make TYPO3 content elements GDPR compliant. You can click on the i

null 6 Aug 8, 2022
Get the system resources in PHP, as memory, number of CPU'S, Temperature of CPU or GPU, Operating System, Hard Disk usage, .... Works in Windows & Linux

system-resources. A class to get the hardware resources We can get CPU load, CPU/GPU temperature, free/used memory & Hard disk. Written in PHP It is a

Rafael Martin Soto 10 Oct 15, 2022
This is a plugin written in PHP programming language and running on the PocketMine platform that works stably on the API 3.25.0 platform

This is a plugin written in PHP programming language and running on the PocketMine platform that works stably on the API 3.25.0 platform. It allows you to hear the sound

Thành Nhân 10 Sep 27, 2022
A payment gateway plugin for WooCommerce to see if your checkout works.

=== Order Test For All for WooCommerce === Contributors: ikamal Donate link: https://kamal.pw/ Tags: wc order test, wc order, woocommerce, woocommerce

Kamal 3 Dec 7, 2021
This package is aimed to be a simplistic PHP workflow package that works in a similar fashion to GitHub Actions.

Workflow This package is aimed to be a simplistic PHP workflow package that works in a similar fashion to GitHub Actions. Installation To install this

Steve McDougall 4 Sep 26, 2022
🔒 Built a recaptcha for Nifty that works with Wordpress's Gravity Forms

Recaptcha Fully Functioning spam filter that has 10 levels of security, but is slim and rpackaged to integrate with any Gravity Forms form WORKING EXA

Lisa Broadhead 1 May 17, 2022
Naive Bayes works by looking at a training set and making a guess based on that set.

Naive Bayes Naive Bayes works by looking at a training set and making a guess based on that set. It uses simple statistics and a bit of math to calcul

Assisted Mindfulness 29 Nov 27, 2022
nUberSoft is a small in-the-works framework Library for PHP

nUberSoft is a small in-the-works framework Library for PHP. It is a mix of old and new due to it's long development timeframe. Documentation is not as robust as it should be. The majority of this framework will work for non-Linux-based systems, but it is not tested and some security (.htaccess) are not read by Win servers.

Rasclatt 0 Jan 10, 2022
Silverstripe-fulltextsearch - Adds external full text search engine support to SilverStripe

FullTextSearch module Adds support for fulltext search engines like Sphinx and Solr to SilverStripe CMS. Compatible with PHP 7.2 Important notes when

Silverstripe CMS 42 Dec 30, 2022
A tool that allows to quickly export data from Magento 1 and Magento 2 store and import it back into Magento 2

Simple Import / Export tool A tool that allows to quickly export data from Magento 1 and Magento 2 store and import it back into Magento 2. Table data

EcomDev B.V. 51 Dec 5, 2022