1C-Bitrix Caching Module Development
Bitrix has its own cache via \Bitrix\Main\Data\Cache — file-based, with tag support through \Bitrix\Main\Data\TaggedCache. On small sites it works fine. Problems begin under high load: thousands of files in /bitrix/cache/, read/write operations competing on the filesystem, tag-based invalidation as a blocking operation. The caching module builds a unified layer on top of the standard mechanism with a Redis backend, statistics, cache warming, and granular invalidation.
Architecture: CacheManager
The central class CacheManager implements the strategy pattern. The backend is selected in the module settings:
$cache = \Vendor\Cache\CacheManager::getInstance();
// Standard get-or-set
$result = $cache->remember('catalog_section_12', 3600, function() {
return CIBlockSection::GetList(/* ... */)->Fetch();
}, ['iblock_12', 'catalog']);
// → Data from cache, or the callable result on a miss
// Explicit tag-based invalidation
$cache->invalidateTag('iblock_12');
// → Flushes all keys tagged with iblock_12
Redis Backend
Bitrix's file cache does not scale across multiple servers. Redis solves this problem:
class RedisCacheBackend implements CacheBackendInterface
{
private \Redis $redis;
public function get(string $key): mixed
{
$data = $this->redis->get($key);
return $data !== false ? unserialize($data) : null;
}
public function set(string $key, mixed $value, int $ttl, array $tags = []): void
{
$serialized = serialize($value);
$this->redis->setEx($key, $ttl, $serialized);
// Tags are stored as Redis Sets
foreach ($tags as $tag) {
$this->redis->sAdd("tag:{$tag}", $key);
$this->redis->expire("tag:{$tag}", $ttl + 3600);
}
}
public function invalidateTag(string $tag): void
{
$keys = $this->redis->sMembers("tag:{$tag}");
if ($keys) {
$this->redis->del(...$keys);
}
$this->redis->del("tag:{$tag}");
}
}
Tags in Redis are implemented via Sets. Tag-based invalidation is an atomic operation with no filesystem locks.
Caching Strategies
The module supports several strategies for different data types:
- TTL cache — classic cache with a time-to-live. For infrequently changing data: site settings, region list, delivery parameters
-
Event-invalidation — cache is flushed on a Bitrix event. Hooked onto
OnAfterIBlockElementAdd,OnAfterIBlockElementUpdate, etc. - Stale-while-revalidate — stale cache is served immediately while regeneration is triggered in the background via an agent. Eliminates the "thundering herd" on cache misses
- Request-scoped — cache for the duration of a single HTTP request (in-memory array). Prevents repeated database queries within the same request
Cache Warming
When the cache is flushed, the first request is always slow — it hits the database. Under high load this causes a spike. The warming agent solves the problem:
// Registered warmup tasks
$cache->registerWarmup('catalog_menu', function() {
return CIBlockElement::GetList(/* full catalogue */);
}, ['iblock_main_catalog'], 7200);
// Agent runs hourly and refreshes cache before TTL expires
\Vendor\Cache\WarmupAgent::run();
Monitoring and Statistics
The b_vendor_cache_stat table stores aggregated statistics per key:
-
key_prefix,hits,misses,avg_ttl,last_hit_at
In the administrative interface:
- Hit rate by key category
- Top "cold" keys (many misses)
- Cache size per backend
- Manual invalidation by tag or key
- Log of recent invalidation operations
Integration with Bitrix Components
Standard components use $APPLICATION->IncludeComponent() with the CACHE_TYPE parameter. The module intercepts this mechanism and redirects to Redis:
// In init.php after loading the module
\Vendor\Cache\BitrixCacheBridge::install();
// → Overrides \Bitrix\Main\Data\Cache::createInstance()
// returning the Redis backend instead of the file backend
The bridge makes the replacement transparent — components continue to work without any code changes.
Development Timeline
| Stage | Duration |
|---|---|
| CacheManager architecture, backend interface | 1 day |
| Redis backend with tag support | 2 days |
| Strategies: stale-while-revalidate, request-scoped | 2 days |
| Cache warming agent | 1 day |
| Bridge for standard Bitrix components | 1 day |
| Statistics, administrative interface | 2 days |
| Load testing | 1 day |
Total: 10 working days. For projects with a PHP server cluster — additional Redis Cluster or Sentinel configuration: +1–2 days.







