J'ai testé pour vous : le composant Cache de Symfony couplé à Redis

Principe du cache

exemples

  • RAM
  • Cache CPU
  • Redis devant BDD
  • DNS
  • CDN

questions associées

  • Espace de stockage limité ?
  • Invalidation ?

cas simple

  • Récupérer une donnée non cachée
  • Invalider la donnée quand une màj est faite dans la source d'origine

Besoin classique

  • Nombreux accès à une BDD, requêtes complexes
  • Redis : clé-valeur
  • Pratique pour stocker des choses simplement
key_1: 'value_1'
key_2: 2
key_3: '{firstName: Ando, lastName: Larz}'

symfony cache

  • Symfony 3.3
  • PSR 16 Simple cache
  • PSR 6 Cache
  • Nombreux adapters (Filesystem, Redis, Memcached, PDO, chain, etc)

notre cas d'usage

  • Site de voyages, produits complexes
  • Données maîtrisées dans un système externe
  • Plusieurs pools, dont un pour les produits

notre cas d'usage

# config/packages/cache.yaml

framework:
    cache:
        default_redis_provider: 'redis://%env(REDIS_CACHE_HOST)%:%env(REDIS_CACHE_PORT)%'

        pools:
            # Individual pools for different product cache usages
            product.cache_pool:
                adapter: 'cache.adapter.redis_tag_aware'
                tags: true
                default_lifetime: 28800
            # Other pools ...

notre cas d'usage

$this->productCachePool->get(
    $productCacheKey,
    function (ItemInterface $item) use ($productId): CacheableProductDto {
        $product = $this->productRepository->find($productId);

        if (null === $product) {
            throw new NotFoundHttpException();
        }

        $item->tag('product_tag');
        $item->expiresAfter('3600');

        return $cacheableProductDto;
    }
);

cas avancé

Administration du cache par les admins

  • Afficher l'ensemble des clés
  • Afficher un item
  • Recherche par filtre
  • Suppression d'une clé
  • Suppression par filtre
  • Suppression par tag
  • Suppression totale

pools Symfony cache

  • 'cache.taggable'
  • Pas de `getAll()`
  • Clés au format `xxx:my_key_1234`
  • Tags spécifiques préfixés `\x01` (binaire)

Impliquent des manipulations spécifiques

Cas faciles

  • Afficher un item
  • Supprimer par tag
  • Suppression totale

affichage de l'ensemble

  • Rappel : plusieurs pools
  • AutowireIterator sur `cache.taggable`

affichage de l'ensemble

trait CacheKeysTrait
{

    private readonly \Redis $redisCache;

    /**
     * @return array<int, string>
     */
    private function scanKeys(string $searchPattern): array
    {
        $cursor = null;
        $keys = [];
        do {
            $retrievedKeys = $this->redisCache->scan($cursor, $searchPattern);
            if (false !== $retrievedKeys) {
                foreach ($retrievedKeys as $key) {
                    $keys[] = $key;
                }
            }
        } while (0 !== $cursor);

        return $keys;
    }
}

affichage de l'ensemble

  • 'Sanitize' les clés

jamld6hgt:product_desert_marocain

affichage de l'ensemble

Filtrer les clés qui sont des tags

return b($poolCompatibleKey)->startsWith("\x01");

affichage de l'ensemble

foreach ($this->cachePools as $cachePool) {
    if (true === $cachePool->hasItem($poolCompatibleKey)) {
        return $cachePool->getItem($poolCompatibleKey);
    }
}

Recherche par filtre

Même fonctionnement

  • Scan Redis (avec pattern de filtrage)
  • Sanitize
  • Filtrage tags
  • foreach
  • Pagination
  • Return

performances

TODO

suppression par filtre

  • Scan Redis
  • Sanitize des clés
  • Filtrage des tags

suppression par filtre

foreach ($this->cachePools as $cachePool) {
    if (true === $cachePool->hasItem($poolCompatibleKey)) {
        $deletionSuccess = $cachePool->deleteItem($poolCompatibleKey);
        if (false === $deletionSuccess) {
            $failedDeletions[] = $key;
        }
    	break;
    }
}

suppression par clé

if (false === $this->redisCache->get($cacheKey)) {
    $this->logger->warning('Tried to delete {cacheKey} cache key, but it was not found.', [
        'cacheKey' => $cacheKey,
    ]);

    return;
}

conclusion

Idéal pour stocker et récupérer des items en cache

 

Pour les besoins plus avancés :

  • Compléter en accédant directement au cache
  • Comprendre la gestion des pools et tags

merci !

QR Code pour les retours

Minimal

By Andoni Larzabal