Comprendre le fonctionnement bas niveau du cache eZ Publish : Le cache de vue (Article 3)
- Publié le 18 mai 2012
- 0 commentaire(s)
- Catégorie : Technologies Web
Après ce « préambule » sur les compilations de templates, ce chapitre détaille le fonctionnement du cache de vue selon un axe pédagogique certainement perfectible (il est difficile de sélectionner un axe plutôt qu'un autre dans un contexte multidimensionnel).
Le cache de vue est mentionné sous diverses formes dans les fichiers de configuration, documentation ou tutoriaux : le cache de contenu, le cache de vue, le cache de vue de contenu, le cache d'affichage de contenu... ces termes désignent tous la même chose. Cet article utilise l'expression "cache de vue" afin d'être cohérent avec le vocabulaire du fichier de configuration "viewcache.ini"
A quoi sert le cache de vue ?
Pour vulgariser son usage, ou peut considérer que le cache de vue permet d'extraire « une seule fois » le contenu stocké dans eZ Publish, pour ensuite le mettre en cache (portion xHTML), en attendant une future expiration provoquant sa reconstruction (pour X raisons, la plus courante étant la mise à jour du contenu).
- le cache de vue s'applique pour les URL couplée à un nœud par le module « content » : « content/view/... », qui retourne le contenu « cachable » au travers de $module_result.content
- le cache de vue ne s'applique pas pour tout le reste, à savoir :
- Le code autour du $module_result.content dans les divers pagelayout.tpl
- dans tous les autres modules (natifs ou personnalisés)
Les différents modes d'expiration du cache de vue
Pour contrôler les performances d'eZ Publish, il est nécessaire de bien comprendre quels sont les évènements / actions / déclencheurs qui peuvent provoquer l'expiration du cache de vue pour une URL donnée (la home par exemple), un lot d’URL, ou encore toutes les URL (la pire des situations, qui ne devrait jamais être possible sur un site à fort trafic).
Une fois ces déclencheurs identifiés, le travail d'optimisation consiste à supprimer tous les déclencheurs critiques, au cas par cas, surtout ceux capable de provoquer une expiration massive du cache de vue (voir l'impact sur les performances). Ce chapitre décrit les différents mécanismes d'expirations du cache de vue, alors que le prochain chapitre décrit les différents évènements qui peuvent provoquer l'un ou l'autre de ces mécanismes d'expiration.
Le cache de vue peut expirer selon 2 mécanismes bien distincts, selon qu'il s'agisse d'une expiration complète (tous les caches de vue) ou partielle (1 lot de noeuds impactés) :
- Expiration par lot de cache de vue (voir le chapitre suivant)
- Expiration complète du cache de vue (voir le chapitre suivant)
Expiration par lot de cache de vue
Lorsqu'un cache de vue expire pour X raisons détaillés plus loin (partons du scénario courant de la mise à jour d'un article), il implique généralement une liste de noeud ayant un cache à expirer : le noeud de l'article lui même, et par exemple les noeuds des articles en relations, les frères, les parents, ou les noeuds exploitant les même mots clés (datatype ezkeyword), etc. (selon les directives du viewcache.ini). Il faut donc faire expirer un ensemble de fichiers de cache corrélés à cet ensemble de noeuds.
Une expiration d'un lot de cache consiste à "altérer" les fichiers de cache correspondant aux noeuds impliqués stockés dans{VarDir}/cache/content/
Le mode d'altération des fichiers est différent en fonction du filehandler (file.ini) exploité :
- filehandler par défaut "ezfsfilehandler" : une suppression des fichiers impactés (unlink)
- filehandler expérimental (stalecache) "ezfs2filehandler" : une modification de la date des fichiers impactés (touch), fixé au 25/05/1977 (jour de la sortie du 1er Star Wars)
- filehandler de cluster DB "ezdbfilehandler" : une modification des enregistrements dans la table SQL "ezdbfile" (UPDATE expired=1)
- filehandler de cluster DFS "ezdfsfilehandler" : une modification des enregistrements dans la table SQL "ezdfsfile" (UPDATE expired=1)
Une fois altérés, les caches sont reconstruits par comparaison entre 2 états :
- filehandler par défaut "ezfsfilehandler" : si le fichier n'existe pas OU si la date du fichier est antérieure au timestamp du fichier expiry.php, recréer un cache
- filehandler expérimental (stalecache) "ezfs2filehandler" : si la date du fichier est antérieure au timestamp du fichier expiry.php, le recréer
- filehandler de cluster DB "ezdbfilehandler" : si le champs "expired=1" dans la table "ezdbfile" (pour rester simple) OU si la date du champs "mtime" est antérieure au timestamp du fichier expiry.php, recréer un cache
- filehandler de cluster DFS "ezdfsfilehandler" : si le champs "expired=1" dans la table "ezdfsfile" (pour rester simple) OU si la date du champs "mtime" est antérieure au timestamp du fichier expiry.php, recréer un cache
La reconstruction de ce cache intervient (si la comparaison est positive) :
- Soit : Par défaut, à la volée, lors de l'appel de l’URL par l'internaute
- Soit lors de la publication de l'objet (si le paramètre PreviewCache du site.ini est activé). Dans ce cas, l’attente du contributeur lors de la publication en back office est plus ou moins supportable, puisque dépendante de la “boucle” sur l’ensemble des caches de vue à expirer
Expiration complète du cache de vue
Pour des raisons de stabilité du système, lorsqu'un évènement exige l'expiration "complète" du cache de vue, eZ Publish ne peut bien évidement pas boucler sur l'ensemble des fichiers pour les faire expirer. Dans ce cas, la valeur 'content-view-cache' du fichier {VarDir}/cache/expiry.php est modifiée afin de rendre opérant le mécanisme de comparaison expliqué ci-dessus.
Cet évènement n'est pas anodin, notamment sur les sites à fort trafic qui vont subir une charge importante lors de la reconstruction massive et rapide de l'ensemble des caches de vue. Il faut ainsi considérer que cet évènement ne doit jamais se produire sur un site à fort trafic et qu'il est important d'identifier tous les déclencheurs possibles afin de les neutraliser (voir le chapitre concerné).
Cependant il est parfois difficile de contourner cet évènement (par exemple sur la création d'une classe de contenu), il faut dans ce cas disposer d'une architecture & d'un configuration eZ Publish suffisamment dimensionnée (ou neutraliser le expiry.php par un backup...), par exemple :
- Utilisation du stalecache (ezfs2filehandler, ezdfsfilehandler, ezdfsfilehandler seulement) permet de limiter les impacts sur les reconstructions concurrente des caches (homepage par exemple). Pour en savoir plus sur stalecache :http://share.ez.no/learn/ez-publish/ez-publish-knowledge-series-stale-cache-or-how-caches-in-ez-publish-4.1-are-handled-in-a-smarter-way
- Utilisation d'un cache frontal (varnish)
- Infrastructure d'hébergement flexible (virtualisation, haute disponibilité), permettant d'assumer un pic de charge
- Dans tous les cas une optimisation du code des templates, afin de limiter les pages générant trop de requêtes (utilisation eZ Find pour les listes à filtres, persistent variables, loadDataMap = false, etc.). Ces mécanismes d'optimisations du code pourraient faire l'objet d'un autre tutoriel...
Les déclencheurs d'expiration du cache de vue & les modes d'expirations associés (lot ou complet)
Le chapitre précédent détaille les différentes modes d'expiration du cache de vue (par lot ou complet), ce chapitre décrit quand en lui les différentes évènements déclencheur qui peuvent provoquer cette expiration (par lot ou complète), que soit volontaire ou malgré vous.
Ces 2 notions de « volontaire » ou « malgré vous » sont déterminantes, puisque :
- L'expiration « volontaire » des caches de vue peut être utilisée à mauvais escient, par exemple pour tenter de résoudre un problème non lié au cache de vue ou encore en sous estimant l'impact d'un vidage massif du cache de vue, qui n'implique en fait qu'un seul lot de cache (on expire souvent tout le cache par facilités, ou parce qu'on ne connaît pas d'autres façon de procéder, sans considérer l'impact de cet action)
- L'expiration « malgré vous » des caches de vue signifie que le cache a expiré suite à une action / évènement qui peut paraître anodine et non impactant pour les caches : vous ne saviez tout simplement pas que cette action provoquait un expiration complète du cache de vue. Ainsi l'ajout d'une classe de contenu provoque l'expiration complète du cache de vue, sans lien direct déductible, ce qui peut provoquer une charge serveur insupportable en fonction du contexte (fort trafic, pas de cache Varnish...)
Expiration complète du cache de vue par script
Cette action est forcement « volontaire » :
php bin/php/ezcache.php --clear-id=content
Résultat : Cache d'affichage de contenu
php bin/php/ezcache.php --clear-tag=content
Résultat : Cache d'affichage de contenu, Cache des identifiants de classes, Cache des clés de classement, Cache des alias d'URL, Cache des template block, Cache RSS, Menu de l'arborescence de contenu., Cache des limitations d'états.
L'exécution de ces scripts ne cible pas un nœud ou une liste de nœud en particulier. L'expiration du cache de vue est donc globale : mise à jour du fichier {VarDir}/cache/expiry.php, et le changement de la valeur 'content-view-cache' => timestamp à jour
Expiration partielle du cache de vue par script
Cette action est forcement « volontaire » :
php bin/php/ezcontentcache.php –clear-node=2 php bin/php/ezcontentcache.php –clear-node=2,46,63 php bin/php/ezcontentcache.php –clear-node=/company/about php bin/php/ezcontentcache.php –clear-subtree=/company/about php bin/php/ezcontentcache.php –clear-subtree=/company/about,/news
Documentation du script ezcontentcache.php :
http://doc.ez.no/eZ-Publish/Technical-manual/4.x/Features/View-caching/Clearing-the-view-cache
“Attention : la suppression partielle du cache de contenu peut automatiquement se transformer en suppression complète du cache de vue si le nombre de nœuds impliqués ( par n’importe que noeud de la liste ou du sous arbre ) est supérieur au CacheThreshold (250 par défaut), voir le chapitre sur le CacheThreshold
Attention : Actuellement une expiration du cache de vue à partir d’une liste de noeuds ou d’un sous arbre reproduit l’ensemble du processus ( smartviewcache, CacheThreshold, expiration des template-block liés à un subtree expiry relatif, etc. ) pour chacun des noeud concernés (liste de noeuds, ou noeuds du sous arbre ). Ainsi, et pour simple exemple parmi d’autres, une règle de smartviewcache sur les frères ( siblings ) pourrait entraîner une expiration du cache de vue “au carré” ( les noeuds expirent autant de fois que le nombre de noeuds frères ), et rendre instable le système.
”
Expiration partielle du cache de vue par le viewcache.ini
Le mécanisme du viewcache.ini est déjà largement détaillé dans d'autres tutoriaux, cet article souhaite s'attarder en particulier sur les configuration critiques ou les recommandations concernant les sites à fort trafic.
Il est en effet fréquent que les règles du viewcache.ini provoquent régulièrement l'expiration complète des caches de vues, malgré vous, sans réelle pertinence ou besoin fonctionnel. En effet, la suppression partielle du cache de contenu peut automatiquement se transformer en suppression complète du cache de vue si le nombre de nœuds impliqués est supérieur au CacheThreshold (250 par défaut), voir le chapitre sur le CacheThreshold.
Il est donc important de maîtriser le nombre de nœuds impactés par une mise à jour de contenu, et pour cela de travailler en mode « Smart view cache », en prenant soin de :
- Ne pas utiliser de directive « all »
- Ne pas utiliser de directive « siblings » si le contenu est massivement stocker sous le même emplacement (frères)
- Configurer le KeywordNodesCacheClearLimit à 0 si vous utilisez massivement les mots clés
Documentation du fonctionnement du Smart view cache :
http://doc.ez.no/eZ-Publish/Technical-manual/4.x/Features/View-caching/Smart-view-cache-cleaning
Documentation du KeywordNodesCacheClearLimit dans le fichier viewcache.ini
# The maximum number of linked keyword nodes to go trough
# when looking for objects that needs to have its cache cleared.
# Set to integer to activate, 0 to disable keyword clearing globally
# or disabled to not have any limit at all (default value)
KeywordNodesCacheClearLimit=0
Documentation du fonctionnement du Smart view cache :
http://doc.ez.no/eZ-Publish/Technical-manual/4.x/Features/View-caching/Smart-view-cache-cleaning
Expiration volontaire du cache de vue en Back Office
Expirer le cache de vue “volontairement” en Back Office, que ce soit via un nœud, un sous arbre ou l'ensemble du cache de vue (onglet /setup/cache/) est une mauvaise pratique a réserver exclusivement aux versions de développement du site.
Ce tutoriel ne souhaite pas faire la promotion de cette pratique (malheureusement trop répandu) et n'en dira donc pas plus à ce sujet à part : un webmaster ou éditeur de contenu ne doit en aucun cas avoir accès aux fonctionnalités de gestion du cache, qui peut dans tous les cas :
- être automatisé et sécurisé sans avoir recours à des actions manuelles
- provoquer d'énormes instabilités du système / crash serveurs sur un site à fort trafic
“Attention : Actuellement une expiration du cache de vue à partir d’un noeud (back office ou script ezcontentcache.php), implique l’expiration récursive de tous les sous noeuds de l’emplacement sélectionné. Cette expiration reproduit l’ensemble du processus (smartviewcache, CacheThreshold, expiration des template-block liés à un subtree expiry relatif, etc.) pour chacun des noeud concernés. Ainsi, et pour simple exemple parmi d’autres, une règle de smartviewcache sur les frères (siblings) pourrait entraîner une expiration du cache de vue “au carré” (chaque noeud expire autant de fois que le nombre de noeuds frères), et rendre instable le système.
”
Expiration complète et involontaire du cache de vue suite à une action en Back Office
Un certain nombre d’opérations font expirer l’ensemble du cache de vue en back office, malgré l’utilisateur ou l’administrateur, qui n’a pas forcement connaissance de la corrélation entre une action back office et l’expiration du cache de vue. Voici une liste, qu’on espère exhaustive des actions en back office qui font expirer l’ensemble du cache de vue :
- Rôles : édition / suppression d’un rôle, édition / suppression de l’assignation d’un rôle
- Sections : assignation d’une section
- La manipulation du ezshop : manipulation des règles de discount, groupes de discount, affectation d’utilisateurs aux groupes, édition / suppression des monnaies, etc.
- Classes de contenu : la création d’une nouvelle classe (même sans objets associés), l’édition et la suppression d’une classe
- Langues : ajout / suppression d’une langue
En dehors de la fonctionnalité de création d’une classe (sans object par défaut), les autres actions back office expirent logiquement l’ensemble du cache de vue. Comme nous le verrons dans un prochain chapitre, ces informations sont exploitées “par défaut” dans la clé de hash du cache de vue (sans prise en compte toutefois d’une éventuelle désactivation de certaines clés par exploitation du paramètre ViewCacheTweaks).
CacheThreshold, une expiration partielle du cache de vue qui devient complète
Lorsqu'un cache de vue expire pour X raisons (mise à jour d'un article, script ezcontentcache.php...), il implique généralement une liste de nœud ayant un cache à expirer : le nœud de l'article lui même, et par exemple les nœuds des articles en relations, les frères, les parents, ou les nœuds exploitant les même mots clés, etc. (selon les directives du viewcache.ini).
Au final, eZ Publish est capable de calculer le nombre de nœuds impliqués dans le vidage de cache déclenchés. Pour stabiliser le système et éviter par exemple d'ordonner l'altération de trop de fichiers de caches sur le serveur (unlink, touch, update SQL... selon le filehandler exploité), eZ Publish utilise pour cela une limite, le CacheThreshold :
- Si le nombre de noeuds impactés est inférieur au CacheThreshold : eZ Publish « invalide » les fichiers de cache selon le filehandler exploité (suppression par défaut). Voir le chapitre qui détaille les différents mode d'altérations (unlink, touch, update SQL...)
- Si le nombre de noeuds impactés est supérieur au CacheThreshold : eZ Publish bascule alors en mode d'expiration complète du cache de vue par changement de la valeur 'content-view-cache' (timestamp à jour), du fichier{VarDir}/cache/expiry.php
Comment sont stockés les fichiers de cache de vues ?
eZ Publish utilise une arborescence de répertoires sous {VarDir}/cache/content/{siteaccess}/, qui permet de répartir le gros volume potentiel de fichier générés, de la façon suivante :
- A la racine de {VarDir}/cache/content/{siteaccess}/ : les fichiers qui sont compris en "2-" et "99-"
- dans les répertoires {VarDir}/cache/content/{siteaccess}/{chiffre}/{chiffre}/{chiffre} : les fichiers qui commencent par les "chiffre" cumulés + 2 chiffres, par exemple : "2/1/5" -> "215xx-"
{VarDir} = valeur du paramètre VarDir dans le site.ini (ou votre surchage spécifique), généralement "var/monsite/"
Voici une simulation simplifié d'une arborescence de cache de vue :
{VarDir}/cache/content/{siteaccess}/
2-ce182234bd70236c6a009578d2a34632.cache
20-ce182234bd70236c6a009578d2a34632.cache
{VarDir}/cache/content/{siteaccess}/1
101-ce182234bd70236c6a009578d2a34632.cache
105-ce182234bd70236c6a009578d2a34632.cache
{VarDir}/cache/content/{siteaccess}/2
204-ce182234bd70236c6a009578d2a34632.cache
210-ce182234bd70236c6a009578d2a34632.cache
{VarDir}/cache/content/{siteaccess}/5/2/1
52101-ce182234bd70236c6a009578d2a34632.cache
52144-ce182234bd70236c6a009578d2a34632.cache
Les noms des fichiers est construit de la façon suivante :
{nodeid}-{hash}.php
2-ce182234bd70236c6a009578d2a34632.cache
Le hash est calculé à partir de nombreuses valeurs séparées en 2 catégories :
- Les valeurs de clé présentes par défaut et non désactivables
- Les valeurs de clé présentes par défaut et désactivables par des directives du site.ini : les ViewCacheTweaks. Ces paramètres permettent de partager un même cache lorsque le contenu n'est pas influencé par le paramètre en question. Il est en effet plutôt inutile de générer et stocker des caches différents par « view_parameters » ou « user_preferences » lorsque le résultat produit n'est pas influencé par ces valeurs.
Tableau des éléments de la clé de hash non désactivables
| Elément de la clé de hash | Signification | Exemple de valeur |
|---|---|---|
| nodeID | Noeud courant | 2 |
| viewMode | Vue courante, dont la liste est extensible dans : [ContentSettings] / CachedViewModes=full;sitemap;pdf | full | sitemap | pdf |
| layout | Nom du pagelayout personnalité, si la vue est invoquée lors de l'appel d'un URL de type « layout/set/print » par exemple (module layout) | |
| language | Sur définition de /(language)/value | Null par défaut, sinon « value » |
| offset | Sur définition de /(offset)/value | Null par défaut, sinon « value » |
| indexFile | La racine de l'index du site, qui peut varié selon divers paramètres, comme par exemple : le nom du siteaccess en mode « URI », ou encore la racine «layout/set/... » | site_admin | layout/set/print |
Tableau des éléments de la clé de hash désactivables (Tweaks) par noeud ou en global
ViewCacheTweaks[<node_id>]=<setting>[;<setting2>] ViewCacheTweaks[global]=<setting>[;<setting2>]
| Elément de la clé de hash | Signification | Exemple de valeur |
|---|---|---|
| roleIDList |
Liste des rôles affectés à l'utilisateur courant |
5.10 |
| limitValueList | Liste des limitations affectés à l'utilisateur courant (subtree)
ViewCacheTweaks : |
/1/2/./1/43/ |
| discountList | Liste des règles de « discount » liées à l'utilisateur courant (eZShop)
ViewCacheTweaks : | Non testé, même logique de tableau que ci-dessus |
| cacheNameExtra |
Détermine que le « access type » du siteaccess est défini par URI, afin d'éventuellement stocker séparément les caches selon les « access type » | NULL | 2 |
| pr_user |
Détermine s'il faut ou non stocker un cache par utilisateur (désactivé par défaut) |
15- |
| viewParameters |
Liste les viewparameters : /(clé)/valeur/(clé2)/valeur/... |
vp:day=vp:month=vp:namefilter=vp:offset=vp:year= |
| userPreferences | Liste les préférences utilisateur courante, en ajoutant celles définies dans [ContentSettings] / CachedViewPreferences | p:admin_navigation_content=1; p:admin_children_viewmode=list; p:admin_list_limit=1 ; Liste de «p: » + clé + « = » + valeur + « ; » |
Au final le nom du fichier est constuit selon la trame :
{VarDir}/cache/content/{siteaccess}/{$numbers}/$nodeID . '-' . $cacheNameExtra . md5( implode( '-', $cacheHashArray ) ) . '.cache';
- $nodeID est le noeud courant
- $cacheNameExtra est vide en mode HOST, égal à 2 en mode URI (ou vide si le ViewCacheTweaksignore_siteaccess_type est activé)
- $cacheHashArray est le tableau de toutes les valeurs décrites ci-dessus
La clé de hash est donc constituée de plusieurs paramètres combinables, qui font impérativement connaître afin de bien comprendre et maîtriser l'impact d'une suppression complète du cache de vue.
En effet, un possédant de nombreux siteaccess et surtout de nombreuses combinaisons de 'viewparameters' pourrait générer un grand nombre de combinaisons possibles de cache de vue, autant de caches à reconstruire lors d'une expiration massive !
Si on suit cette logique de construction, cela implique que la construction d'une URL erronée, mais "valide" dans la typologie d'URL eZ Publish génère également systématique un cache de vue : http://website.com/(param)/hello1, http://website.com/(param)/hello2, http://website.com/(param)/nimportequoi , etc... On peut ainsi remplir progressivement le disque de cache inutiles, et rendre critique une expiration de cache sur le nœud concerné par une invalidation trop massive de fichiers de caches
Comment faire la correspondance entre un cache de vue et la page / URL d'origine ?
Pour les plus courageux qui souhaitent explorer les fichiers de caches générés et en déduire une exploitation / information utile, voici quelques pistes permettant d'effectuer un peu d'optimisation.
Comme nous l'avons détaillés précédemment, un même nœud peut avoir une grande combinaison de caches de vues (voir la clé de hash du nom du fichier dans le chapitre concerné). Dans un souci d'optimisation, il peut être utile d'investiguer la cause d'une génération massive de cache de vue (homepage par exemple) : des centaines de caches de vue sur le noeud "2-{hash}.cache".
Dans ce cas, lorsqu'on explore un fichier généré, on retrouve en pied de fichier la combinaison de paramètres qui a provoqué sa génération, puisqu'à l'origine d'une clé différente de hash, par exemple :
"view_parameters";a:6:{s:6:"offset";b:0;s:4:"year";b:0;s:5:"month";b:0;s:3:"day";b:0;s:10:"namefilter";b:0;s:4:"test";s:1:"2";}
On peut en déduire que ce cache a été provoqué par la présence du viewparameter "/(test)/2"
Comment logger l’activité du cache de vue ?
La meilleure façon de maitriser son optimisation du cache de vue reste encore de pouvoir logguer son activité de la façon suivante :
- Quelle URL a déclenché une expiration ?
- Quel est le noeud concerné ?
- Combien d’autres noeuds sont concernés par cette expiration ?
- Quel est la liste de ces autres noeuds ?
Depuis eZ Publish 4.5, il existe une façon assez simple de procéder, en utilisant le mécanisme de programmation événementiel : ezpEvent. Un certain nombre d’évènements sont ainsi positionnés dans le Kernel eZ Publish ( en fonction des évolutions fonctionnelles ou des besoins du eZ Market ). Ainsi l’évènement “content/cache” est disponible par défaut sur eZ Publish.
Pour logger l’activité du cache de vue, il suffit donc :
- 1. De faire un mapping entre l’évènement “content/cache”, et une méthode statique d’une nouvelle classe ( par exemple la méthode logviewcache de la classe test )
Dans votre settings/override/site.ini.append.php :
[Event] Listeners[]=content/cache@test::logviewcache
- 2. De créer la classe PHP en question ( répertoire classes/ d’une extension ), en écrivant le code souhaité, par exemple :
<?php class test { static public function logviewcache( $nodeList ) { $uri = $GLOBALS['_SERVER']['REQUEST_URI']; eZLog::write('node_id count : '. count( $nodeList ). ' / node_id list : ' . implode(', ', $nodeList ) . ' / URI : '.$uri, 'chachethresold.log'); return $nodeList; }} ?>
- 3. Regénérer les autoloads :
php bin/php/ezpgenerateautoloads.php
Le cache de vue « in a nutshell » : 5 minutes et 2 schémas
- Tags :
- eZ Publish
- Cache
Que boire avec ce billet ?
Domaine Léon Barral - Jadis - Rouge 2007
| Région : | Languedoc |
| Appellation : | Faugères |
| Domaine : | Domaine Léon Barral |
| Couleur : | |
| Stock : | 0 |
| Notation : | |
| Prix : | 16 € |
| Commentaire(s) : | 0 Commentaire(s) |
Plus concentré, plus complexe, plus profond que la première cuvée, ce vin de pur plaisir représente l'identité des vins du Languedoc et de Faugères en particulier, trop souvent assimilés aux rosés des terrasses ensoleillées. Il suffit de parcourir la cave de Lavinia pour comprendre que ce domaine compte parmi les grands.
